自适应容器需要用到自定义属性,先简单了解自定义属性
TextView View Button 都有一些属性,例如 android:layout_width,这些都是系统定义的属性,可以直接用,当然这些属性在有些时候不能满足我们的需求,最常见的是在自定义控件的时候,网上的开源框架很多都有自定义控件,使用到自定义属性,这些自定义属性可以改变控件的样式等,方便使用者修改,
先看下系统的定义的属性,这些属性都是在别人的博客看到的
<declare-styleable name="View">
<attr name="id" format="reference" />
<attr name="background" format="reference|color" />
<attr name="padding" format="dimension" />
...
<attr name="focusable" format="boolean" />
...
</declare-styleable>
<declare-styleable name="TextView">
<attr name="text" format="string" localization="suggested" />
<attr name="hint" format="string" />
<attr name="textColor" />
<attr name="textColorHighlight" />
<attr name="textColorHint" />
...
</declare-styleable>
<declare-styleable name="ViewGroup_Layout">
<attr name="layout_width" format="dimension">
<enum name="fill_parent" value="-1" />
<enum name="match_parent" value="-1" />
<enum name="wrap_content" value="-2" />
</attr>
<attr name="layout_height" format="dimension">
<enum name="fill_parent" value="-1" />
<enum name="match_parent" value="-1" />
<enum name="wrap_content" value="-2" />
</attr>
</declare-styleable>
<declare-styleable name="LinearLayout_Layout">
<attr name="layout_width" />
<attr name="layout_height" />
<attr name="layout_weight" format="float" />
<attr name="layout_gravity" />
</declare-styleable>
<declare-styleable name="RelativeLayout_Layout">
<attr name="layout_centerInParent" format="boolean" />
<attr name="layout_centerHorizontal" format="boolean" />
<attr name="layout_centerVertical" format="boolean" />
...
</declare-styleable>
可以看到一些控件都有自己的属性,TextView是继承自view同时也有View的属性,name是属性的名字,format表示该属性能接受到值的类型
类型有很多种就不说了,在写自定属性的时候自动会提示的
接下来开始写自定义属性了
首先在res->values创建一个存放自定义属性的xml(attrs.xml),下面是要用到的属性
<resources> <declare-styleable name="self_adaption"> <attr name="proportion" format="float"/> </declare-styleable> </resources>
自定义控件
** * 自适应的容器 */ public class HomeAdvertThreeImage extends FrameLayout { //宽高比例 private float mPicRatio;// = 2.02f; public HomeAdvertThreeImage(Context context, AttributeSet attrs) { super(context, attrs); //读取自定义的属性 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.self_adaption); mPicRatio = array.getFloat(R.styleable.self_adaption_proportion, 0.0f); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //得到模式,根据宽度动态计算高度 int widthMode = MeasureSpec.getMode(widthMeasureSpec); //得到模式,根据高度动态计算宽度 int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (widthMode == MeasureSpec.EXACTLY) { //得到自身的宽度 int selfWidth = MeasureSpec.getSize(widthMeasureSpec); //根据比例值获取高度 int selfHeight = (int) (selfWidth / mPicRatio + .5f); //保存测量结果 setMeasuredDimension(selfWidth, selfHeight); //孩子的宽和高 int childWidth = selfWidth - getPaddingLeft() - getPaddingRight(); int childHeight = selfHeight - getPaddingBottom() - getPaddingTop(); //孩子确切的宽和高 int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY); int childHeightMeauseSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY); //测量孩子 measureChildren(childWidthMeasureSpec, childHeightMeauseSpec); } else if (heightMode == MeasureSpec.EXACTLY){ //得到自身的高度 int selfHeight = MeasureSpec.getSize(heightMeasureSpec); //根据比例值获取高度 int selfWidth = (int) (selfHeight / mPicRatio + .5f); //保存测量结果 setMeasuredDimension(selfWidth, selfHeight); //孩子的宽和高 int childWidth = selfWidth - getPaddingLeft() - getPaddingRight(); int childHeight = selfHeight - getPaddingBottom() - getPaddingTop(); //孩子确切的宽和高 int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY); int childHeightMeauseSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY); //测量孩子 measureChildren(childWidthMeasureSpec, childHeightMeauseSpec); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } }
使用自定义控件
<com.cad.view.HomeAdvertThreeImage app:proportion="2.02" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v4.view.ViewPager android:id="@id/viewpager" android:layout_width="match_parent" android:layout_height="wrap_content"/> <LinearLayout android:layout_gravity="bottom" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="30dp" android:layout_alignParentBottom="true" android:gravity="center" android:orientation="horizontal"> </LinearLayout> </com.cad.view.HomeAdvertThreeImage>
其中app:proprotion="2.02"就是上面定义的属性,接受的值是float类型
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.self_adaption); mPicRatio = array.getFloat(R.styleable.self_adaption_proportion, 0.0f);这两行代码就是读取到xml中使用的自定义属性的值,然后赋值给宽高比例,这样这个最重要的比例值就可以在xml定义了,相当于对外暴露了方法可写可不写,不写的话必须要有默认值,这样就完成了自适应容器了(注释全网最清晰),有那里不对的可以回复我,我再修改修改
我自己写的做记录,方便以后用到直接复制就ok了
在来个自定义属性的介绍详细的链接