效果图:
思路:
1、编写xml文件,声明自定义属性
2、继承RelativeLayout
3、根据自定义ViewGroup的思想我们一般会在继承之后,创建构造器,然后重写onMeasure、onLayout和onDraw三个方法。这里对onLayout和onDraw方法都不需要进行特别的操作。因为百分比布局,是以该布局作为容器,子控件的宽度跟高度以百分比布局为参考设定。比如你的容器宽200px,子控件设置占容器宽度的0.5则子控件宽度为100px。所以主要是在onMeasure方法中编写代码。
为了支持margin、padding属性重写了generateLayoutParams()方法,并通过返回new LayoutParams(getContext(),attrs)对象解析到自定义的属性,最后在omMeasure方法中获取容器宽和高,遍历子控件,如果子控件的widthPercent或者heightPercent属性不为0就为该子控件的宽度或者高度重新赋值
4、使用自定义布局
代码:
1、声明自定义属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="percentLayout">
<attr name="widthPercent" format="float"></attr>
<attr name="heightPercent" format="float"></attr>
</declare-styleable>
</resources>
2、自定义百分比布局
(1)定义属性、解析属性 、返回给generateLayoutParams
(2)onMeasure中对子控件遍历、获取属性值、设置宽度或者高度
public class PercentLayout extends RelativeLayout {
public PercentLayout(Context context) {
super(context);
}
public PercentLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
//测量容器宽高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = View.MeasureSpec.getSize(widthMeasureSpec);
int height=View.MeasureSpec.getSize(heightMeasureSpec);
//测量出子控件的宽高
int childcount=getChildCount();
for (int i=0;i<childcount;i++){
View child=this.getChildAt(i);
LayoutParams params= (LayoutParams) child.getLayoutParams();
//默认不设置是为0
float widthPercent=0;
float heightPercent=0;
if(params instanceof PercentLayout.LayoutParams){
widthPercent=((LayoutParams) params).getWidthPercent();
heightPercent=((LayoutParams) params).getHeightPercent();
if(widthPercent!=0){
//不为0时重新设置宽度
params.width= (int) (width*widthPercent);
}
if(heightPercent!=0){
params.height= (int) (height*heightPercent);
}
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public RelativeLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(),attrs);
}
public static class LayoutParams extends RelativeLayout.LayoutParams{
//定义属性
private float widthPercent;
private float heightPercent;
public float getWidthPercent() {
return widthPercent;
}
public float getHeightPercent() {
return heightPercent;
}
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
//解析自己定义的属性
TypedArray array=context.obtainStyledAttributes(attrs,R.styleable.percentLayout);
widthPercent=array.getFloat(R.styleable.percentLayout_widthPercent,widthPercent);
heightPercent=array.getFloat(R.styleable.percentLayout_heightPercent,getHeightPercent());
array.recycle();
}
public LayoutParams(int w, int h) {
super(w, h);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
}
//用于对子控件进行布局
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
}
}
3、使用
注意:添加这行代码(AndroidStudio如下,如果是ecplise:xmlns:app="http://schemas.android.com/apk/res/包名+类名
):
xmlns:app="http://schemas.android.com/apk/res-auto"
使用例子:
<com.df.percentlayout.androidpercentlayout.PercentLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:widthPercent="0.8"
app:heightPercent="0.8"
android:layout_centerInParent="true"
android:background="#00ff00"
android:text="Hello World!" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:widthPercent="0.5"
app:heightPercent="0.3"
android:layout_centerInParent="true"
android:background="#ff0000"
android:text="Hello World!" />
</com.df.percentlayout.androidpercentlayout.PercentLayout>