Android自定义View
2020-03-05 本文已影响0人
Itachi001
自定view分两种:
- 自定义ViewGroup,主要覆写onMeasure,onLayout,onTouch
- 自定义View,主要覆写onMeasure,onDraw,onTouch
onMeasure(int widthMeasureSpec, int heightMeasureSpec):
onMeasure方法接收的两个int型参数是你在xml中给该View设置的宽高,但是注意这两个参数的值是与你设置的值不同
在这里需要首先了解一下MeasureSpec
它是View中的内部类,里面都是二进制运算。
由于int是32位的,用高两位表示mode,低30位表示size,而mode有三种:
UNSPECIFIED:不对View大小做限制
EXACTLY:确切的大小,如100dp或者match_parent
AT_MOST:大小不超过某数值,如wrap_content
可以通过MeasureSpec的getMode和getSize方法获取mode和size
int selfWidth = MeasureSpec.getSize(widthMeasureSpec);//View解析的宽度
int selfHeight = MeasureSpec.getSize(heightMeasureSpec);//View解析的高度
在这里,假如你是想自定义ViewGroup,你需要对子view进行测量,还得了解一个方法:
getChildMeasureSpec(int spec, int padding, int childDimension)
子view的MeasureSpec是由ViewGroup的MeasureSpec和子view的LayoutParams 共同决定的
LayoutParams layoutParams = childAt.getLayoutParams();
int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight, layoutParams.width);
int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom, layoutParams.height);
childAt.measure(childWidthMeasureSpec, childHeightMeasureSpec);
子view测量完毕,便可获取子view测量后的宽高
//获取子View宽高
int childAtMeasuredWidth = childAt.getMeasuredWidth();
int childAtMeasuredHeight = childAt.getMeasuredHeight();
最后根据子view的总宽高以及ViewGroup的mode确定ViewGroup的宽高,并调用以下方法保存:
setMeasuredDimension(int measuredWidth, int measuredHeight)
onLayout(boolean changed, int left, int top, int right, int bottom):
changed:ViewGroup的大小或位置是否改变,left、top、right、bottom:ViewGroup的四个角的坐标
在该方法中通过子view的layout()方法对子view进行布局
itemView.layout(itemViewLeft, itemViewTop, itemViewRight, itemViewBottom);
onDraw(Canvas canvas)
canvas参数为画布,可以理解为一张纸,你需要在View初始化时创建画笔Paint,对Paint设置不同的属性以达到画出不同的图形的目的,关于Android Paint,调用canvas的如下方法进行绘制
RectF(float left, float top, float right, float bottom)
drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)
drawText(@NonNull String text, int start, int end, float x, float y,@NonNull Paint paint)
drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint)
onTouchEvent(MotionEvent event)
稍后再说
思考:视图还未绘制完成,怎么获取view的信息?
- 在View的事件回调里获取
- onWindowFocusChanged回调方法中获取
- 在onResume方法最后开线程300毫秒左右后获取(不推荐)
- 通过getViewTreeObserver().addOnGlobalLayoutListener()方法为View添加回调来获取,用完记得删除回调
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// doing
}
});
- 手动对view进行measure来得到view的宽高
view.measure(int widthMeasureSpec,int heightMeasureSpec)