版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/isee361820238/article/details/53954078
在Android開發中,有時候難免會遇到需要繪製圖形圖像的功能需求,針對這類需求,我們可以採用分解功能點,先易後難,逐個擊破的策略。這裏以可滑動的刻度尺功能爲例,進行自定義View的探討和學習。
首先,繪製一個刻度尺有最基本的幾個要素:最大刻度、最小刻度、底部橫線、每一個刻度的大小等,當然我們還需要繪製文字,刻度尺起始位置,刻度尺也需要有顏色等。這些自定義屬性我們可以直接寫在attrs.xml文件中。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RulerView">
<!--最大刻度-->
<attr name="max_value" format="dimension" />
<!--最小刻度-->
<attr name="min_value" format="dimension" />
<!--刻度字體大小-->
<attr name="scale_text_size" format="dimension" />
<!--刻度字體顏色-->
<attr name="scale_text_color" format="color" />
<!--底部橫線的顏色-->
<attr name="scale_bottom_line_color" format="color" />
<!--遊標顏色-->
<attr name="cursor_color" format="color" />
<!--標尺開始顯示位置-->
<attr name="start_location" format="dimension" />
<!--一屏顯示Item-->
<attr name="one_screen_item_count" format="integer" />
<!--一個刻度的大小-->
<attr name="one_scale_value" format="integer" />
</declare-styleable>
</resources>
接下來,我們就在自定義控件中進行引用,並初始化一些需要用到的數據:
public class RulerView extends View {
private static final String TAG = "RulerView";
public static final int DEFAULT_BOTTOM_LINE_COLOR = 0xFFB3B2B2;
public static final int DEFAULT_CURSOR_COLOR = 0XF3FF4081;
public static final int DEFAULT_SCALE_TEXT_COLOR = 0xFF000000;
public static final int DEFAULT_TEXT_SIZE = 24;
public static final int DEFAULT_MAX_SCALE_VALUE = 20000;
public static final int DEFAULT_ONE_SCREEN_ITEM_COUNT = 5 * 10;
public static final int DEFAULT_ONE_SCALE_VALUE = 100;
private int bottomLineColor;
private int cursorColor;
private int scaleTextColor;
private int scaleTextSize;
private int maxScaleValue; // 最大的刻度值
private int oneScreenItemCount; // 一屏顯示的刻度數量
private int oneScaleValue; // 一個刻度的大小
private float oneScaleWidth; // 一個刻度的寬度
private float scaleHeight; // 一個刻度的高度
private int scaleCount; // 刻度數量
private int currLocation;
private float viewWidth;
private float viewHeight;
private float screenWidth;
private Paint bottomLinePaint;
private Paint scalePaint;
private Paint textPaint;
private Paint cursorPaint;
public RulerView(Context context) {
super(context);
}
public RulerView(Context context, AttributeSet attrs) {
super(context, attrs);
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(dm);
screenWidth = dm.widthPixels;
Log.d(TAG, "ScreenWidth = " + screenWidth); //1440
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RulerView);
bottomLineColor = typedArray.getColor(R.styleable.RulerView_scale_bottom_line_color, DEFAULT_BOTTOM_LINE_COLOR);
cursorColor = typedArray.getColor(R.styleable.RulerView_cursor_color, DEFAULT_CURSOR_COLOR);
scaleTextColor = typedArray.getColor(R.styleable.RulerView_scale_text_color, DEFAULT_SCALE_TEXT_COLOR);
scaleTextSize = typedArray.getDimensionPixelSize(R.styleable.RulerView_scale_text_size, DEFAULT_TEXT_SIZE);
maxScaleValue = typedArray.getDimensionPixelOffset(R.styleable.RulerView_max_value, DEFAULT_MAX_SCALE_VALUE);
oneScreenItemCount = typedArray.getInteger(R.styleable.RulerView_one_screen_item_count, DEFAULT_ONE_SCREEN_ITEM_COUNT);
oneScaleValue = typedArray.getInteger(R.styleable.RulerView_one_scale_value, DEFAULT_ONE_SCALE_VALUE);
currLocation = typedArray.getDimensionPixelOffset(R.styleable.RulerView_start_location, 0);
typedArray.recycle();
oneScaleWidth = screenWidth / oneScreenItemCount; // 1440 / (5 * 10)
scaleCount = maxScaleValue / oneScaleValue; //刻度總數量 200
viewWidth = scaleCount * oneScaleWidth; //刻度尺總寬度
Log.d(TAG, "RulerView--oneScaleWidth = " + oneScaleWidth); //28
Log.d(TAG, "RulerView--viewWidth = " + viewWidth); //5600
// init paint
initPaint();
}
}
畫筆的初始化:
private void initPaint() {
bottomLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bottomLinePaint.setStrokeWidth(3);
bottomLinePaint.setColor(bottomLineColor);
scalePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
scalePaint.setStrokeWidth(3);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(scaleTextSize);
textPaint.setColor(scaleTextColor);
cursorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
cursorPaint.setStrokeWidth(4);
cursorPaint.setColor(cursorColor);
}
在真正繪製前,我們還需要知道該控件的高度以及刻度尺的高度,這裏我們在onMeasure()方法中進行獲取:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewHeight = MeasureSpec.getSize(heightMeasureSpec);
scaleHeight = viewHeight / 4;
Log.d(TAG, "onMeasure--viewHeight = " + viewHeight); //320
}
最後,我們在onDraw()方法中進行我們的繪製:
@Override
protected void onDraw(Canvas canvas) {
drawBottomLine(canvas);
drawScale(canvas);
drawCursor(canvas);
}
繪製底部的橫線
private void drawBottomLine(Canvas canvas) {
canvas.drawLine(0, viewHeight, viewWidth, viewHeight, bottomLinePaint);
}
繪製刻度以及刻度值
private void drawScale(Canvas canvas) {
//計算遊標開始繪製的位置
float startLocation = (screenWidth / 2) - ((oneScaleWidth * (currLocation / oneScaleValue)));
for (int i = 0; i <= scaleCount; i++) {
float location = startLocation + i * oneScaleWidth;
if (i % 10 == 0) {
canvas.drawLine(location, viewHeight - scaleHeight, location, viewHeight, scalePaint);
String drawStr = oneScaleValue * i + "";
Rect bounds = new Rect();
textPaint.getTextBounds(drawStr, 0, drawStr.length(), bounds);
//drawText的第三個參數表示:文本繪製的Y方向的基線位置
canvas.drawText(drawStr, location - bounds.width() / 2, viewHeight - (scaleHeight + 10), textPaint);
} else {
canvas.drawLine(location, viewHeight - scaleHeight / 2, location, viewHeight, scalePaint);
}
}
}
繪製遊標
private void drawCursor(Canvas canvas) {
canvas.drawLine(screenWidth / 2, viewHeight / 6, screenWidth / 2, viewHeight, cursorPaint);
}
至此,遊標功能初具模樣了,在接下來的一篇文章中將實現滑動效果。