Android开发艺术探索笔记(15)- 自定义View
来源:互联网 发布:清华大学材料学院知乎 编辑:程序博客网 时间:2024/05/16 05:42
View的原理学习的差不过了,是时候可以自定义View。记得,3个步骤,测量(onMeasure)- 布局(onLayout)- 绘画(onDraw)。
onMeasure
测量上一节已经学过onMeasure方法的主要参数MeasureSpec,我们主要根据MeasureSpec得到的mode和size,测量View的宽高。
// 定义mWidth和mHeightint mWidth = 200;int mHeight = 100;// 重写onMeasure方法@Overridepublic void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); /** * 因为View的LayoutParams是wrap_content,就是AT_MOST模式,如果父容器是match_parent,那么View的模式也会跟着父容器,为match_content,所以wrap_content会不起作用,所以我们自己设置大小。mWidth和mHeight可以根据实际情况而定。 **/ if (widthMode == MeasureSpec.AT_MOST && heightMeasureSpec == MeasureSpec.AT_MOST) { setMeasuredDimension(mWidth, mHeight); } else if(widthMode == MeasureSpec.AT_MOST) { setMeasuredDimension(mWidth, heightSize); } else if(heightMeasureSpec == MeasureSpec.AT_MOST) { setMeasuredDimension(widthSize, mHeight); }}
如果我们需要重新调用View的onMeasure方法,可以调用requestLayout方法即可。
要想在onCreate或者onResume直接调用getWidth/getHeight获取View的大小,貌似是不行的。作者体用了几种常用的方法:
(1)利用onWindowFocusChanged()方法获取
public void onWindowFocusChanged(boolean hadFocus) { if (hadFocus) { // 此时View已经初始化完毕了 int width = view.getMeasuredWidth(); int height = view.getMeasureHeight(); }}
(2)利用view.post(runnable)方法获取
// 将消息加到消息队列最后,此时view也已经初始化完毕,也就是在onCreate和onResume之后才获取view的大小view.post(new Runnable() { int width = view.getMeasuredWidth(); int height = view.getMeasureHeight();});
我认为这种方式是最简单的。
(3)ViewTreeObserver
ViewTreeObserver observer = view.getViewTreeObserver();observer.addOnGlobalLayoutLisetner(new OnGlobalLayoutLisetner(){ public void onGlobalLayout() { // 一定要移除监听,否则会执行很多遍 view.getViewTreeObserver().removeGlobalLayoutLisetner(this); int width = view.getMeasuredWidth(); int height = view.getMeasureHeight(); }});
这种方式是作者推荐使用的一种方法。
(4)view.measure(int widthMeasureSpec, int heightMeasureSpec)
之前百度过有这个方法,这里作者指出这个方法可以用,但是要谨慎,分分钟获取不到值,so就不记录了。
onLayout
onLayout方法用于布局,一般自定义Viewgroup时才需要重写该方法,确定子View的位置,子View只有layout方法(确定自己位置)。onLayout会遍历子View,调用其layout方法确定各个子View的方法。
// 这里用伪代码只做演示,请自行修改@Overridepublic void onLayout(boolean isChanged, int l, int t, int r, int b) { int childCount = getChildCount(); for(int i = 0; i < childCount; i++) { View childView = getChildAt(i); if (childView.getVisibility() == GONE) { continue(); } // 计算ChildView左上角的x坐标 int left = caculateChildLeft(); // 计算ChildView左上角的y坐标 int top = caculateChildTop(); // 确定ChildView的位置 childView.layout(left, top, left + viewWidth, top + viewHeight); }}
我在慕课网的Android自定义View学到,应该把比较耗时的操作尽量延迟到onLayout这个方法中,因为onMeasure方法会执行多次,而onLayout方法只会执行一次,比较轻量级。如果想重新调用onLayout方法,也是调用View的requestLayout方法(调用requestLayout方法时,会调用View的onLayout方法和onMeasure方法进行重新测量和布局)。
onDraw
onDraw用于绘画,一般用在自定义View(在自定义ViewGroup时一般不进行绘画)。学会怎么使用Canvas.drawXXX方法进行绘制就行。可以配合translate、rotate等进行一些动画,不过要记得使用save和restore来进行动画状态的操作,还有重要的一点,就是如果Activity销毁时,也就是自定义View被移除时,记得要停止动画,如果不这样的话,会造成内存泄露(特别注意)。在View被移除时或者Activity销毁时,会调用View的onDetachedFromWindow方法,我们重写这个方法,停止动画或者销毁一些线程,回收资源就可以避免内存泄露问题啦。
还有一点,就是我们没有必要在自定义View使用handler。View已经提供了子线程更新View的机制,就是使用postInvalidate方法。如果需要在ui线程更新View,可以使用invalidate方法。
自定义View时的注意事项
(1)让View支持wrap_content
这个问题在上面的onMeasure中已经说的很清楚了。
(2)如果有必要,让你们View支持padding
如果是自定义View,如果需要padding,那么在onDraw方法中处理padding。可以在onDraw方法中利用getPaddingLeft等方法获取到padding的值,然后canvas.drawXXX方法时,计算位置加上一个padding即可。如果是自定义ViewGroup,如果需要padding,在重写onLayout和onMeasure方法计算padding值。
(3)尽量在View中不要使用Handler,没必要
上面onDraw中已经说明白了。
(4)View如果有线程或者动画,需要及时停止和释放资源
在上面onDraw也已经说明白了。
(5)View如果带有滑动嵌套情形时,需要处理好滑动冲突。
具体处理方法参考我之前写的View的滑动冲突处理一节。
- Android开发艺术探索笔记(15)- 自定义View
- 《Android开发艺术探索》 自定义View
- android 艺术开发探索 view移动 笔记
- Android开发艺术探索笔记(8)- View的基础
- Android开发艺术探索笔记(9)- View的滑动
- 《Android开发艺术探索》笔记(View的知识体系)
- 一个规范的自定义View——Android开发艺术探索笔记
- 《Android开发艺术探索第四章读书笔记-自定义VIew》
- View的滑动冲突解决-android开发艺术探索笔记
- Android 开发艺术探索笔记-View的事件分发
- 读书笔记--自定义View --开发艺术探索
- 《Android开发艺术探索》笔记(1)
- 《Android开发艺术探索》笔记
- 《Android开发艺术探索》笔记
- Android开发艺术探索学习笔记(3)--View的事件体系(1)
- 《Android 开发艺术探索》笔记——(3)View 的事件体系
- 《Android开发艺术探索》之学习笔记(四)View的工作原理
- 《Android开发艺术探索》之学习笔记(三)View的基础知识
- Mysql5.7.16安装教程
- 服务器 进程实现
- POJ 2393 Yogurt factory 笔记
- 弗洛伊德法求最短路径
- <C++>_函数重载
- Android开发艺术探索笔记(15)- 自定义View
- 表单提交数据乱码(datatables提交中文查询处理)
- 面向对象(猜字游戏)
- android中常用的距离单位
- input输入框下拉提示、js的keyup的实现、
- 公司发版shell脚本重构
- 如何重新修改sourceinght的注册序列号
- VS2008的常见问题
- MimeMessageHelper使用流发送带附件的邮件报错