[原创]android自定义控件的最大高度MaxHeightView
代码地址:https://github.com/Carbs0126/MaxHeightView
android中部分控件具有maxHeight功能,如button等,但是对于ViewGroup类的控件,没有此属性,当我们需要限制某些view的高度时,(比如限制屏幕下方对话框的最大高度)那么,就需要一种可以限制其子view最大高度的ViewGroup。如何为自定义ViewGroup添加一个最大高度的属性呢?其实很简单,主要就是使用onMeasure()函数,在函数中控制高度即可。
先看下效果图:
这是一个dialog,dialog中添加了共有20个button,如果不使用最大高度可控的viewgroup,则会充满整个屏幕。
java代码实现如下:
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 }
属性文件如下:
<?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>
实现原理:
1.在构造方法中获取最大高度或者最大高度的比例;
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
欢迎指正。