Android开发中偶尔会用到自定义View,一般情况下,自定义View都需要继承View类的onMeasure方法,那么,为什么要继承 onMeasure()函数呢?什么情况下要继承onMeasure()?系统默认的onMeasure()函数行为是怎样的 ?本文就探究探究这些问题。

 

首先,我们写一个自定义View,直接调用系统默认的onMeasure函数,看看会是怎样的现象:

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
      
      <div class="line number6 index5 alt1">
        6
      </div>
      
      <div class="line number7 index6 alt2">
        7
      </div>
      
      <div class="line number8 index7 alt1">
        8
      </div>
      
      <div class="line number9 index8 alt2">
        9
      </div>
      
      <div class="line number10 index9 alt1">
        10
      </div>
      
      <div class="line number11 index10 alt2">
        11
      </div>
      
      <div class="line number12 index11 alt1">
        12
      </div>
      
      <div class="line number13 index12 alt2">
        13
      </div>
      
      <div class="line number14 index13 alt1">
        14
      </div>
      
      <div class="line number15 index14 alt2">
        15
      </div>
      
      <div class="line number16 index15 alt1">
        16
      </div>
      
      <div class="line number17 index16 alt2">
        17
      </div>
      
      <div class="line number18 index17 alt1">
        18
      </div>
      
      <div class="line number19 index18 alt2">
        19
      </div>
      
      <div class="line number20 index19 alt1">
        20
      </div>
      
      <div class="line number21 index20 alt2">
        21
      </div>
      
      <div class="line number22 index21 alt1">
        22
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `package` `com.titcktick.customview;`
        </div>
        
        <div class="line number2 index1 alt1">
        </div>
        
        <div class="line number3 index2 alt2">
          `import` `android.content.Context;`
        </div>
        
        <div class="line number4 index3 alt1">
          `import` `android.util.AttributeSet;`
        </div>
        
        <div class="line number5 index4 alt2">
          `import` `android.view.View;`
        </div>
        
        <div class="line number6 index5 alt1">
        </div>
        
        <div class="line number7 index6 alt2">
          `public` `class` `CustomView ``extends` `View {`
        </div>
        
        <div class="line number8 index7 alt1">
          `    `
        </div>
        
        <div class="line number9 index8 alt2">
          `    ``public` `CustomView(Context context) {`
        </div>
        
        <div class="line number10 index9 alt1">
          `        ``super``(context); `
        </div>
        
        <div class="line number11 index10 alt2">
          `    ``}`
        </div>
        
        <div class="line number12 index11 alt1">
        </div>
        
        <div class="line number13 index12 alt2">
          `    ``public` `CustomView(Context context, AttributeSet attrs) {`
        </div>
        
        <div class="line number14 index13 alt1">
          `        ``super``(context, attrs);      `
        </div>
        
        <div class="line number15 index14 alt2">
          `    ``}`
        </div>
        
        <div class="line number16 index15 alt1">
          `    `
        </div>
        
        <div class="line number17 index16 alt2">
          `    ``@Override`
        </div>
        
        <div class="line number18 index17 alt1">
          `    ``protected` `void` `onMeasure(``int` `widthMeasureSpec, ``int` `heightMeasureSpec) {        `
        </div>
        
        <div class="line number19 index18 alt2">
          `        ``super``.onMeasure(widthMeasureSpec, heightMeasureSpec);`
        </div>
        
        <div class="line number20 index19 alt1">
          `    ``}`
        </div>
        
        <div class="line number21 index20 alt2">
        </div>
        
        <div class="line number22 index21 alt1">
          `}`
        </div>
      </div>
    </td>
  </tr>
</table>

 

1. 父控件使用match_parent,CustomView使用match_parent

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
      
      <div class="line number6 index5 alt1">
        6
      </div>
      
      <div class="line number7 index6 alt2">
        7
      </div>
      
      <div class="line number8 index7 alt1">
        8
      </div>
      
      <div class="line number9 index8 alt2">
        9
      </div>
      
      <div class="line number10 index9 alt1">
        10
      </div>
      
      <div class="line number11 index10 alt2">
        11
      </div>
      
      <div class="line number12 index11 alt1">
        12
      </div>
      
      <div class="line number13 index12 alt2">
        13
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `&lt;LinearLayout xmlns:android=``"http://schemas.android.com/apk/res/android"`
        </div>
        
        <div class="line number2 index1 alt1">
          `    ``xmlns:tools=``"http://schemas.android.com/tools"`
        </div>
        
        <div class="line number3 index2 alt2">
          `    ``android:layout_width=``"match_parent"`
        </div>
        
        <div class="line number4 index3 alt1">
          `    ``android:layout_height=``"match_parent"`
        </div>
        
        <div class="line number5 index4 alt2">
          `    ``android:orientation=``"vertical"``&gt;`
        </div>
        
        <div class="line number6 index5 alt1">
        </div>
        
        <div class="line number7 index6 alt2">
          `    ``&lt;com.titcktick.customview.CustomView`
        </div>
        
        <div class="line number8 index7 alt1">
          `        ``android:layout_width=``"match_parent"`
        </div>
        
        <div class="line number9 index8 alt2">
          `        ``android:layout_height=``"match_parent"`
        </div>
        
        <div class="line number10 index9 alt1">
          `        ``android:layout_margin=``"10dp"`
        </div>
        
        <div class="line number11 index10 alt2">
          `        ``android:background=``"@android:color/black"``/&gt;`
        </div>
        
        <div class="line number12 index11 alt1">
        </div>
        
        <div class="line number13 index12 alt2">
          `&lt;/LinearLayout&gt;`
        </div>
      </div>
    </td>
  </tr>
</table>

 

这里加了10dp的margin并且把View的背景设置为了黑色,是为了方便辨别我们的CustomView,效果如下:

 

wKioL1Pso77ROkIvAAAxTKcLymg465.jpg

 

我们可以看到,默认情况下,如果父控件和CustomView都使用match_parent,则CustomView会充满父控件。

 

2.  父控件使用match_parent,CustomView使用wrap_content

 

把layout文件中,CustomView的layout_width/layout_height替换为wrap_content,你会发现,结果依然是充满父控件。

 

3.  父控件使用match_parent,CustomView使用固定的值

 

把layout文件中,CustomView的layout_width/layout_height替换为50dp,你会发现,CustomView的显示结果为50dpx50dp,如图所示:

 

wKiom1PsoqaShr74AAA8MgI5FPY164.jpg

 

4.  父控件使用固定的值,CustomView使用match_parent或者wrap_content

 

那么,如果把父控件的layout_width/layout_height替换为50dp,CustomView设置为match_parent或者wrap_content,你会发现,CustomView的显示结果也是为50dpx50 dp。

 

5  结论

 

如果自定义的CustomView采用默认的onMeasure函数,行为如下:

 

(1) CustomView设置为 match_parent 或者 wrap_content 没有任何区别,其显示大小由父控件决定,它会填充满整个父控件的空间。

 

(2) CustomView设置为固定的值,则其显示大小为该设定的值。

 

如果你的自定义控件的大小计算就是跟系统默认的行为一致的话,那么你就不需要重写onMeasure函数了。

 

6. 怎样编写onMeasure函数

 

系统默认的onMeasure函数的行为就讨论到这,下面也说说怎样重写onMeasure函数,以及onMeasure函数的基本原理,关键部分在代码中以注释的形式给出了,仅供参考:

 

1
      <div class="line number2 index1 alt1">
        2
      </div>
      
      <div class="line number3 index2 alt2">
        3
      </div>
      
      <div class="line number4 index3 alt1">
        4
      </div>
      
      <div class="line number5 index4 alt2">
        5
      </div>
      
      <div class="line number6 index5 alt1">
        6
      </div>
      
      <div class="line number7 index6 alt2">
        7
      </div>
      
      <div class="line number8 index7 alt1">
        8
      </div>
      
      <div class="line number9 index8 alt2">
        9
      </div>
      
      <div class="line number10 index9 alt1">
        10
      </div>
      
      <div class="line number11 index10 alt2">
        11
      </div>
      
      <div class="line number12 index11 alt1">
        12
      </div>
      
      <div class="line number13 index12 alt2">
        13
      </div>
      
      <div class="line number14 index13 alt1">
        14
      </div>
      
      <div class="line number15 index14 alt2">
        15
      </div>
      
      <div class="line number16 index15 alt1">
        16
      </div>
      
      <div class="line number17 index16 alt2">
        17
      </div>
      
      <div class="line number18 index17 alt1">
        18
      </div>
      
      <div class="line number19 index18 alt2">
        19
      </div>
      
      <div class="line number20 index19 alt1">
        20
      </div>
      
      <div class="line number21 index20 alt2">
        21
      </div>
      
      <div class="line number22 index21 alt1">
        22
      </div>
      
      <div class="line number23 index22 alt2">
        23
      </div>
      
      <div class="line number24 index23 alt1">
        24
      </div>
      
      <div class="line number25 index24 alt2">
        25
      </div>
      
      <div class="line number26 index25 alt1">
        26
      </div>
      
      <div class="line number27 index26 alt2">
        27
      </div>
      
      <div class="line number28 index27 alt1">
        28
      </div>
      
      <div class="line number29 index28 alt2">
        29
      </div>
      
      <div class="line number30 index29 alt1">
        30
      </div>
      
      <div class="line number31 index30 alt2">
        31
      </div>
      
      <div class="line number32 index31 alt1">
        32
      </div>
      
      <div class="line number33 index32 alt2">
        33
      </div>
      
      <div class="line number34 index33 alt1">
        34
      </div>
      
      <div class="line number35 index34 alt2">
        35
      </div>
      
      <div class="line number36 index35 alt1">
        36
      </div>
      
      <div class="line number37 index36 alt2">
        37
      </div>
      
      <div class="line number38 index37 alt1">
        38
      </div>
      
      <div class="line number39 index38 alt2">
        39
      </div>
      
      <div class="line number40 index39 alt1">
        40
      </div>
      
      <div class="line number41 index40 alt2">
        41
      </div>
      
      <div class="line number42 index41 alt1">
        42
      </div>
      
      <div class="line number43 index42 alt2">
        43
      </div>
      
      <div class="line number44 index43 alt1">
        44
      </div>
      
      <div class="line number45 index44 alt2">
        45
      </div>
      
      <div class="line number46 index45 alt1">
        46
      </div>
      
      <div class="line number47 index46 alt2">
        47
      </div>
      
      <div class="line number48 index47 alt1">
        48
      </div>
      
      <div class="line number49 index48 alt2">
        49
      </div>
      
      <div class="line number50 index49 alt1">
        50
      </div>
      
      <div class="line number51 index50 alt2">
        51
      </div>
      
      <div class="line number52 index51 alt1">
        52
      </div>
      
      <div class="line number53 index52 alt2">
        53
      </div>
      
      <div class="line number54 index53 alt1">
        54
      </div>
    </td>
    
    <td class="code">
      <div class="container">
        <div class="line number1 index0 alt2">
          `package` `com.titcktick.customview;`
        </div>
        
        <div class="line number2 index1 alt1">
        </div>
        
        <div class="line number3 index2 alt2">
          `import` `android.content.Context;`
        </div>
        
        <div class="line number4 index3 alt1">
          `import` `android.util.AttributeSet;`
        </div>
        
        <div class="line number5 index4 alt2">
          `import` `android.view.View;`
        </div>
        
        <div class="line number6 index5 alt1">
        </div>
        
        <div class="line number7 index6 alt2">
          `public` `class` `CustomView ``extends` `View {`
        </div>
        
        <div class="line number8 index7 alt1">
          `    `
        </div>
        
        <div class="line number9 index8 alt2">
          `    ``private` `static` `final` `int` `DEFAULT_VIEW_WIDTH = ``100``;`
        </div>
        
        <div class="line number10 index9 alt1">
          `    ``private` `static` `final` `int` `DEFAULT_VIEW_HEIGHT = ``100``;`
        </div>
        
        <div class="line number11 index10 alt2">
          `    `
        </div>
        
        <div class="line number12 index11 alt1">
          `    ``public` `CustomView(Context context) {`
        </div>
        
        <div class="line number13 index12 alt2">
          `        ``super``(context); `
        </div>
        
        <div class="line number14 index13 alt1">
          `    ``}`
        </div>
        
        <div class="line number15 index14 alt2">
        </div>
        
        <div class="line number16 index15 alt1">
          `    ``public` `CustomView(Context context, AttributeSet attrs) {`
        </div>
        
        <div class="line number17 index16 alt2">
          `        ``super``(context, attrs);      `
        </div>
        
        <div class="line number18 index17 alt1">
          `    ``}`
        </div>
        
        <div class="line number19 index18 alt2">
          `    `
        </div>
        
        <div class="line number20 index19 alt1">
          `    ``@Override`
        </div>
        
        <div class="line number21 index20 alt2">
          `    ``protected` `void` `onMeasure(``int` `widthMeasureSpec, ``int` `heightMeasureSpec) {`
        </div>
        
        <div class="line number22 index21 alt1">
          `        `
        </div>
        
        <div class="line number23 index22 alt2">
          `        ``int` `width  = measureDimension(DEFAULT_VIEW_WIDTH, widthMeasureSpec);`
        </div>
        
        <div class="line number24 index23 alt1">
          `        ``int` `height = measureDimension(DEFAULT_VIEW_HEIGHT, heightMeasureSpec);`
        </div>
        
        <div class="line number25 index24 alt2">
          `        `
        </div>
        
        <div class="line number26 index25 alt1">
          `        ``setMeasuredDimension(width, height);                `
        </div>
        
        <div class="line number27 index26 alt2">
          `    ``}`
        </div>
        
        <div class="line number28 index27 alt1">
          `    `
        </div>
        
        <div class="line number29 index28 alt2">
          `    ``protected` `int` `measureDimension( ``int` `defaultSize, ``int` `measureSpec ) {`
        </div>
        
        <div class="line number30 index29 alt1">
          `        `
        </div>
        
        <div class="line number31 index30 alt2">
          `        ``int` `result = defaultSize;`
        </div>
        
        <div class="line number32 index31 alt1">
          `        `
        </div>
        
        <div class="line number33 index32 alt2">
          `        ``int` `specMode = MeasureSpec.getMode(measureSpec);`
        </div>
        
        <div class="line number34 index33 alt1">
          `        ``int` `specSize = MeasureSpec.getSize(measureSpec);`
        </div>
        
        <div class="line number35 index34 alt2">
          `                `
        </div>
        
        <div class="line number36 index35 alt1">
          `        ``//1. layout给出了确定的值,比如:100dp`
        </div>
        
        <div class="line number37 index36 alt2">
          `        ``//2. layout使用的是match_parent,但父控件的size已经可以确定了,比如设置的是具体的值或者match_parent`
        </div>
        
        <div class="line number38 index37 alt1">
          `        ``if` `(specMode == MeasureSpec.EXACTLY) {      `
        </div>
        
        <div class="line number39 index38 alt2">
          `            ``result = specSize; ``//建议:result直接使用确定值`
        </div>
        
        <div class="line number40 index39 alt1">
          `        ``} `
        </div>
        
        <div class="line number41 index40 alt2">
          `        ``//1. layout使用的是wrap_content`
        </div>
        
        <div class="line number42 index41 alt1">
          `        ``//2. layout使用的是match_parent,但父控件使用的是确定的值或者wrap_content`
        </div>
        
        <div class="line number43 index42 alt2">
          `        ``else` `if` `(specMode == MeasureSpec.AT_MOST) {             `
        </div>
        
        <div class="line number44 index43 alt1">
          `            ``result = Math.min(defaultSize, specSize); ``//建议:result不能大于specSize`
        </div>
        
        <div class="line number45 index44 alt2">
          `        ``} `
        </div>
        
        <div class="line number46 index45 alt1">
          `        ``//UNSPECIFIED,没有任何限制,所以可以设置任何大小`
        </div>
        
        <div class="line number47 index46 alt2">
          `        ``//多半出现在自定义的父控件的情况下,期望由自控件自行决定大小`
        </div>
        
        <div class="line number48 index47 alt1">
          `        ``else` `{      `
        </div>
        
        <div class="line number49 index48 alt2">
          `            ``result = defaultSize; `
        </div>
        
        <div class="line number50 index49 alt1">
          `        ``}`
        </div>
        
        <div class="line number51 index50 alt2">
          `        `
        </div>
        
        <div class="line number52 index51 alt1">
          `        ``return` `result;`
        </div>
        
        <div class="line number53 index52 alt2">
          `    ``}`
        </div>
        
        <div class="line number54 index53 alt1">
          `}`
        </div>
      </div>
    </td>
  </tr>
</table>

 

这样重载了onMeasure函数之后,你会发现,当CustomView使用match_parent的时候,它会占满整个父控件,而当CustomView使用wrap_content的时候,它的大小则是代码中定义的默认大小100×100像素。当然,你也可以根据自己的需求改写measureDimension()的实现。

 

转自:http://ticktick.blog.51cto.com/823160/1540134

💬 评论