美文网首页
屏幕适配

屏幕适配

作者: 放肆滴微笑 | 来源:发表于2019-11-05 16:10 被阅读0次

1. 什么是屏幕尺寸,屏幕分辨率,屏幕像素密度

1.1屏幕尺寸:
屏幕对角线长度,单位是英寸,比如4.7手机,5寸手机,6寸手机


image.png

1.2屏幕分辨率:
如1920*1080,指在手机屏幕上的像素点个数单位是px,1px=1像素点。


image.png
1.3 屏幕像素密度:
指每英寸上的像素点个数,单位是dpi。像素密度与屏幕尺寸和屏幕分辨率有关。
image.png

2. dp、dip、dpi、sp、px

  • dp:Android特有的,意为密度无关像素,Google 发布的 BASELINE(基准线)为 160,以此为基准。1dip=1px或1dp=1px。480 * 320 160dpi 那么这台机器上的1DP会被翻译成1px
    800 * 480 240dpi 而这台机器上的1DP会被翻译成1.5px
  • dip:(Density Independent Pixels)同dp一个意思
  • dpi:屏幕像素密度
  • sp:(Scale-IndependentPixels)可以根据文字大小首选项自动进行缩放。Google推荐我们使用12sp以上的大小,通常使用12sp,14sp,18sp,22sp,为避免精度损失,建议最好不要使用奇数和小数
  • px:构成涂销的最小单位,常说的像素
  名称                 像素密度范围         图片大小
  mdpi                 120dp~160dp         48×48px
  hdpi                 160dp~240dp         72×72px
  xhdpi                240dp~320dp         96×96px
  xxhdpi               320dp~480dp         144×144px
  xxxhdpi              480dp~640dp         192×192px
image.png

在Google官方开发文档中,说明了 mdpi:hdpi:xhdpi:xxhdpi:xxxhdpi=2:3:4:6:8 的尺寸比例进行缩放。例如,一个图标的大小为48×48dp,表示在mdpi上,实际大小为48×48px,在hdpi像素密度上,实际尺寸为mdpi上的1.5倍,即72×72px,以此类推,可以继续往后增加,不过一般情况下已经够用了,这种用来去适配手机和平板之间的图形问题

3. 屏幕适配

  • 限定符
限定符分类:
    屏幕尺寸    
        small   小屏幕
        normal  基准屏幕
        large   大屏幕
        xlarge  超大屏幕
    屏幕密度
        ldpi    <=120dpi
        mdpi    <= 160dpi
        hdpi    <= 240dpi
        xhdpi   <= 320dpi
        xxhdpi  <= 480dpi
        xxhdpi  <= 640dpi(只用来存放icon)
        nodpi   与屏幕密度无关的资源.系统不会针对屏幕密度对其中资源进行压缩或者拉伸
        tvdpi   介于mdpi与hdpi之间,特定针对213dpi,专门为电视准备的,手机应用开发不需要关心这个密度值.
    屏幕方向    
        land    横向
        port    纵向
    屏幕宽高比   
        long    比标准屏幕宽高比明显的高或者宽的这样屏幕
        notlong 和标准屏幕配置一样的屏幕宽高比

3.1、 屏幕分辨率限定符(不推荐)

屏幕分辨率限定符适配需要再res文件夹下创建各种屏幕分辨率对应的valuse-xxx,如图

image.png
然后根据一个基准分辨率,例如基准1280*720,将宽度分成720份,取值1px720px,将高度分为1280份,取值1px1280px,生成各种分辨率对应的dimens.xml
image.png
加上设计图上空间宽度为600px,那布局中就写android:layout_width="@dimen/x600" ,当运行程序时,就会找对应的valuse下面对应的dimens,如720手机找720下的x600,1080则找1080下的x600,从而达到屏幕的适配。

3.2 smallestWidth 限定符(推荐)

smallestWidth 限定符适配原理与屏幕分辨率限定符适配原理一样,系统都是根据限定符去寻找对应的 dimens.xml 文件。例如程序运行在最小宽度为 360dp 的设备上,系统会自动找到对应的 values-sw360dp 文件夹下的 dimens.xml 文件。区别就在于屏幕分辨率限定符适配是拿 px 值等比例缩放,而 smallestWidth 限定符适配是拿 dp 值来等比缩放而已。需要注意的是“最小宽度”是不区分方向的,即无论是宽度还是高度,哪一边小就认为哪一边是“最小宽度”。如下分别为最小宽度为 360dp 与最小宽度为 640dp 所对应的 dimens.xml 文件:

最小宽度的计算
假如当前设备为1920*1080分辨率 5.5寸手机
1920*1920+1080*1080 = 4852800
开根约2202...
像素密度DPI=2202/5.5=400
400/160 = 2.5  因为160是基准
1080/2.5 = 432   这就是最小宽度dp

DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int heightPixels = ScreenUtils.getScreenHeight(this);
int widthPixels = ScreenUtils.getScreenWidth(this);
float density = dm.density;
float heightDP = heightPixels / density;
float widthDP = widthPixels / density;
float smallestWidthDP;
if(widthDP < heightDP) {
    smallestWidthDP = widthDP;
}else {
    smallestWidthDP = heightDP;
}
image.png

3.3 为什么选择samallWidth限定符

既然原理都一样,都需要多套dimens.xml文件,为啥选择samallWidth不选择屏幕分辨率限定符呢?
1、屏幕分辨率限定符适配根据分辨率的,android设备分辨率非常多,还要考虑虚拟键盘,就需要大量dimens.xml,就19201080是无虚拟键盘,有无虚拟键盘就变成18121080。而无论手机像素是多少,密度多少,90%手机的最小宽度都是360dp所以采用samallWidth,就变成少量dimens.xml文件。
2、屏幕分辨率是px单位,而samallWidth是dp和sp,Google推荐使用dp和sp,sp又能随着设置系统大小而更改字体大小,使用起来更灵活。
3、屏幕分辨率需要valuse-xxx完全匹配才能达到适配,而samallWidth限定符寻找dimens.xml的原理是从大忘小的找,假如设备最小宽度是411dp,就会先找valuse-411dp,发现没有,才会像下找valuse-410~~400,如果没有,才会去valuse默认里面找。

4. 屏幕适配解决方案

4.1 系统布局方案

  • 避免写死控件尺寸,使用wrap_content, match_parent
  • LinearLayout xxx:weight="0.5“
  • RelativeLayout xxx:layout_centerInParent="true" ...
  • ContraintLayout xxx:layout_constraintLeft_toLeftOf="parent"...

4.2 像素密度适配

1、在BaseActivity方法中调用DensityUtils.setDensity(getApplication(), this);
2、或者在Activity的生命周期中调用

registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                DensityUtils.setDensity(MyApplication.this, activity);
            }

下面为像素密度的适配代码

    private static final float WIDTH = 360;//参考像素密度(dp)
    private static float appDensity;//表示屏幕密度
    private static float appScaleDensity;//字体缩放比例,默认为appDensity

    public static void setDensity(final Application application, Activity activity) {
        //获取当前屏幕信息
        DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
        if (appDensity == 0) {
            //初始化赋值
            appDensity = displayMetrics.density;
            appScaleDensity = displayMetrics.scaledDensity;
            //监听字体变化
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(Configuration newConfig) {
                    //字体发生更改,重新计算scaleDensity
                    if (newConfig != null && newConfig.fontScale > 0) {
                        appScaleDensity = application.getResources().getDisplayMetrics().scaledDensity;
                    }
                }

                @Override
                public void onLowMemory() {

                }
            });
        }
        //计算目标density scaledDensity
        float targetDensity = displayMetrics.widthPixels / WIDTH;//1080/360=3;
        float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
        int targetDensityDpi = (int) (targetDensity * 160);
        //替换Activity的值
        //px = dp * (dpi / 160)
        DisplayMetrics dm = activity.getResources().getDisplayMetrics();
        dm.density = targetDensity;  //(dpi/160) 后得到的值
        dm.scaledDensity = targetScaleDensity;
        dm.densityDpi = targetDensityDpi;  //dpi
    }

4.3 通过smallestWidth 限定符来适配

5 刘海屏适配

1、判断有没有刘海屏,需要再View绑定到Window后才能判断,没有绑定则拿不到数据

NotchUtil.isHasCutout(this, new OnCutoutListener() {
            @Override
            public void isHasCutout(boolean isHas) {
                isHasCutout = isHas;  //注释1
                if (isHas) {
                    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                    /**
                     * * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 全屏模式,内容下移 非全屏模式下不受影响
                     * * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 允许内容进入刘海区域
                     * * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 不允许内容进入刘海区域
                     */
                    NotchUtil.setImmersiveWithNotch(BaseActivity.this, false,
                            WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES);
                }
            }
        });

可以在注释1处获取到当前是否是刘海屏
判断刘海屏实际代码
因为刘海屏是在28之后才出现的,Google在28之后也出了专门获取刘海屏的类

/**
     * 判断是否有刘海屏
     * PS:因为Android P是在回调中判断的,所以,使用listener形式
     * 并且,只有在切换时才会获取到,否则返回都是false(API 28)
     *
     * @param app      {@link AppCompatActivity}
     * @param listener {@link OnCutoutListener}
     */
    public static void isHasCutout(AppCompatActivity app, OnCutoutListener listener) {
        if (Build.VERSION.SDK_INT >= 28) {
            NotchThirdUtil.getNotchSize4Google(app, listener);
        } else {
            if (OSUtil.isEmui()) {
                listener.isHasCutout(NotchThirdUtil.hasNotchInScreenAtHuawei(app));
            } else if (OSUtil.isOppo()) {
                listener.isHasCutout(NotchThirdUtil.hasNotchInScreenAtOppo(app));
            } else if (OSUtil.isVivo()) {
                listener.isHasCutout(NotchThirdUtil.hasNotchInScreenAtVoio(app));
            } else if (OSUtil.isMiui()) {
                listener.isHasCutout(NotchThirdUtil.hasNotchInScreenAtXiaomi());
            }
        }
    }

2、在得到是否有刘海屏后,如果有,则通过设置布局的padding属性,将布局下移状态栏的高度,没有则不处理

@Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        if(getIsHasCutout()){  //有刘海屏,则下移
            RelativeLayout layout = findViewById(R.id.layout);
            layout.setPadding(0, StatusBarUtil.getStatusBarHeight(this)
                    , 0, 0);
        }
    }

相关文章

  • 屏幕适配总结

    屏幕适配总结 为什么要针对屏幕做适配 drawable目录常见问题 : 屏幕适配方案:

  • Android屏幕适配-应用篇

    目录 Android屏幕适配-基础篇Android屏幕适配-应用篇 Android屏幕适配最主要的原因:  是由于...

  • 屏幕适配的那些坑

    屏幕适配的那些坑 屏幕适配的那些坑

  • LayaAir屏幕适配

    LayaAir屏幕适配 官方教程链接:LayaAir实战开发11-屏幕适配 屏幕适配 随着移动端设备(手机、平板、...

  • she

    1.适配的分类 系统适配 屏幕适配 1.1屏幕适配历史 1.1.1autoresizing 去掉auto layo...

  • Android屏幕适配

    一. 为什么要适配屏幕 android屏幕大小、屏幕密度碎片化严重 二. 怎么样适配屏幕 图片适配 应用图标提供不...

  • 屏幕适配AutoResizing

    适配器简介 AutoResizing 屏幕适配的历史 -iPhonestyGS\IPhone4 -没有屏幕适配可言...

  • css media 适配屏幕宽度

    H5 屏幕适配 css media 适配屏幕宽度;js 通过 适配获取屏幕宽度,来执行对应方法; max-widt...

  • 关于iOS适配的一点事

    屏幕适配及文字适配

  • Android屏幕适配(4)常见:第三种

    前言:Android屏幕适配(1)基础知识篇Android屏幕适配(2)常见:第一种Android屏幕适配(3)常...

网友评论

      本文标题:屏幕适配

      本文链接:https://www.haomeiwen.com/subject/qnysbctx.html