江阴做网站/关键词的作用
简单的自定义进度条绘制,想自定义View最少知道什么?
- View的三个绘制流程方法
- 举例,自定义进度条
- 看一下自定义的进度条,都做了哪些操作
- 总结,所以自定义View的基本流程是?
View的三个绘制流程方法
view的绘制基本上由三个方法组成,分别是measure、layout、draw
measure 测量当前view
layout 计算当前view和子View的轮廓尺寸
draw 绘制当前view
如果只是绘制View,不是ViewGroup,onLayout()是不会触发的。
接下来举个例子,绘制个简单的View进度条,因为是绘制View,而不是ViewGroup,所以这里的onLayout()并没有用到。
举例,自定义进度条
自定义进度条
1.写个BaseView
public class BaseView extends View {private boolean isLog = true;protected String TAG = this.getClass().getSimpleName();protected int height, width;protected int start, end, top, bottom;protected int magin;public BaseView(Context context) {this(context, null);}public BaseView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public BaseView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initBase(context);}protected void initBase(Context context) {LogUtils.i(TAG, "initBase");}protected Paint getInitPaint() {LogUtils.i(TAG, "getInitPaint");Paint paint;paint = new Paint();paint.setAntiAlias(true);paint.setStrokeCap(Paint.Cap.SQUARE);paint.setAntiAlias(true);paint.setDither(true);return paint;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);height = getMeasuredHeight() - 2 * magin;start = getPaddingLeft() + magin;end = getMeasuredWidth() - getPaddingRight() - magin;width = end - start;top = getPaddingTop() + magin;bottom = getMeasuredHeight() - getPaddingBottom() - magin;}public void setLog(boolean log) {isLog = log;}protected void log(String msg){if (isLog) {LogUtils.i( TAG,msg);}}}
2.写需要的进度条
public class CustomSeekbar extends BaseView {private Paint paintBg, paintProgress, paintSlider;private RectF rectFBg, rectFProgress, rectFSlider;private int startBg, topBg, startProgress, topProgress, startSlider, topSlider;private int wBg, wProgress;private int duration, progress;private int newProgress;private int radiusSlider;private final int RADIUS_2 = 2;private Bitmap bitmap;public CustomSeekbar(Context context) {this(context, null);}public CustomSeekbar(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CustomSeekbar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void initBase(Context context) {super.initBase(context);magin = 0;duration = 100;progress = 0;bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.seekbar_progress_2);paintBg = getInitPaint();paintProgress = getInitPaint();paintSlider = getInitPaint();paintBg.setColor(0xC2A688);paintBg.setAlpha((int) (0.2 * 255));radiusSlider = 52 / 2;paintProgress.setColor(0xffC2A688);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);startBg = start + radiusSlider;topBg = top + radiusSlider - 1;wBg = width - 2 * radiusSlider;rectFBg = new RectF(startBg, topBg, startBg + wBg, topBg + 2);startProgress = start + radiusSlider;topProgress = top + radiusSlider - 1;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawRoundRect(rectFBg, RADIUS_2, RADIUS_2, paintBg);wProgress = wBg * progress / duration;rectFProgress = new RectF(startProgress, topProgress, startProgress + wProgress, topProgress + 2);canvas.drawRoundRect(rectFProgress, RADIUS_2, RADIUS_2, paintProgress);startSlider = startProgress + wProgress - radiusSlider;topSlider = top;rectFSlider = new RectF(startSlider, topSlider, startSlider + 2 * radiusSlider, topSlider + 2 * radiusSlider);canvas.drawBitmap(bitmap, null, rectFSlider, paintSlider);}@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.i(TAG, "onTouchEvent: ");switch (event.getActionMasked()) {case MotionEvent.ACTION_DOWN:newProgress = calProgress(event.getX());if (progress != newProgress) {progress = newProgress;
// invalidate();}Log.i(TAG, "onTouchEvent ACTION_DOWN: " + progress);break;case MotionEvent.ACTION_MOVE:newProgress = calProgress(event.getX());if (progress != newProgress) {progress = newProgress;invalidate();}Log.i(TAG, "onTouchEvent ACTION_MOVE: " + progress);break;case MotionEvent.ACTION_UP:newProgress = calProgress(event.getX());if (progress != newProgress) {progress = newProgress;invalidate();}if (onProgressCallback != null) {onProgressCallback.onCallBack(progress);}Log.i(TAG, "onTouchEvent ACTION_UP: " + progress);case MotionEvent.ACTION_CANCEL:getRootView().performClick();invalidate();break;default:Log.i(TAG, "onTouchEvent default: " + progress);break;}return true;}private int calProgress(float x) {log("calProgress x ==" + x);log("calProgress wBg ==" + wBg);log("calProgress duration ==" + duration);int pro = (int) Math.ceil(duration * (x - radiusSlider) / wBg);if (pro < 0) pro = 0;else if (pro > duration) pro = duration;log("calProgress pro ==" + pro);return pro;}private OnProgressCallback onProgressCallback;public void setOnProgressCallback(OnProgressCallback onProgressCallback) {this.onProgressCallback = onProgressCallback;}public void setProgress(int i) {log("setProgress i ==" + i);if (progress != i)invalidate();this.progress = i;}public void setMax(int i) {log("setMax i ==" + i);if (duration != i)invalidate();duration = i;}public interface OnProgressCallback {void onCallBack(int progress);}}
看一下自定义的进度条,都做了哪些操作
- 创建类,继承View
因为是绘制View,不是ViewGroup
- 写三个构造方法
如果没有自定义属性,可以写前两个
- 初始化数据和paint
初始化的方法是由构造方法调用的,初始化的是一些和尺寸无关的东西,或者已经确定下来的尺寸
- 测量(onMeasure)
分两部分,一部分是base内的尺寸
protected int height, width;protected int start, end, top, bottom;
这些尺寸里 左上的起点和控件的长高是必须知道的,每个自定义View都需要
第二部分,是我们需要绘制的图形
自定义View的进度条有三个图形,一个是底色,一个进度色,一个是滑块
其中,底色固定,进度色和滑块需要通过进度计算
固定的东西就需要在这里算完,和进度相关的需要在onDraw内计算
- 绘制(onDraw)
画就行了,需要连接 canvas
- 点击事件(onTouchEvent)
点击事件需要重写public boolean onTouchEvent(MotionEvent event)方法,通过获取点到控件边的距离,计算所处的进度即可。
总结,所以自定义View的基本流程是?
1.创建继承View的类
2.构造方法
3.初始化
4.测量
5.绘制
6.点击(有的也没有)