随着Android系统版本的不断迭代升级,支持的设备也越来越多,从最初的手机,到现在覆盖watch,TV等,应用越来越广泛,但是暴露出的碎片化问题也愈发突出,设备适配也变成了一个复杂的任务,基于以上问题,编写具有百分比的自定义布局适配各中不同设备显得十分必要。
- 自定义布局首先是自定义属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="PercentRelativelayout">
<attr name="layout_widthPercent" format="float"></attr>
<attr name="layout_heightPercent" format="float"></attr>
</declare-styleable>
</resources>
- 其次是继承Relativelayout布局,并重写里面对应的方法:
public class PercentRelativelayout extends RelativeLayout {
public PercentRelativelayout(Context context) {
super(context);
}
public PercentRelativelayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PercentRelativelayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = View.MeasureSpec.getSize(widthMeasureSpec);
int height = View.MeasureSpec.getSize(heightMeasureSpec);
//测量子控件的高度进行改变
int childCount = this.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);//每一个子控件
ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
//解析自定义进行替换
float widthPercent = 0;
float heightPercent = 0;
if (layoutParams instanceof PercentRelativelayout.LayoutParams) {
widthPercent = ((LayoutParams) layoutParams).getWidthPercent();
heightPercent = ((LayoutParams) layoutParams).getHeightPercent();
}
if (widthPercent != 0) {
layoutParams.width = (int) (width * widthPercent);
}
if (heightPercent != 0) {
layoutParams.height = (int) (height * heightPercent);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
}
@Override
public 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 void setWidthPercent(float widthPercent) {
this.widthPercent = widthPercent;
}
public float getHeightPercent() {
return heightPercent;
}
public void setHeightPercent(float heightPercent) {
this.heightPercent = heightPercent;
}
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray typedArray = c.obtainStyledAttributes(attrs, R.styleable.PercentRelativelayout);
widthPercent = typedArray.getFloat(R.styleable.PercentRelativelayout_layout_widthPercent, widthPercent);
heightPercent = typedArray.getFloat(R.styleable.PercentRelativelayout_layout_heightPercent, heightPercent);
typedArray.recycle();
}
public LayoutParams(int w, int h) {
super(w, h);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public LayoutParams(RelativeLayout.LayoutParams source) {
super(source);
}
}
}
在该类中重写了onMeasure,generateLayoutParams方法,其中LayoutParams 继承自RelativeLayout.LayoutParams,将百分比布局的属性widthPercent,heightPercent初始化,并封装。
在generateLayoutParams方法中回调LayoutParams 方法,在onMeasure方法中获取并测量子布局大小,若自定义属性widthPercent ,heightPercent 为非空时,设置子布局大小。
- 布局引用:
<?xml version="1.0" encoding="utf-8"?>
<com.terry.app.zhdemo.view.PercentRelativelayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<TextView
android:id="@+id/tv_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_red_dark"
app:layout_widthPercent="0.5"
app:layout_heightPercent="0.8"
android:text="列表内容"
android:textSize="24sp" />
</com.terry.app.zhdemo.view.PercentRelativelayout>
需要自定义命名空间xmlns:app="http://schemas.android.com/apk/res-auto", 设置app:layout_widthPercent="0.5" app:layout_heightPercent="0.8",显示效果如下: