Android屏幕适配---以指定宽高确认dp⬅➡px转换(头条方案)

超久没写过博客了,来一篇小干货。几行代码完成屏幕适配方案。

发现问题

开发过程中,UI一般是以1080P的分辨率给与标注图的,宽度1080px,也就是360dp。当我们按照标注开发时,发现交付UI时,总是出现这样或者那样的问题,比如icon大小总是不对一样。
比如横排两个图片宽高540px,我们布局很容易就标注两个ImageView 180dp,可是我发现部分手机显示效果异常。

发现无法铺满屏幕,一般来说我们都会采用代码中动态布局的方式,计算出屏幕的一半宽度,最后修改布局的宽高解决,但是这样太损耗性能,和不方便了。
在代码中计算一波180dp->495px,并不是我们认为的540px,在小米的手机的开发者选项中有个可以调整的最小宽度

我们将其调整为360dp,显示效果则是我们预期的占满整个屏幕宽度。

问题分析

先摆出几个公式:
dpi = √(宽度²+高度²) / 屏幕尺寸(如5寸)
density = dpi/160f
dp = px / density

目前市面手机dpi都不同,所以导致density的值也就不同,特别是部分手机如小米可以调整density的值,导致我们根据UI标注图计算的dp放到代码中显示效果各有不同。
所以我们的解决思路就是修改density的值,使其满足我们的dp/px/sp直接的转换计算。
因为现在1080P的手机分辨率也不同于1920*1080,所以我们需要以宽度或者高度的其中一方作为标准去修改转换比率,我们不再根据dpi计算出density,而是根据屏幕宽度倒推出density。
有人说可以根据宽度和高度分别修改不同的比例,问题是如果180dp的值在宽高的px则不同,所以只能取宽或者高为基准

代码实现

package com.monke.screenfitdemo;

import android.app.Activity;
import android.support.annotation.NonNull;
import android.util.DisplayMetrics;

public class ScreenFitManager {
    private static ScreenFitManager instance;

    private ScreenFitManager() {

    }

    public static ScreenFitManager getInstance() {
        if (instance == null) {
            synchronized (ScreenFitManager.class) {
                if (instance == null) {
                    instance = new ScreenFitManager();
                }
            }
        }
        return instance;
    }

    private float temp = 0;
    private Fit fit;
    private float whole;

    /**
     * application onCreate第一行调用
     */
    public void init(@NonNull Application application, Fit fit, float whole) {
        this.fit = fit;
        this.whole = whole;
        if (whole < 0) {
            throw new RuntimeException("whole数据必须大于0");
        } else {
            DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
            float defaultDensity = displayMetrics.density;
            float defaultScaledDensity = displayMetrics.scaledDensity;  //字体sp计算用
            temp = defaultScaledDensity / defaultDensity;

            float density;
            int dpi;
            float scaledDensity;
            if (fit == Fit.WIDTH) {
                density = displayMetrics.widthPixels / whole;
                dpi = (int) (density * 160f);
                scaledDensity = temp * density;  //重新计算出字体缩放比例
            } else {
                density = displayMetrics.heightPixels / whole;
                dpi = (int) (density * 160f);
                scaledDensity = temp * density;  //重新计算出字体缩放比例
            }
            displayMetrics.density = density;
            displayMetrics.densityDpi = dpi;
            displayMetrics.scaledDensity = scaledDensity;
        }
    }

    /**
     * activity onCreate中第一行调用
     */
    public void fitInit(@NonNull Activity activity) {
        DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
        float density;
        int dpi;
        float scaledDensity;
        if (fit == Fit.WIDTH) {
            density = displayMetrics.widthPixels / whole;
            dpi = (int) (density * 160f);
            scaledDensity = temp * density;  //重新计算出字体缩放比例
        } else {
            density = displayMetrics.heightPixels / whole;
            dpi = (int) (density * 160f);
            scaledDensity = temp * density;  //重新计算出字体缩放比例
        }
        displayMetrics.density = density;
        displayMetrics.densityDpi = dpi;
        displayMetrics.scaledDensity = scaledDensity;
    }

    public enum Fit {
        WIDTH,
        HEIGHT
    }
}

在Application中onCreate中添加
例如设计师给的是1080P的设计图

ScreenFitManager.getInstance().init(this, ScreenFitManager.Fit.WIDTH, 360f);

使用Activity中onCreate中添加即可

ScreenFitManager.getInstance().fitInit(this);;

满足我们的要求,并且字体缩放也做了适配,可以根据UI标注图肆无忌怛的填值了。
如果需要针对用户修改系统字体大小即时优化,请开发者自行添加监听器。
本方法基本没什么缺点,都是使用系统API,基本不用考虑后续android版本升级问题,且代码入侵性几乎为0。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值