隨筆雜記

             :: 首頁 :: 新隨筆 ::  ::  :: 管理 ::

          有時(shí),Android系統(tǒng)控件無法滿足我們的需求,因此有必要自定義View。具體方法參見官方開發(fā)文檔:http://developer.android.com/guide/topics/ui/custom-components.html


          一般來說,自定義控件都會(huì)去重寫View的onMeasure方法,因?yàn)樵摲椒ㄖ付ㄔ摽丶谄聊簧系拇笮 ?/p>

          protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)

          onMeasure傳入的兩個(gè)參數(shù)是由上一層控件傳入的大小,有多種情況,重寫該方法時(shí)需要對(duì)計(jì)算控件的實(shí)際大小,然后調(diào)用setMeasuredDimension(int, int)設(shè)置實(shí)際大小。


          onMeasure傳入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸數(shù)值,而是將模式和尺寸組合在一起的數(shù)值。我們需要通過int mode = MeasureSpec.getMode(widthMeasureSpec)得到模式,用int size = MeasureSpec.getSize(widthMeasureSpec)得到尺寸。


          mode共有三種情況,取值分別為MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。


          MeasureSpec.EXACTLY是精確尺寸,當(dāng)我們將控件的layout_width或layout_height指定為具體數(shù)值時(shí)如andorid:layout_width="50dip",或者為FILL_PARENT是,都是控件大小已經(jīng)確定的情況,都是精確尺寸。


          MeasureSpec.AT_MOST是最大尺寸,當(dāng)控件的layout_width或layout_height指定為WRAP_CONTENT時(shí),控件大小一般隨著控件的子空間或內(nèi)容進(jìn)行變化,此時(shí)控件尺寸只要不超過父控件允許的最大尺寸即可。因此,此時(shí)的mode是AT_MOST,size給出了父控件允許的最大尺寸。


          MeasureSpec.UNSPECIFIED是未指定尺寸,這種情況不多,一般都是父控件是AdapterView,通過measure方法傳入的模式。


          因此,在重寫onMeasure方法時(shí)要根據(jù)模式不同進(jìn)行尺寸計(jì)算。下面代碼就是一種比較典型的方式:

          @Override    
          protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    
              setMeasuredDimension(getMeasuredLength(widthMeasureSpec, true), getMeasuredLength(heightMeasureSpec, false));    
          }    
              
              
          private int getMeasuredLength(int length, boolean isWidth) {    
              int specMode = MeasureSpec.getMode(length);    
              int specSize = MeasureSpec.getSize(length);    
              int size;    
              int padding = isWidth ? getPaddingLeft() + getPaddingRight()    
                      : getPaddingTop() + getPaddingBottom();    
              if (specMode == MeasureSpec.EXACTLY) {    
                  size = specSize;    
              } else {    
                  size = isWidth ? padding + mWave.length / 4 : DEFAULT_HEIGHT    
                          + padding;    
                  if (specMode == MeasureSpec.AT_MOST) {    
                      size = Math.min(size, specSize);    
                  }    
              }    
              return size;    
          }  

          posted on 2012-03-15 19:18 天宇恒星 閱讀(30323) 評(píng)論(2)  編輯  收藏 所屬分類: Android

          評(píng)論

          # re: Android中自定義View的MeasureSpec使用 2013-02-01 11:53 jeremy_sky
          你好。mode共有三種情況,取值分別為MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。既然三種模式對(duì)應(yīng)不同的數(shù)值,那么為什么在源碼中需要這個(gè)模式屬性呢?比如:(Linearlayout.java 方法 measureVertical(int widthMeasureSpec, int heightMeasureSpec)部分源碼 )
          if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {
          final int totalLength = mTotalLength;
          mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
          } else {
          int oldHeight = Integer.MIN_VALUE;

          if (lp.height == 0 && lp.weight > 0) {
          oldHeight = 0;
          lp.height = LayoutParams.WRAP_CONTENT;
          }
          ...
          }
          能幫我解釋一下么?(主要是代碼沒看懂~~~)

            回復(fù)  更多評(píng)論
            

          # re: Android中自定義View的MeasureSpec使用 2014-12-01 19:53 渣渣
          heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0這個(gè)很明顯是要判斷權(quán)重weight,哎寫自定義控件確實(shí)是個(gè)麻煩事,要考慮寬高,還要考慮padding,weight。  回復(fù)  更多評(píng)論
            

          主站蜘蛛池模板: 武强县| 泊头市| 重庆市| 海丰县| 肥城市| 乌海市| 岗巴县| 巴马| 万荣县| 湖北省| 长岛县| 枣庄市| 睢宁县| 奉贤区| 平潭县| 蚌埠市| 瑞金市| 万全县| 商洛市| 宜昌市| 兴城市| 新河县| 磴口县| 元氏县| 民和| 县级市| 连州市| 隆化县| 北碚区| 承德市| 济阳县| 宾川县| 廊坊市| 莱西市| 津市市| 北流市| 石棉县| 合水县| 榆中县| 南涧| 柯坪县|