返回
顶部

修改密码

Android自定义View-------为什么重写onMeasure()以及怎么重写

+1

-1

收藏

+1

-1

点赞0

评论0

这两天在看关于Android自定义组件的知识,刚开始查阅了很多资料,依然觉得对onMeasure()方法的理解不够透彻,后来大致知道onMeasure怎么用了之后,又很好奇为什么需要去实现onMeasure()这个方法。这篇文章主要记录两个问题,1)自定义组件时什么情况下需要实现onMeasure()方法…


这两天在看关于Android自定义组件的知识,刚开始查阅了很多资料,依然觉得对onMeasure()方法的理解不够透彻,后来大致知道onMeasure怎么用了之后,又很好奇为什么需要去实现onMeasure()这个方法。

这篇文章主要记录两个问题,1)自定义组件时什么情况下需要实现onMeasure()方法,2)怎么实现onMeasure()方法

为什么需要实现onMeasure()方法

我们看以下例子,我们自己定义一个View,很简单,只是继承View类。

         

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class MyView extends View {  
  2.   
  3.     public MyView(Context context, AttributeSet attrs, int defStyleAttr) {  
  4.         super(context, attrs, defStyleAttr);  
  5.         // TODO Auto-generated constructor stub  
  6.     }  
  7.   
  8.     public MyView(Context context, AttributeSet attrs) {  
  9.         super(context, attrs);  
  10.         // TODO Auto-generated constructor stub  
  11.     }  
  12.   
  13.     public MyView(Context context) {  
  14.         super(context);  
  15.         // TODO Auto-generated constructor stub  
  16.     }  
  17.       
  18.     @Override  
  19.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  20.         // TODO Auto-generated method stub  
  21.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  22.     }  
  23. }  

然后在布局文件中定义如下布局:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     xmlns:MyView="http://schemas.android.com/apk/res/com.notes.notes_onmeasure"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:orientation="vertical"  
  7.     android:padding="@dimen/activity_vertical_margin"  
  8.     tools:context="com.notes.notes_onmeasure.EasyActivity" >  
  9.   
  10.       
  11.       
  12.     <com.notes.notes_onmeasure.MyView  
  13.         android:layout_width="wrap_content"  
  14.         android:layout_height="wrap_content"  
  15.         android:background="#78787878" />  
  16.   
  17.     <TextView  
  18.         android:layout_width="wrap_content"  
  19.         android:layout_height="wrap_content"  
  20.         android:text="能看到我吗?" />  
  21.   
  22. </LinearLayout>  


结果显示如

当MyView的宽和高设置为match_parent时,MyView会填充整个界面是毋庸置疑的,当将其宽和高设置为某个确定值时,MyView的大小也会按这个确定的值显示。但是上面的例子中,我们把MyView的宽和高设置为wrap_content,它依然填充整个界面。问题就出在这里,所以我们需要重写onMeasure()方法控制其大小。其它继承于View的组件,如Button,TextView,它们都已经通过重写onMeasuer()方法。


    怎么重写onMeasure()方法

    

android中,每个View的大小,不仅取决于自身,而且也受父视图的影响,可以参考我的另一篇文章 Android界面绘制流程----How Android Draws Views。而onMeasure()是在父视图计算子视图大小时被调用的,其中的细节就不在此详细讲述了,我们暂时只需要这一点即可。

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  2.    //,,,  
  3. }  

onMeasure()方法有两个参数,这两个参数就是父视图发过来给子视图的限制条件。我们直接来重写上面的MyView中的onMeasure()方法,通过一个例子了解onMeasure()方法怎么实现。


[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. @Override  
  2.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  3.         // TODO Auto-generated method stub  
  4.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  5.         int width = measureDimension(200, widthMeasureSpec);  
  6.         int height = measureDimension(200, heightMeasureSpec);  
  7.         setMeasuredDimension(width, height);  
  8.     }  
  9.   
  10.     public int measureDimension(int defaultSize, int measureSpec){  
  11.         int result;  
  12.           
  13.         int specMode = MeasureSpec.getMode(measureSpec);  
  14.         int specSize = MeasureSpec.getSize(measureSpec);  
  15.           
  16.         if(specMode == MeasureSpec.EXACTLY){  
  17.             result = specSize;  
  18.         }else{  
  19.             result = defaultSize;   //UNSPECIFIED  
  20.             if(specMode == MeasureSpec.AT_MOST){  
  21.                 result = Math.min(result, specSize);  
  22.             }  
  23.         }  
  24.         return result;  
  25.     }  

重写onMeasure()方法时,必须最后调用setMeasureDimension()方法,否则会报错。然后我们最终setMeasureDimension()的width和height是怎么计算得到的呢?


首先我们解析widthMeasureSpec获得两个数据,一个是父视图希望子视图的大小是多少,一个是关于大小的模式,这两个数据分别通过以下两句代码获得


[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int specMode = MeasureSpec.getMode(measureSpec);  
  2. int specSize = MeasureSpec.getSize(measureSpec);  

MeasureSpec.getMode()方法返回的结果有三种:
  • UNSPECIFIED:父结点对子结点的大小没有任何要求。
  • EXACTLY:  父结点要求其子节点的大小指定为某个确切的值。其子节点以及其他子孙结点都需要适应该大小。   
  • AT MOST:父结点要求其子节点的大小不能超过某个最大值,其子节点以及其他子孙结点的大小都需要小于这个值


扫一扫在手机打开

评论
已有0条评论
0/150
提交
热门评论
相关推荐
今日要闻
换一批
热点排行