代碼地址:https://github.com/Carbs0126/MaxHeightViewjava
android中部分控件具備maxHeight功能,如button等,可是對於ViewGroup類的控件,沒有此屬性,當咱們須要限制某些view的高度時,(好比限制屏幕下方對話框的最大高度)那麼,就須要一種能夠限制其子view最大高度的ViewGroup。如何爲自定義ViewGroup添加一個最大高度的屬性呢?其實很簡單,主要就是使用onMeasure()函數,在函數中控制高度便可。android
先看下效果圖:git
這是一個dialog,dialog中添加了共有20個button,若是不使用最大高度可控的viewgroup,則會充滿整個屏幕。github
java代碼實現以下:app
1 package cn.carbs.android.maxheightview.library; 2 3 /** 4 * Created by carbs on 2016/5/12. 5 */ 6 import android.content.Context; 7 import android.content.res.TypedArray; 8 import android.util.AttributeSet; 9 import android.view.WindowManager; 10 import android.widget.FrameLayout; 11 12 /** 13 * 先判斷是否設定了mMaxHeight,若是設定了mMaxHeight,則直接使用mMaxHeight的值, 14 * 若是沒有設定mMaxHeight,則判斷是否設定了mMaxRatio,若是設定了mMaxRatio的值 則使用此值與屏幕高度的乘積做爲最高高度 15 * 16 * @author Carbs 17 */ 18 public class MaxHeightView extends FrameLayout { 19 20 private static final float DEFAULT_MAX_RATIO = 0.6f; 21 private static final float DEFAULT_MAX_HEIGHT = 0f; 22 23 private float mMaxRatio = DEFAULT_MAX_RATIO;// 優先級高 24 private float mMaxHeight = DEFAULT_MAX_HEIGHT;// 優先級低 25 26 public MaxHeightView(Context context) { 27 super(context); 28 init(); 29 } 30 31 public MaxHeightView(Context context, AttributeSet attrs) { 32 super(context, attrs); 33 initAttrs(context, attrs); 34 init(); 35 } 36 37 public MaxHeightView(Context context, AttributeSet attrs, int defStyle) { 38 super(context, attrs, defStyle); 39 initAttrs(context, attrs); 40 init(); 41 } 42 43 private void initAttrs(Context context, AttributeSet attrs) { 44 TypedArray a = context.obtainStyledAttributes(attrs, 45 R.styleable.MaxHeightView); 46 47 final int count = a.getIndexCount(); 48 for (int i = 0; i < count; ++i) { 49 int attr = a.getIndex(i); 50 if(attr == R.styleable.MaxHeightView_mhv_HeightRatio){ 51 mMaxRatio = a.getFloat(attr, DEFAULT_MAX_RATIO); 52 }else if(attr == R.styleable.MaxHeightView_mhv_HeightDimen){ 53 mMaxHeight = a.getDimension(attr, DEFAULT_MAX_HEIGHT); 54 } 55 } 56 a.recycle(); 57 } 58 59 private void init(){ 60 if (mMaxHeight <= 0) { 61 mMaxHeight = mMaxRatio * (float) getScreenHeight(getContext()); 62 } else { 63 mMaxHeight = Math.min(mMaxHeight, mMaxRatio * (float) getScreenHeight(getContext())); 64 } 65 } 66 67 @Override 68 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 69 70 int heightMode = MeasureSpec.getMode(heightMeasureSpec); 71 int heightSize = MeasureSpec.getSize(heightMeasureSpec); 72 73 if (heightMode == MeasureSpec.EXACTLY) { 74 heightSize = heightSize <= mMaxHeight ? heightSize 75 : (int) mMaxHeight; 76 } 77 78 if (heightMode == MeasureSpec.UNSPECIFIED) { 79 heightSize = heightSize <= mMaxHeight ? heightSize 80 : (int) mMaxHeight; 81 } 82 if (heightMode == MeasureSpec.AT_MOST) { 83 heightSize = heightSize <= mMaxHeight ? heightSize 84 : (int) mMaxHeight; 85 } 86 int maxHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, 87 heightMode); 88 super.onMeasure(widthMeasureSpec, maxHeightMeasureSpec); 89 } 90 91 /** 92 * 獲取屏幕高度 93 * 94 * @param context 95 */ 96 private int getScreenHeight(Context context) { 97 WindowManager wm = (WindowManager) context 98 .getSystemService(Context.WINDOW_SERVICE); 99 return wm.getDefaultDisplay().getHeight(); 100 } 101 102 }
屬性文件以下:ide
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MaxHeightView"> <attr name="mhv_HeightRatio" format="reference|float" /> <attr name="mhv_HeightDimen" format="reference|dimension" /> </declare-styleable> </resources>
使用方法:函數
在佈局中使用以下代碼:佈局
<cn.carbs.android.maxheightview.library.MaxHeightView android:id="@+id/maxview" android:layout_width="match_parent" android:layout_height="wrap_content" app:mhv_HeightRatio="0.7"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="60dp" android:gravity="center" android:text="MaxHeightView" android:textSize="20sp"/> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <Button android:layout_width="match_parent" android:layout_height="60dp" android:text="button0"/> <Button android:layout_width="match_parent" android:layout_height="60dp" android:text="button1"/> .......... </LinearLayout> </ScrollView> </LinearLayout> </cn.carbs.android.maxheightview.library.MaxHeightView>
實現原理:spa
1.在構造方法中獲取最大高度或者最大高度的比例;code
2.在onMeasure()中經過獲取heightMeasureSpec的size判斷是否大於限定最大高度,若是大於,則將size設置爲限定最大高度,並從新生成heightMeasureSpec,並調用super.onMeasure(widthMeasureSpec, maxHeightMeasureSpec);以完成onMeasure對控件大小的設定
注意事項:
此自定義view繼承自FrameLayout,使用時最好嵌套一個ScrollView,以提升用戶體驗。
此view不完善的地方有,暫時不支持經過代碼生成MaxHeightView,不過能夠經過修改只有一個構造方法的public MaxHeightView(Context context)添加對應的mMaxHeight或者Ratio來限制大小。
代碼項目地址:
https://github.com/Carbs0126/MaxHeightView
歡迎指正。