由于不管dp、sp、pt,最终显示在屏幕上的时候,都是px,那么我们在做设计图的时候,可以以px为基准来设计,然后在显示的时候,获取屏幕的分辨率,计算出比例,缩放坐标。最终达到屏幕适配
首先需要设置一个基准值,这个基准值的单位是px
public static final float STANDARD_WIDTH = 1080f;
public static final float STANDARD_HEIGHT = 1920f;
然后我们可以通过windowManager.getDefaultDisplay().getMetrics(displayMetrics);获取到屏幕的分辨率
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
//windowManager.getDefaultDisplay().getRealMetrics(displayMetrics);
if (displayMetrics.widthPixels > displayMetrics.heightPixels) {
//横屏
this.displayMetricsWidth = displayMetrics.heightPixels;
this.displayMetricsHeight = displayMetrics.widthPixels;
} else {
//竖屏
this.displayMetricsWidth = displayMetrics.widthPixels;
this.displayMetricsHeight = displayMetrics.heightPixels;
}
上面的getMetrics是获取当前窗口的分辨率,不包括虚拟按键。getRealMetrics是获取完整的分辨率。
然后就可以计算缩放比例了
public float getHorizontalScaleValue() {
return displayMetricsWidth / STANDARD_WIDTH;
}
public float getVerticalScaleValue() {
return displayMetricsHeight / STANDARD_HEIGHT;
}
public int getWidth(int width) {
return Math.round((float) width * this.displayMetricsWidth / STANDARD_WIDTH);
}
public int getHeight(int height) {
return Math.round((float) height * this.displayMetricsHeight / STANDARD_HEIGHT);
}
缩放系数得到了,然后就是对布局进行缩放了
这里有两个做法,第一个,自定义容器,第二个,直接修改子View大小和位置
测试机
机器 | 尺寸(英寸) | widthPixels | heightPixels | 对角线 | 计算出的densityDpi | densityDpi | density |
---|---|---|---|---|---|---|---|
机器A | 10.5 | 1920 | 1200 | 2264 | 215.6 | 240 | 1.5 |
机器D | 6 | 2160 | 1080 | 2415 | 402.5 | 420 | 2.625 |
自定义容器
在容器类测量(Measure)的时候,直接修改对子View遍历
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (flag) {
flag = false;
float scaleX = UIUtils.getInstance(getContext()).getHorizontalScaleValue();
float scaleY = UIUtils.getInstance().getVerticalScaleValue();
int childCount = this.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
layoutParams.width = (int) (layoutParams.width * scaleX);
layoutParams.height = (int) (layoutParams.height * scaleY);
layoutParams.leftMargin = (int) (layoutParams.leftMargin * scaleX);
layoutParams.rightMargin = (int) (layoutParams.rightMargin * scaleX);
layoutParams.topMargin = (int) (layoutParams.topMargin * scaleY);
layoutParams.bottomMargin = (int) (layoutParams.bottomMargin * scaleY);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
我们在布局中测试一下
假设ui给的图的基准是1280*800 px
TextView要求占据屏幕的1/4,那么就是320*200
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<com.example.screenfit.custom.UIRelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:text="容器内自适应200*320px"
android:layout_width="200px"
android:layout_height="320px"
android:background="#50f0" />
</com.example.screenfit.custom.UIRelativeLayout>
<TextView
android:text="200*320px"
android:layout_width="200px"
android:layout_height="320px"
android:background="#5f0f" />
<TextView
android:text="200*320dp"
android:layout_width="200dp"
android:layout_height="320dp"
android:background="#5ff0" />
</LinearLayout>
注意,容器内子View的大小的单位是px,如果是dp,就会先转成px再缩放,那样大小就不对了
看下结果
2222222.png
修改子View大小
接下来看看修改子View大小
因为是直接获取到子View并修改大小,我们要知道父布局是什么并且去获取响应的LayoutParams,我们的父布局是LinearLayout,那么我们就要相应的去获取LinearLayout.LayoutParams,修改大小后,再把LayoutParams设置回去
public static void setViewLinearLayoutParam(View view, int width, int height, int topMargin, int bottomMargin, int lefMargin,
int rightMargin, boolean asWidth) {
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) view.getLayoutParams();
if (width != RelativeLayout.LayoutParams.MATCH_PARENT && width != RelativeLayout.LayoutParams.WRAP_CONTENT && width != RelativeLayout.LayoutParams.FILL_PARENT) {
layoutParams.width = UIUtils.getInstance().getWidth(width);
} else {
layoutParams.width = width;
}
if (height != RelativeLayout.LayoutParams.MATCH_PARENT && height != RelativeLayout.LayoutParams.WRAP_CONTENT && height != RelativeLayout.LayoutParams.FILL_PARENT) {
layoutParams.height = asWidth ? UIUtils.getInstance().getWidth(height) : UIUtils.getInstance().getHeight(height);
} else {
layoutParams.height = height;
}
layoutParams.topMargin = asWidth ? UIUtils.getInstance().getWidth(topMargin) : UIUtils.getInstance().getHeight(topMargin);
layoutParams.bottomMargin = asWidth ? UIUtils.getInstance().getWidth(bottomMargin) : UIUtils.getInstance().getHeight(bottomMargin);
layoutParams.leftMargin = UIUtils.getInstance().getWidth(lefMargin);
layoutParams.rightMargin = UIUtils.getInstance().getWidth(rightMargin);
view.setLayoutParams(layoutParams);
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<!--<com.example.screenfit.custom.UIRelativeLayout-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content">-->
<!--<TextView-->
<!--android:text="容器内自适应200*320px"-->
<!--android:layout_width="200px"-->
<!--android:layout_height="320px"-->
<!--android:background="#50f0" />-->
<!--</com.example.screenfit.custom.UIRelativeLayout>-->
<TextView
android:id="@+id/text"
android:text="容器内自适应200*320px"
android:layout_width="200px"
android:layout_height="320px"
android:background="#50f0" />
<TextView
android:text="200*320px"
android:layout_width="200px"
android:layout_height="320px"
android:background="#5f0f" />
<TextView
android:text="200*320dp"
android:layout_width="200dp"
android:layout_height="320dp"
android:background="#5ff0" />
</LinearLayout>
然后在activity中重新设置大小
TextView text = findViewById(R.id.text);
UIUtils.getInstance(this);
ViewCalculateUtil.setViewLinearLayoutParam(text, 200, 320, 0, 0, 0, 0, true);
看下效果图
device-2019-09-20-103839_spec.png
看到和方法一一样的效果
网友评论