效果图:
思路:
一、编写xml文件,声明自定义属性
二、继承RelativeLayout
三、根据自定义ViewGroup的思想咱们通常会在继承以后,建立构造器,而后重写onMeasure、onLayout和onDraw三个方法。这里对onLayout和onDraw方法都不须要进行特别的操做。由于百分比布局,是以该布局做为容器,子控件的宽度跟高度以百分比布局为参考设定。好比你的容器宽200px,子控件设置占容器宽度的0.5则子控件宽度为100px。因此主要是在onMeasure方法中编写代码。
为了支持margin、padding属性重写了generateLayoutParams()方法,并经过返回new LayoutParams(getContext(),attrs)对象解析到自定义的属性,最后在omMeasure方法中获取容器宽和高,遍历子控件,若是子控件的widthPercent或者heightPercent属性不为0就为该子控件的宽度或者高度从新赋值
四、使用自定义布局
代码:
一、声明自定义属性:java
<?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>
二、自定义百分比布局
(1)定义属性、解析属性 、返回给generateLayoutParams
(2)onMeasure中对子控件遍历、获取属性值、设置宽度或者高度android
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);
}
}
三、使用
注意:添加这行代码(AndroidStudio以下,若是是ecplise:xmlns:app="http://schemas.android.com/apk/res/包名+类名
):web
xmlns:app="http://schemas.android.com/apk/res-auto"
使用例子:bash
<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>