Android自定义可控最大宽高的Layout
来源:互联网 发布:dg恢复数据 编辑:程序博客网 时间:2024/06/06 03:14
完整项目示例Git仓库
https://git.oschina.net/jokerlee/CustomFrameLayout.git
Android View的宽高属性
View拥有的默认属性中含有minHeight以及minWidth可以控制view在其父View布局计算宽高时,能够有一个最小的宽高的限定;在进行一些布局的时候能够利用该属性来限定最小的宽高,但能否自己定义maxHeight和maxWidth来实现同样的限定view的宽高上限?
<Button android:id="@+id/button" android:minHeight="155dp" android:minWidth="240dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Select"/>
Android自定义attr属性
View除了android赋予的默认属性可以使用外,还提供了自己定义属性的方法,即在在res/values文件下新建一个attrs.xml,加入自定义的属性:
在布局xml使用自定义属性
在attrs.xml文件声明定义好自定义属性的名称和类型之后,在布局文件内加入:
xmlns:custom_attr="http://schemas.android.com/apk/res-auto"
xmlns:custom_attr="http://schemas.android.com/apk/res/[your package name]
新的官方文档建议使用第一个namespace声明(Android Studio仅支持该声明),旧版可使用第二种写法。
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:custom_attr="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.jokerlee.custommaxsizeframelayout.MainActivity"> <com.example.jokerlee.custommaxsizeframelayout.CustomFramlayout android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" custom_attr:layout_maxWidth="50dp" custom_attr:layout_maxHeight="30dp"> <ImageView android:layout_width="350dp" android:layout_height="330dp" android:layout_gravity="center" android:background="@color/material_blue_grey_800"/> </FrameLayout> </com.example.jokerlee.custommaxsizeframelayout.CustomFramlayout></RelativeLayout>
最大宽高限制的实现
自定义LayoutParams类,用于自定义的view的布局,从属性集合内读取出maxWidth和maxHeight:
public static class LayoutParams extends FrameLayout.LayoutParams { @ViewDebug.ExportedProperty(category = "layout") public int maxWidth; @ViewDebug.ExportedProperty(category = "layout") public int maxHeight; public LayoutParams(ViewGroup.LayoutParams other) { super(other); } public LayoutParams(LayoutParams other) { super(other); maxWidth = other.maxWidth; maxHeight = other.maxHeight; } public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); final TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.CustomFrameLayoutAttr, 0, 0); maxWidth = a.getDimensionPixelSize( R.styleable.CustomFrameLayoutAttr_layout_maxWidth, 0); maxHeight = a.getDimensionPixelSize( R.styleable.CustomFrameLayoutAttr_layout_maxHeight, 0); a.recycle(); } }
重载ViewGroup的layoutParams生成函数,这几个函数负责将view的属性集合或者现有的ViewGroup.LayoutParams转换为适用于当前view类型的布局参数。
@Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(),attrs); } @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return p instanceof LayoutParams ? new LayoutParams((LayoutParams)p):new LayoutParams(p); } @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof LayoutParams; }
核心的子view布局宽高控制为onMeasure函数,该函数计算并设置所有child view包括自身的大小,保证child view不会超过max值
@Override protected void onMeasure(int widthSpec, int heightSpec) { final int widthMode = MeasureSpec.getMode(widthSpec); final int heightMode = MeasureSpec.getMode(heightSpec); if (DEBUG && widthMode != MeasureSpec.AT_MOST) { Log.w(TAG, "onMeasure: widthSpec " + MeasureSpec.toString(widthSpec) + " should be AT_MOST"); } if (DEBUG && heightMode != MeasureSpec.AT_MOST) { Log.w(TAG, "onMeasure: heightSpec " + MeasureSpec.toString(heightSpec) + " should be AT_MOST"); } final int widthSize = MeasureSpec.getSize(widthSpec); final int heightSize = MeasureSpec.getSize(heightSpec); int maxWidth = widthSize; int maxHeight = heightSize; final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (lp.maxWidth > 0 && lp.maxWidth < maxWidth) { maxWidth = lp.maxWidth; } if (lp.maxHeight > 0 && lp.maxHeight < maxHeight) { maxHeight = lp.maxHeight; } } final int wPadding = getPaddingLeft() + getPaddingRight(); final int hPadding = getPaddingTop() + getPaddingBottom(); maxWidth -= wPadding; maxHeight -= hPadding; int width = widthMode == MeasureSpec.EXACTLY ? widthSize : 0; int height = heightMode == MeasureSpec.EXACTLY ? heightSize : 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); final int childWidthSpec = makeChildMeasureSpec(maxWidth, lp.width); final int childHeightSpec = makeChildMeasureSpec(maxHeight, lp.height); child.measure(childWidthSpec, childHeightSpec); width = Math.max(width, Math.min(child.getMeasuredWidth(), widthSize - wPadding)); height = Math.max(height, Math.min(child.getMeasuredHeight(), heightSize - hPadding)); } setMeasuredDimension(width + wPadding, height + hPadding); } private int makeChildMeasureSpec(int maxSize, int childDimen) { final int mode; final int size; switch (childDimen) { case LayoutParams.WRAP_CONTENT: mode = MeasureSpec.AT_MOST; size = maxSize; break; case LayoutParams.MATCH_PARENT: mode = MeasureSpec.EXACTLY; size = maxSize; break; default: mode = MeasureSpec.EXACTLY; size = Math.min(maxSize, childDimen); break; } return MeasureSpec.makeMeasureSpec(size, mode); }
0 0
- Android自定义可控最大宽高的Layout
- 自定义RatingBar控件,实现可自定义星星(或项目所需图片)的宽高,告别使用warp_content导致控件大小不可控
- 【Android】可控滑动的Viewpager
- android 自定义对话框宽不能占满父layout的解决办法
- 分享一个自定义的SlidingDrawer,可控大小。
- 分享一个自定义的SlidingDrawer,可控大小
- Android自定义带标题边框的Layout
- Android自定义带标题边框的Layout
- android 自定义Layout布局
- android 解析自定义layout
- Android自定义Layout
- Android经典可控线程的实现
- android 动态添加组件,layout的宽高的正确显示
- 自定义可控带跑马灯效果的TextView
- Android自定义宽高动画
- layout中设置图片自适应大小,并且设置最大宽高
- layout中设置图片自适应大小,并且设置最大宽高
- Android--Notification加载自定义Layout
- 越看心越宽,能打开任何人心结的好文章
- 快速排序 c++ 实现
- VC编译iconv库
- No_16_0311 Java基础学习第十六天
- 获取手机唯一标识码并对其MD5加密
- Android自定义可控最大宽高的Layout
- C++对象初始化
- 4、文件上传_5、多文件上传_6、文件下载
- LOAD DATA FROM MASTER的说明
- CKEDitor支持WORD格式的缩进问题
- OS X 10.11 安装Cocoapods 出现问题的解决方法
- 菜鸟成长记-UIScrollView
- android 常见的补间动画
- 如何用caffe解决回归问题