今日头条的安卓适配方案,值得收藏

前言

文章链接,之前确实没有接触过,我简单看了一遍,可以说,这也是相对比较完美的方案,我先简单说一下这个方案的思路,它是通过修改density值,强行把所有不同尺寸分辨率的手机的宽度dp值改成一个统一的值,这样就解决了所有的适配问题。

比如,设计稿宽度是360px,那么开发这边就会把目标dp值设为360dp,在不同的设备中,动态修改density值,从而保证(手机像素宽度)px/density这个值始终是360dp,这样的话,就能保证UI在不同的设备上表现一致了。

这个方案侵入性很低,而且也没有涉及私有API,应该也是极不错的方案,我暂时也想不到强行修改density是否会有其他影响,既然有今日头条的大厂在用,稳定性应当是有保证的。

但是根据我的观察,这套方案对老项目是不太友好的,因为修改了系统的density值之后,整个布局的实际尺寸都会发生改变,如果想要在老项目文件中使用,恐怕整个布局文件中的尺寸都可能要重新按照设计稿修改一遍才行。因此,如果你是在维护或者改造老项目,使用这套方案就要三思了。

具体代码实现为:

    // 今日头条的屏幕适配方案
    // 通过修改density值,强行把所有不同尺寸分辨率的手机的宽度dp值改成一个统一的值,这样就解决了所有的适配问题
    // @param activity
    // @param application

    private static float sNoncompatDensity;
    private static float sNoncompatScaledDensity;
    public static void setCustomDensity(@NonNull Activity activity, @NonNull final Application application){
        DisplayMetrics appDisplayMetrics=application.getResources().getDisplayMetrics();
        if (sNoncompatDensity==0){
            sNoncompatDensity=appDisplayMetrics.density;
            sNoncompatScaledDensity=appDisplayMetrics.scaledDensity;
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(Configuration newConfig) {
                    if (newConfig!=null&&newConfig.fontScale>0){
                        sNoncompatScaledDensity=application.getResources().getDisplayMetrics().scaledDensity;
                    }
                }

                @Override
                public void onLowMemory() {

                }
            });
        }
        float targetDensity=appDisplayMetrics.widthPixels/360;
        float targetScaleDensity=targetDensity*(sNoncompatScaledDensity/sNoncompatDensity);
        int targetDensityDpi=(int)(160*targetDensity);
        appDisplayMetrics.density=targetDensity;
        appDisplayMetrics.scaledDensity=targetScaleDensity;
        appDisplayMetrics.densityDpi=targetDensityDpi;

        final DisplayMetrics activityDisplayMetrics=activity.getResources().getDisplayMetrics();
        activityDisplayMetrics.density=targetDensity;
        activityDisplayMetrics.scaledDensity=targetScaleDensity;
        activityDisplayMetrics.densityDpi=targetDensityDpi;
    }

2018-10-10更新一波:

今天看到大神blankj根据今日头条改进的方案,传送门,写的不错

稀土掘金地址:https://juejin.im/post/5b6250bee51d451918537021

- Adapt the screen for vertical slide.
  *
- @param activity        The activity.
- @param designWidthInPx The size of design diagram's width, in pixel.
  */
  public static void adaptScreen4VerticalSlide(final Activity activity,
                                           final int designWidthInPx) {
  adaptScreen(activity, designWidthInPx, true);
  }
  /**
- Adapt the screen for horizontal slide.
  *
- @param activity         The activity.
- @param designHeightInPx The size of design diagram's height, in pixel.
  */
  public static void adaptScreen4HorizontalSlide(final Activity activity,
                                             final int designHeightInPx) {
  adaptScreen(activity, designHeightInPx, false);
  }
  /**
- Reference from: https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA
  */
  private static void adaptScreen(final Activity activity,
                              final int sizeInPx,
                              final boolean isVerticalSlide) {
  final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();
  final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics();
  final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics();
  if (isVerticalSlide) {
      activityDm.density = activityDm.widthPixels / (float) sizeInPx;
  } else {
      activityDm.density = activityDm.heightPixels / (float) sizeInPx;
  }
  activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.dens
  activityDm.densityDpi = (int) (160 * activityDm.density);
  appDm.density = activityDm.density;
  appDm.scaledDensity = activityDm.scaledDensity;
  appDm.densityDpi = activityDm.densityDpi;
  }
  /**
- Cancel adapt the screen.
  *
- @param activity The activity.
  */
  public static void cancelAdaptScreen(final Activity activity) {
  final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();
  final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics();
  final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics();
  activityDm.density = systemDm.density;
  activityDm.scaledDensity = systemDm.scaledDensity;
  activityDm.densityDpi = systemDm.densityDpi;
  appDm.density = systemDm.density;
  appDm.scaledDensity = systemDm.scaledDensity;
  appDm.densityDpi = systemDm.densityDpi;
  }
  /**
- Return whether adapt screen.
  *
- @return {@code true}: yes<br>{@code false}: no
  */
  public static boolean isAdaptScreen() {
  final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();
  final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics();
  return systemDm.density != appDm.density;
  }


------ 本文结束 ------
坚持原创技术分享,您的支持将鼓励我继续创作!