赞
踩
在 Android 开发中,不同设备的屏幕尺寸和分辨率千差万别,导致同一个界面在不同设备上的显示效果可能大相径庭。因此,为了在各种设备上都能呈现出优秀的 UI,开发者需要进行 UI 自适应的设计。
ScreenAdapterLayout 是一个自定义的继承自 RelativeLayout 的布局,它可以帮助开发者快速在不同尺寸的设备上实现 UI 自适应。使用 ScreenAdapterLayout 的过程也十分简单,只需将原来页面的根布局替换成 ScreenAdapterLayout 即可,ScreenAdapterLayout代码如下:
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.View;
- import android.widget.RelativeLayout;
-
- /**
- * 自定义布局,实现屏幕适配,将页面根布局换成 ScreenAdapterLayout
- * <p>
- * ScreenAdapterLayout 会在 onMeasure() 中计算子控件缩放后的尺寸和位置
- */
- public class ScreenAdapterLayout extends RelativeLayout {
-
- //flag 用于避免重复计算
- private boolean flag;
-
- public ScreenAdapterLayout(Context context) {
- super(context);
- }
-
- public ScreenAdapterLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public ScreenAdapterLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- //只有第一次 onMeasure 时才进行计算
- if (!flag) {
- //获取缩放比例
- float scaleX = Utils.getInstance(getContext()).getHorizontalScale();
- float scaleY = Utils.getInstance(getContext()).getVerticalScale();
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- LayoutParams params = (LayoutParams) child.getLayoutParams();
- //根据缩放比例计算子控件的尺寸和位置
- params.width = (int) (params.width * scaleX);
- params.height = (int) (params.height * scaleY);
- params.leftMargin = (int) (params.leftMargin * scaleX);
- params.rightMargin = (int) (params.rightMargin * scaleX);
- params.topMargin = (int) (params.topMargin * scaleY);
- params.bottomMargin = (int) (params.bottomMargin * scaleY);
- }
- //标记已经计算过
- flag = true;
- }
- //调用父类 onMeasure()
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- }
- }
在 ScreenAdapterLayout 中,onMeasure() 方法被重写。在这个方法中,首先获取了屏幕的宽高和缩放比例。然后遍历布局中所有子 View,根据缩放比例对它们进行缩放。最后将 flag 设置为 true,避免重复缩放。
使用方法非常简单,只需将你原来的布局类改为 ScreenAdapterLayout 即可,如下所示:
- <?xml version="1.0" encoding="utf-8"?>
- <com.study.pixel.ScreenAdapterLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:layout_width="540px"
- android:layout_height="540px"
- android:layout_marginLeft="10px"
- android:text="Hello World!"
- android:background="@color/colorAccent"/>
-
- </com.study.pixel.ScreenAdapterLayout>
工具类Utils代码如下:
- import android.content.Context;
- import android.util.DisplayMetrics;
- import android.view.WindowManager;
-
- public class Utils {
-
- private static Utils utils;
-
- //这里是设计稿参考宽高
- private static final float STANDARD_WIDTH = 1080;
- private static final float STANDARD_HEIGHT = 1920;
-
- //这里是屏幕显示宽高
- private int mDisplayWidth;
- private int mDisplayHeight;
-
- private Utils(Context context){
- //获取屏幕的宽高
- if(mDisplayWidth == 0 || mDisplayHeight == 0){
- WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- if (manager != null){
- DisplayMetrics displayMetrics = new DisplayMetrics();
- manager.getDefaultDisplay().getMetrics(displayMetrics);
- if (displayMetrics.widthPixels > displayMetrics.heightPixels){
- //横屏
- mDisplayWidth = displayMetrics.heightPixels;
- mDisplayHeight = displayMetrics.widthPixels;
- }else{
- mDisplayWidth = displayMetrics.widthPixels;
- mDisplayHeight = displayMetrics.heightPixels - getStatusBarHeight(context);
- }
- }
- }
-
- }
-
- public int getStatusBarHeight(Context context){
- int resID = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
- if (resID > 0){
- return context.getResources().getDimensionPixelSize(resID);
- }
- return 0;
- }
-
- public static Utils getInstance(Context context){
- if (utils == null){
- utils = new Utils(context.getApplicationContext());
- }
- return utils;
- }
-
- //获取水平方向的缩放比例
- public float getHorizontalScale(){
- return mDisplayWidth / STANDARD_WIDTH;
- }
-
- //获取垂直方向的缩放比例
- public float getVerticalScale(){
- return mDisplayHeight / STANDARD_HEIGHT;
- }
-
- }
这是工具类 Utils,用于计算设备屏幕尺寸与设计稿尺寸的比例。
首先,在类中定义了两个常量:STANDARD_WIDTH 和 STANDARD_HEIGHT,表示设计稿的宽度和高度,即 UI 设计师设计时所参考的标准尺寸。
其次,该类的构造函数 Utils(Context context) 中获取了屏幕的宽高,并将其存储在成员变量 mDisplayWidth 和 mDisplayHeight 中。如果 mDisplayWidth 和 mDisplayHeight 已经被赋值,就不会再次获取屏幕宽高。该构造函数还调用了 getStatusBarHeight(Context context) 方法,用于获取状态栏的高度。
getStatusBarHeight(Context context) 方法通过获取系统资源的方式,获得了状态栏的高度,并返回这个值。在计算高度的缩放比例时,要减去状态栏的高度,避免状态栏影响缩放比例。
getInstance(Context context) 方法是单例模式的实现,它用于获取 Utils 类的实例。如果 utils 为 null,就创建一个 Utils 对象并返回。否则,直接返回 utils。
最后,getHorizontalScale() 和 getVerticalScale() 方法用于计算水平方向和垂直方向的缩放比例。它们分别将屏幕的宽高与设计稿的宽高相除,得到一个缩放比例。这些方法可以帮助开发者在不同尺寸的设备上实现 UI 的自适应。
如果设计稿的屏幕宽度为1080,设置一个宽度为540的TextView,android:layout_width="540px",将ScreenAdapterLayout设置成根布局,那么不管在任何屏幕尺寸的设备上,TextView的宽度都会显示成屏幕宽度的一半。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。