1. 程式人生 > >Android AutoLayout適配問題解決方案

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