实现 Android UI 自适应的最佳实践

        在 Android 开发中,不同设备的屏幕尺寸和分辨率千差万别,导致同一个界面在不同设备上的显示效果可能大相径庭。因此,为了在各种设备上都能呈现出优秀的 UI,开发者需要进行 UI 自适应的设计。

一、ScreenAdapterLayout

        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工具类

工具类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的宽度都会显示成屏幕宽度的一半。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值