本文在鸿洋的AutoLayout上做了修改,原文地址https://blog.csdn.net/lmj623565791/article/details/49990941。
AutoLayout原本的使用方法和思想没有发生变化,主要针对适配中出现的问题进行修改。如果你遇到了下边的一些问题,可以参考:
- 出现图像,View变形问题。
- 全面屏适配问题。
- 底部虚拟按键问题尤其是华为可升降虚拟按键问题。
- 自定义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);
只改变某个属性,也可以用如下代码修改,其中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。