Android AutoLayout適配問題解決方案
本文在鴻洋的AutoLayout上做了修改,原文地址https://blog.csdn.net/lmj623565791/article/details/49990941。
AutoLayout原本的使用方法和思想沒有發生變化,主要針對適配中出現的問題進行修改。如果你遇到了下邊的一些問題,可以參考:
- 出現影象,View變形問題。
- 全面屏適配問題。
- 底部虛擬按鍵問題尤其是華為可升降虛擬按鍵問題。
- 自定義View與AutoLayout不適配
1,主要思路
先借一張圖:
我們拿到這幾圖的時候,是以某個解析度來設計的,與原AutoLayout一樣,都需要在Manifest中定義好設計圖大小。上邊這張圖的設計尺寸是720的寬度,假設新增乘客這個的圖片設計大小為30px30px,在1080p解析度的螢幕上實際應該顯示大小為30
實際顯示的尺寸 = 設計圖尺寸*螢幕寬度/設計圖寬度。
事實上這裡邊沒有設計圖高度的事。但我在改的時候仍然保留了高度的設定值。
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);
只改變某個屬性,也可以用如下程式碼修改,其中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。