[Android]今日头条的屏幕适配方案,简单又粗暴!

原文链接

有个大佬以今日头条的方案为基础,结合自己的开发经验,封装了一个屏幕适配库,有兴趣的可以了解一下.

我先简单说一下这个方案的思路,它是通过修改density值,强行把所有不同尺寸分辨率的手机的宽度dp值改成一个统一的值,这样就解决了所有的适配问题。

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

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

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

上代码(做了下改动):

import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.DisplayMetrics;

/**
 * Created by SouShin on 2018/8/20842.
 * 通过修改系统参数来适配android设备
 */

public class DensityUtils {
    private static float appDensity;
    private static float appScaledDensity;
    private static DisplayMetrics appDisplayMetrics;
    private static int barHeight;
    public final static String WIDTH = "width";
    public final static String HEIGHT = "height";

    /**
     * 在Application里初始化一下
     * @param application
     */
    public static void setDensity(@NonNull Application application) {
        //获取application的DisplayMetrics
        appDisplayMetrics = application.getResources().getDisplayMetrics();
        //获取状态栏高度
        barHeight = getStatusBarHeight(application);

        if (appDensity == 0) {
            //初始化的时候赋值
            appDensity = appDisplayMetrics.density;
            appScaledDensity = appDisplayMetrics.scaledDensity;

            //添加字体变化的监听
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(Configuration newConfig) {
                //字体改变后,将appScaledDensity重新赋值
                    if (newConfig != null && newConfig.fontScale > 0) {
                    appScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                    }
            }

                @Override
                public void onLowMemory() {
                }
            });
    }
}

/**
 * 此方法在BaseActivity中做初始化(如果不封装BaseActivity的话,直接用下面那个方法就好)
 * 在setContentView()之前设置
 * @param activity
 */
public static void setDefault(Activity activity) {
    setAppOrientation(activity, WIDTH);
}

/**
 * 此方法用于在某一个Activity里面更改适配的方向
 * 在setContentView()之前设置
 * @param activity
 * @param orientation
 */
public static void setOrientation(Activity activity, String orientation) {
    setAppOrientation(activity, orientation);
}

/**
 * targetDensity
 * targetScaledDensity
 * targetDensityDpi
 * 这三个参数是统一修改过后的值
 * orientation:方向值,传入width或height
 */
private static void setAppOrientation(@Nullable Activity activity, String orientation) {

    float targetDensity;

    if (orientation.equals("height")) {
        targetDensity = (appDisplayMetrics.heightPixels - barHeight) / 667f;//设计图的高度 单位:dp
    } else {
        targetDensity = appDisplayMetrics.widthPixels / 360f;//设计图的宽度 单位:dp
    }

    float targetScaledDensity = targetDensity * (appScaledDensity / appDensity);
    int targetDensityDpi = (int) (160 * targetDensity);

    /**
     *
     * 最后在这里将修改过后的值赋给系统参数
     * 只修改Activity的density值
     */
    DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
    activityDisplayMetrics.density = targetDensity;
    activityDisplayMetrics.scaledDensity = targetScaledDensity;
    activityDisplayMetrics.densityDpi = targetDensityDpi;
}

/**
 * 获取状态栏高度
 *
 * @param context
 * @return
 */
public static int getStatusBarHeight(Context context) {
    int result = 0;
    int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = context.getResources().getDimensionPixelSize(resourceId);
    }
    return result;
    }
}
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值