痛点:
Android阵容屏幕众多,尺寸、大小、DPI各种参数不一致,如何一键适配所有屏幕?以下提供一种解决方案。
以ConstraintLayout为例,继承约束布局下面来写一个自定义百分比布局。
在attrs文件中定义我们的属性:
<declare-styleable name="ConstraintPercentLayout">
<attr name="constraintWidthPercent" format="float" />
<attr name="constraintHeightPercent" format="float" />
<attr name="constraintMarginLeftPercent" format="float" />
<attr name="constraintMarginRightPercent" format="float" />
<attr name="constraintMarginTopPercent" format="float" />
<attr name="constraintMarginBottomPercent" format="float" />
</declare-styleable>
解析这些属性到类中:
public static class PercentLayoutParams extends ConstraintLayout.LayoutParams{
private float widthPercent;
private float heightPercent;
private float marginLeftPercent;
private float marginRightPercent;
private float marginTopPercent;
private float marginBottomPercent;
public PercentLayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray a = c.obtainStyledAttributes(attrs,R.styleable.ConstraintPercentLayout);
widthPercent = a.getFloat(R.styleable.ConstraintPercentLayout_constraintWidthPercent,0);
heightPercent = a.getFloat(R.styleable.ConstraintPercentLayout_constraintHeightPercent,0);
marginLeftPercent = a.getFloat(R.styleable.ConstraintPercentLayout_constraintMarginLeftPercent,0);
marginRightPercent = a.getFloat(R.styleable.ConstraintPercentLayout_constraintMarginRightPercent,0);
marginTopPercent = a.getFloat(R.styleable.ConstraintPercentLayout_constraintMarginTopPercent,0);
marginBottomPercent = a.getFloat(R.styleable.ConstraintPercentLayout_constraintMarginBottomPercent,0);
a.recycle();
}
}
在onMeasure方法中,通过解析出来的各个元素属性值来计算百分比布局的子元素实际值:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取父容器尺寸
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
ViewGroup.LayoutParams layoutParams = childView.getLayoutParams();
//检查如果是我们自定义的百分比布局,则执行计算
if (checkLayoutParams(layoutParams)){
//获取每个子控件参数的具体数值
PercentLayoutParams percentLayoutParams = (PercentLayoutParams) layoutParams;
float widthPercent = percentLayoutParams.widthPercent;
float heightPercent = percentLayoutParams.heightPercent;
float marginLeftPercent = percentLayoutParams.marginLeftPercent;
float marginRightPercent = percentLayoutParams.marginRightPercent;
float marginTopPercent = percentLayoutParams.marginTopPercent;
float marginBottomPercent = percentLayoutParams.marginBottomPercent;
//计算出百分比布局中控件的实际参数
if (widthPercent > 0){
Log.d(TAG, "onMeasure: widthSize = " + widthSize);
layoutParams.width = (int) (widthPercent * widthSize);
Log.d(TAG, "onMeasure: widthPercent = " + widthPercent + " widthSize = " + widthSize);
}
if (heightPercent > 0 ){
layoutParams.height = (int) (heightPercent * heightSize);
}
if (marginLeftPercent > 0){
((PercentLayoutParams)layoutParams).leftMargin = (int) (widthSize * marginLeftPercent);
}
if (marginRightPercent > 0){
((PercentLayoutParams) layoutParams).rightMargin = (int) (widthSize * marginRightPercent);
}
if (marginTopPercent > 0){
((PercentLayoutParams) layoutParams).topMargin = (int) (heightSize * marginTopPercent);
}
if (marginBottomPercent > 0){
((PercentLayoutParams) layoutParams).bottomMargin= (int) (heightSize * marginBottomPercent);
}
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof PercentLayoutParams;
}
上面判断每个子元素,假如是自定义百分比布局则计算并且保存到代码
ViewGroup.LayoutParams params = child.getLayoutParams();
中的params中去。
其中需要注意的是,需要重写generateLayoutParams方法,该方法的作用是生成LayoutParams,重写它来生成我们自定义的百分比LayoutParams:
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
// return super.generateLayoutParams(attrs);
return new PercentLayoutParams(getContext(),attrs);
}
好了,自定义百分比布局算是写完了。
我们测试效果,布局如下:
<?xml version="1.0" encoding="utf-8"?>
<com.netease.screenadapter.percentlayout.ConstraintPercentLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:text="50% 50%"
android:background="@android:color/holo_purple"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:constraintWidthPercent="0.5"
app:constraintHeightPercent="0.5"
app:constraintMarginLeftPercent="0.5"/>
</com.netease.screenadapter.percentlayout.ConstraintPercentLayout>
在以下尺寸的屏幕里面测试
其中800 x 1280效果为:
1920 x 1080效果为:
符合我们的逾期。
根据后期需求可在此项目里面灵活添加修改。