Android AutoLayout适配问题解决方案

本文在鸿洋的AutoLayout上做了修改,原文地址https://blog.csdn.net/lmj623565791/article/details/49990941。
AutoLayout原本的使用方法和思想没有发生变化,主要针对适配中出现的问题进行修改。如果你遇到了下边的一些问题,可以参考:

  1. 出现图像,View变形问题。
  2. 全面屏适配问题。
  3. 底部虚拟按键问题尤其是华为可升降虚拟按键问题。
  4. 自定义View与AutoLayout不适配

1,主要思路

先借一张图:
拿到的设计图我们拿到这几图的时候,是以某个分辨率来设计的,与原AutoLayout一样,都需要在Manifest中定义好设计图大小。上边这张图的设计尺寸是720的宽度,假设新增乘客这个的图片设计大小为30px30px,在1080p分辨率的屏幕上实际应该显示大小为30(1080/720) = 45px,因此1080p分辨率屏幕上该图显示大小为45*45px。同样计算得到margin,padding,textsize等属性。

实际显示的尺寸 = 设计图尺寸*屏幕宽度/设计图宽度。

事实上这里边没有设计图高度的事。但我在改的时候仍然保留了高度的设定值。

2,核心代码

public class AutoLayoutConifg {

    private static AutoLayoutConifg sIntance = new AutoLayoutConifg();


    private static final String KEY_DESIGN_WIDTH = "design_width";
    private static final String KEY_DESIGN_HEIGHT = "design_height";

    private int mScreenWidth;
    private int mScreenHeight;

    private int mDesignWidth;
    private int mDesignHeight;


    private AutoLayoutConifg() {
    }

    public void checkParams() {
        if (mDesignHeight <= 0 || mDesignWidth <= 0) {
            throw new RuntimeException(
                    "you must set " + KEY_DESIGN_WIDTH + " and " + KEY_DESIGN_HEIGHT + "  in your manifest file.");
        }
    }

    public static AutoLayoutConifg getInstance() {
        return sIntance;
    }


    public int getScreenWidth() {
        return mScreenWidth;
    }

    public int getScreenHeight() {
        return mScreenHeight;
    }

    public int getDesignWidth() {
        return mDesignWidth;
    }

    public int getDesignHeight() {
        return mDesignHeight;
    }


    public void init(Context context) {
    //这里读取了屏幕的宽高,然后根据屏幕的宽高和设计图的宽度,计算设计图对应的高度
        mScreenWidth = DisplayUtil.getDisplay(context).widthPixels;
        mScreenHeight = DisplayUtil.getDisplay(context).heightPixels;
        mDesignWidth = DisplayUtil.getMetaDataWid(context);
        mDesignHeight = mDesignWidth * mScreenHeight / mScreenWidth;
    }

}

mDesignHeight = mDesignWidth * mScreenHeight / mScreenWidth;

这句话实际是:拿到实际屏幕使用的设计图高度。比如我屏幕是19201080,设计图是720的宽度,那么我得到的设计图尺寸是1280720。同理21601080得到1440720,1600:1200的屏幕得到960*720。这是解决屏幕中View变形、底部虚拟按键和全面屏适配的关键。

3,具体使用

xml中的使用与原来没有任何变化,根布局使用Autolayout,布局中所有涉及到尺寸的地方,都用px代替,包括字体大小(字体大小需要特别注意textview的上下边距问题,一般字体大小需要设置成比设计图大10%)。需要注意的点和原来是一样的,例如根布局的尺寸不生效等。代码中new的View,用AutoUtil的auto方法调用一遍即可。代码中更改View的某个属性,可用DisplayUtils的getgetRateHei和getRateWid方法乘以设计图尺寸。

例如我现在设计图尺寸1080px宽度,就可用下边方法添加一个居中显示的View。viewGroup的宽高是屏幕宽度,或者都设置成1080px。

        //设置居中的一个TextView
        AutoLinearLayout viewGroup = findViewById(R.id.linearlayout);
        TextView textView = new TextView(this);
        textView.setText("我是从代码中添加的View");
        textView.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_dark));
        AutoLinearLayout.LayoutParams params = new AutoLinearLayout.LayoutParams(540, 540);
        params.leftMargin = 270;
        params.bottomMargin = 270;
        params.topMargin = 270;
        textView.setLayoutParams(params);
        AutoUtils.auto(textView);
        viewGroup.addView(textView);

代码添加的居中View只改变某个属性,也可以用如下代码修改,其中600是设计图尺寸:

        //更改View的属性
        TextView change_attr = findViewById(R.id.change_attr);
        //此处需要注意,原本是谁的layoutparams就用谁的,如果用了ViewGroup的可能会出现属性丢失
        AutoLinearLayout.LayoutParams layoutParams = new AutoLinearLayout.LayoutParams(
                (AutoLinearLayout.LayoutParams) change_attr.getLayoutParams());
        //可不用DisplayUtil用AutoUtils
        layoutParams.width = (int) (600 * DisplayUtil.getRateWid());
        change_attr.setLayoutParams(layoutParams);

4,自定义View

  • 自定义ViewGroup
    自定义ViewGroup在原本项目中已经有示例,而且也很简单:
public class AutoCardView extends CardView {
    private final AutoLayoutHelper mHelper = new AutoLayoutHelper(this);

    public AutoCardView(Context context) {
        super(context);
    }

    public AutoCardView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AutoCardView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public AutoFrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new AutoFrameLayout.LayoutParams(getContext(), attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (!isInEditMode()) {
            mHelper.adjustChildren();
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}
  • 自定义View
//MyLineTextView 带底部线条的TextView
public class MyLineTextView extends View {

    private int lineColor;
    private int textColor;
    private float lineSize;
    private float inTextSize;
    private String text;

    private Paint paint;
    private int width;
    private int height;

    public MyLineTextView(Context context) {
        this(context, null);
    }

    public MyLineTextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyLineTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context, attrs);
    }

    private void initView(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs,
                R.styleable.MyLineTextView);
        if (ta != null) {
            lineColor = ta.getColor(R.styleable.MyLineTextView_lineColor, 0);
            textColor = ta.getColor(R.styleable.MyLineTextView_inTextColor, 0);
            inTextSize = ta.getDimension(R.styleable.MyLineTextView_inTextSize, 50);
            text = ta.getString(R.styleable.MyLineTextView_text);
            lineSize = ta.getDimension(R.styleable.MyLineTextView_lineSize, 50);
            ta.recycle();
        }
        paint = new Paint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = (int) (MeasureSpec.getSize(widthMeasureSpec));
        height = (int) (MeasureSpec.getSize(heightMeasureSpec)*DisplayUtil.getRateHei());
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(lineColor);
        paint.setStrokeWidth(DisplayUtil.getRateWid() * lineSize);
        canvas.drawLine(0, height-(DisplayUtil.getRateWid() * lineSize)/2, width, height-(DisplayUtil.getRateWid() * lineSize)/2, paint);
        
        paint.setTextSize(DisplayUtil.getRateWid() * inTextSize);
        paint.setColor(textColor);
        Paint.FontMetricsInt centerfontMetricsInt = paint.getFontMetricsInt();
        canvas.drawText(text, 0, height-(DisplayUtil.getRateHei() * lineSize)-centerfontMetricsInt.descent, paint);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }
}

自定义View的属性

<resources>
    <declare-styleable name="MyLineTextView">
        <attr name="inTextSize" format="dimension"/>
        <attr name="text" format="string" />
        <attr name="lineColor" format="color" />
        <attr name="inTextColor" format="color" />
        <attr name="lineSize" format="dimension" />
    </declare-styleable>
</resources>

xml中使用

 <com.kukugtu.autolayoutdemo.MyLineTextView
                android:id="@+id/bottomView"
                android:layout_width="800px"
                android:layout_height="300px"
                android:layout_marginTop="200px"
                app:inTextColor="#ff0000"
                app:inTextSize="200px"
                app:lineColor="#00ff00"
                app:lineSize="50px"
                app:text="自定义View"/>

自定义View里边的操作其实和修改View的某个属性操作类似,涉及到操作尺寸的,需要用DisplayUtils的比例乘以需要设定的尺寸,xml中写的大小用px。

5,总结

总体思路是将根据屏幕尺寸,调整设计图到适合自己屏幕的比例,然后根据这个比例进行大小计算。之前的变形和不适配问题,应是出现在设计图尺寸和显示尺寸不同。导致这个的原因有多方面,包括虚拟按键,通知栏,全面屏等等。

本文地址:https://blog.csdn.net/qq_39154578/article/details/83862602
GitHub:https://github.com/hongyangAndroid/AndroidAutoLayout
原创作品,转载请注明 Author:Kukugtu

猜你喜欢

转载自blog.csdn.net/qq_39154578/article/details/83862602
今日推荐