「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」

设计师应该按照哪个比例出图

  • 设计师出图总是有对标的设备的,比如按照iphone6s或者按照webview渲染有什么用iphone13mini,这些设备的宽高和尺寸是固定的,因此dpi也是固定的。
  • 举个例子,公司按照iphone13mini的标准出图,WebView宽高是375 * 812 ,屏幕尺寸是5.42英寸
//一倍图导出
ppi = 根号(375*375+812*812) / 5.42 = 164
//按照三倍导出则是宽高分别为 1125*2436
ppi = 495 

再对比不同的d像素原神rawable目录所需要测试的资源文件,我们可以android的drawable类很方便得知,按照三倍导出的图需要放入到xxh像素地牢dpi的目录下。而按照一倍图导出的放入到mdpi下。

多分辨率适配的思考

  • 目前设计师一般都是用figma出图,选择按标准dpi,也就是160dpi出图,在导出2倍图,3倍图时,刚好可以放到对应的xhpid像素生存者2,xxhdpi目录下,也算是一种取巧。

资源是怎么被使用的?

资源查找规则

android系统会根据设备本身的dpi来寻找最合适的图片加载,比如设备本身是xhdpi,则它的查找资源顺序为

xhdpi-xxhdpi-xxxhdpi-nodpi-hdpi-mdpi-ldpi

资源没命中会如何?

  • android下载安装xhdpi的设备从xxhdpi找到某张图时,它认为图的密度高于了设备本身的密度,因此会对图片进行缩小。
  • 同理如果高密度的设备从低app小胖子密度的文件夹找到图片时,图测试纸怀孕图片片会被放大
  • 图片缩放测试你适合学心理学吗的比例为 destinateandroid是什么手机牌子Dpi/deWebViewviceDpi

分辨率该如何适配?

分辨率适配的根本目的

  • application辨率适配的根本目的是为了让不同的设备对同样一张图“看起来感官”一样。也就是如果是固定宽度的app,要求不同的按钮,图片在不同设备上看起来占比是一样的。

  • 如下图所示,按钮A与页面的比例都是50%。由于导出的图片的尺寸是一致的,比如说都是50×50,因此需要对图片做放大才能达到目的。右边的图片我们需要放大到75×75.

多分辨率适配的思考

如何适配

为了使得图片看起来一致,我们需要按照比例去放大图片,问题转化为如何计算图片放大的比例。

假定设备的宽高为wScreen,hScreen,设计稿宽高为wDesign,hDeWebViewsign

宽高比缩放

最简单纯粹的方案为:

scaleFactorW =  wScreen/wDesign
scaleFactorH =  hScreen/hDesign

由于设备的比例多种多样,比如16:9 , 2:1 , 4:3,如果按照这样计算,scaleFactorW和android下载安装scaleFactorH的大测试抑郁症小不一样像素射击,图片会被拉伸。

为了解决拉伸问题,我们针对不同的业务类型,选择固定某个值作为参考,也就是固定宽缩放或者固定高缩放。

比如在一些新闻资讯类app,高度是不敏感的,宽webview实现度很敏感,就可以选择固定宽缩放。因此可以得到

scaleFactor = wScreen/wDesign

直接设置宽高可以吗?

既然我们得到最终的适配像素射击下载是让宽高缩放一个固定的比例,那我们可以直接写测试纸怀孕图片死一个值吗?

显然是不行的。我们在xml去写某个ImageView大小的时候,很多像素原神时候都写了一个固定的数字,比如30dp,3android什么意思0px,对于不同的设备,我们缩放完后算出的大小是不一样的。

怎么办呢。要解决这个问题,我们要看下系统对于dp的解析逻辑。

dp的解Android析逻辑

这个dp的解析逻辑,网上有很app小胖子多的分析代码,最终都指向一出,即TypedValue.applyDimension

public static float applyDimension(int unit, float value,
                                       DisplayMetrics metrics)
{
    switch (unit) {
    case COMPLEX_UNIT_PX:
        return value;
    case COMPLEX_UNIT_DIP:
        return value * metrics.density;
    case COMPLEX_UNIT_SP:
        return value * metrics.scaledDensity;
    case COMPLEX_UNIT_PT:
        return value * metrics.xdpi * (1.0f/72);
    case COMPLEX_UNIT_IN:
        return value * metrics.xdpi;
    case COMPLEX_UNIT_MM:
        return value * metrics.xdpi * (1.0f/25.4f);
    }
    return 0;
}

由代码我们可以看出dp转化出来的公式

//px与dp的关系
pxScreen = dpScreen * density
//可知 density的含义为像素与dp的比值
density = pxScreen / dpScreen
//对于宽度来说
density = wScreen/dpScreen

根据这个公式density=wScreen/dpScreen,我们可以理解成,density为屏幕宽度包含了多少个dp,也就是1dp实际占用了android的drawable类屏幕多少的像素。

像素画据我们的缩放公式scaleFactor=wScreen/wD测试手机是否被监控esign,缩放的最终目的是让设计稿的宽度在不同设备上看起来一样。当我app小胖子们的设计稿的宽度dp固定时,希望这个固定的dp能够刚好均匀的占满整个屏幕的宽度。所以density计算出来就是屏幕的宽度/设计稿的dwebview是什么东西可以删除吗p,就是我们要缩放的比例。也就是

scaleDensity = wScreen / dpDeisgn

代码

 public class AutoSizeHelper {
    private boolean isInited = false;
    private float sNoncompatDensity;
    private float sNoncompatScaledDensity;
    private float sTargetDensity;
    private static AutoSizeHelper sInstance;
    private AutoSizeHelper() {
    }
    public synchronized static AutoSizeHelper getInstance() {
        if (sInstance == null) {
            sInstance = new AutoSizeHelper();
        }
        return sInstance;
    }
    public void init(Application application) {
        DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
        sNoncompatDensity = appDisplayMetrics.density;
        sNoncompatScaledDensity = appDisplayMetrics.scaledDensity;
        // portrait下短边占屏幕适配100%权重,landscape下长短边各占适配50%的权重
        if (OXConstant.APP_MODE == OXConstant.AppMode.PORTRAIT) {
            sTargetDensity = Kits.Dimens.getRawScreenShorter() * 1F / OXConstant.DESIGN_SHORTER;
        } else {
            sTargetDensity = Kits.Dimens.getRawScreenLonger() * 0.5F / OXConstant.DESIGN_LONGER + Kits.Dimens.getRawScreenShorter() * 0.5F / OXConstant.DESIGN_SHORTER;
        }
        isInited = true;
    }
    public boolean isInited() {
        return isInited;
    }
    /**
     * 为了保证density适配的有效性,并且在WebView初始化、屏幕旋转等多种情况下density被动重置后依然能正确重设回来
     * 请在getResource时重设density
     *
     * @param displayMetrics
     */
    public void setDisplayMetrics(DisplayMetrics displayMetrics) {
        if (displayMetrics == null || displayMetrics.density == sTargetDensity) {
            return;
        }
        int targetDensityDpi = (int) (160 * sTargetDensity);
        float targetScaledDensity = sTargetDensity * (sNoncompatScaledDensity / sNoncompatDensity);
        displayMetrics.density = sTargetDensity;
        displayMetrics.scaledDensity = targetScaledDensity;
        displayMetrics.densityDpi = targetDensityDpi;
    }
}