Android自定义百分比布局,一劳永逸的多机型尺寸适配方案

痛点:

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效果为:

符合我们的逾期。

根据后期需求可在此项目里面灵活添加修改。

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林树杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值