android中部分控件具备maxHeight功能,如button等,可是对于ViewGroup类的控件,没有此属性,当咱们须要限制某些view的高度时,(好比限制屏幕下方对话框的最大高度)那么,就须要一种能够限制其子view最大高度的ViewGroup。如何为自定义ViewGroup添加一个最大高度的属性呢?其实很简单,主要就是使用onMeasure()函数,在函数中控制高度便可。android
先看下效果图:git
这是一个dialog,dialog中添加了共有20个button,若是不使用最大高度可控的viewgroup,则会充满整个屏幕。github
java代码实现以下:app
1 packagecn.carbs.android.maxheightview.library;2
3 /**
4 * Created by carbs on 2016/5/12.5 */
6 importandroid.content.Context;7 importandroid.content.res.TypedArray;8 importandroid.util.AttributeSet;9 importandroid.view.WindowManager;10 importandroid.widget.FrameLayout;11
12 /**
13 * 先判断是否设定了mMaxHeight,若是设定了mMaxHeight,则直接使用mMaxHeight的值,14 * 若是没有设定mMaxHeight,则判断是否设定了mMaxRatio,若是设定了mMaxRatio的值 则使用此值与屏幕高度的乘积做为最高高度15 *16 *@authorCarbs17 */
18 public class MaxHeightView extendsFrameLayout {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 publicMaxHeightView(Context context) {27 super(context);28 init();29 }30
31 publicMaxHeightView(Context context, AttributeSet attrs) {32 super(context, attrs);33 initAttrs(context, attrs);34 init();35 }36
37 public MaxHeightView(Context context, AttributeSet attrs, intdefStyle) {38 super(context, attrs, defStyle);39 initAttrs(context, attrs);40 init();41 }42
43 private voidinitAttrs(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 voidinit(){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 @Override68 protected void onMeasure(int widthMeasureSpec, intheightMeasureSpec) {69
70 int heightMode =MeasureSpec.getMode(heightMeasureSpec);71 int heightSize =MeasureSpec.getSize(heightMeasureSpec);72
73 if (heightMode ==MeasureSpec.EXACTLY) {74 heightSize = heightSize <= mMaxHeight ?heightSize75 : (int) mMaxHeight;76 }77
78 if (heightMode ==MeasureSpec.UNSPECIFIED) {79 heightSize = heightSize <= mMaxHeight ?heightSize80 : (int) mMaxHeight;81 }82 if (heightMode ==MeasureSpec.AT_MOST) {83 heightSize = heightSize <= mMaxHeight ?heightSize84 : (int) mMaxHeight;85 }86 int maxHeightMeasureSpec =MeasureSpec.makeMeasureSpec(heightSize,87 heightMode);88 super.onMeasure(widthMeasureSpec, maxHeightMeasureSpec);89 }90
91 /**
92 * 获取屏幕高度93 *94 *@paramcontext95 */
96 private intgetScreenHeight(Context context) {97 WindowManager wm =(WindowManager) context98 .getSystemService(Context.WINDOW_SERVICE);99 returnwm.getDefaultDisplay().getHeight();100 }101
102 }
属性文件以下:ide
使用方法:函数
在布局中使用以下代码:布局
..........
实现原理: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来限制大小。
代码项目地址:
欢迎指正。