美文网首页
2018-08-29

2018-08-29

作者: 贾发展 | 来源:发表于2018-08-29 16:01 被阅读0次

今日头条适配方案 

一、屏幕适配原理

1Android中的dppxdpidesity关系

px = density * dp;

density = dpi / 160;

px = dp * (dpi / 160);

其中dpi是根据屏幕的真实分辨率和尺寸计算的,每个设备可能都不一样

2、为什么要算出 density,这和屏幕适配有什么关系呢?

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;

    }

不管你在布局文件中填写的是什么单位,最后都会被转化为px,系统就是通过上面的方法,将你在项目中任何地方填写的单位都转换为px 的,所以我们常用的pxdp的公式dp = px / density,就是根据上面的方法得来的

3、修改density的大小,保证在所有的设备上计算出来的px 的值正好是屏幕宽度(解决方案)

(1)、Denstiy是DisplayMetrics 中的成员变量,DisplayMetrics 实例通过 Resources#getDisplayMetrics() 可以获得,而Resouces通过Activity或者Application的Context获得

DisplayMetrics#density 就是上述的density

DisplayMetrics#densityDpi 就是上述的dpi

DisplayMetrics#scaledDensity 字体的缩放因子

正常情况下和density相等,但是调节系统字体大小后会改变这个值

(2)假设按照设计图是320dp,依据宽度来适配

注:今日头条的适配方式,今日头条适配方案默认项目中只能以高或宽中的一个作为基准,进行适配

那么适配后的 density = 设备真实宽(单位px) / 320,接下来只需要把我们计算好的 density 在系统中修改下即可,代码实现如下

// 获取原始密度大小

private static float sRoncompatDennsity;

// 缩放比例因子

private static float sRoncompatScaledDensity;

private void setCustomDensity(@NonNull Activity activity,final @NonNull Application application) {

    //application

final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();

    if (sRoncompatDennsity == 0) {

        sRoncompatDennsity = appDisplayMetrics.density;

        sRoncompatScaledDensity = appDisplayMetrics.scaledDensity;

        //

当应用程序运行中,系统配置发生改变时,系统回调用此方法

        application.registerComponentCallbacks(new ComponentCallbacks() {

            @Override

            public void onConfigurationChanged(Configuration newConfig) {

                if (newConfig !=null && newConfig.fontScale > 0) {

                 // 当系统配置发生改变,缩放因子也随之改变

                    sRoncompatScaledDensity = application.getResources()

                            .getDisplayMetrics().scaledDensity;

                }

            }

        });

    }

    //

计算宽为320dp

    final float targetDensity = appDisplayMetrics.widthPixels / 320;

    final float targetScaledDensity = targetDensity * (sRoncompatScaledDensity /sRoncompatDennsity);

    final int targetDensityDpi = (int) (targetDensity * 160);

    appDisplayMetrics.density = targetDensity;

    appDisplayMetrics.densityDpi = targetDensityDpi;

    appDisplayMetrics.scaledDensity = targetScaledDensity;

    //activity

final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();

    activityDisplayMetrics.density = targetDensity;

    activityDisplayMetrics.densityDpi = targetDensityDpi;

    activityDisplayMetrics.scaledDensity = targetScaledDensity;

}

AndroidAutoSize 使用注意事项和原理

项目地址:https://github.com/JessYanCoding/AndroidAutoSize

1、AndroidAutosize使用注意事项

              我们还是依照宽度为320dp为基准说明

[if !supportLists]a、  [endif]当我们的设计图宽度为填充整个屏幕的宽度时,我们的宽度写成layout_width="320dp"和layout_width="match_parent"都可以

[if !supportLists]b、  [endif]对于固定尺寸的图片或者其他控件,如果mark图上面明确标注了宽、高,我就按照设计图宽和高的1\2设置对应的宽、高(单位为:dp)

2、AndroidAutosize原理

       AndroidAntuosize 第三方库的实现基本原理和今日头条适配原理一样,其实就是对今日头条适配方案的封装

1、通过声明{@link

InitProvider} 自动启动初始化

Provider是由ActivityThread负责启动的,ActivityThread对应应用进程的主线程,即在应用进程启动时,会将ContentProvider启动起来。

@Override

public boolean onCreate() {

    AutoSizeConfig.getInstance()

            .setLog(true)

            .init((Application) getContext().getApplicationContext())

            .setUseDeviceSize(false);

    return true;

}

2、配置AutosizeConfig中完成具体的初始化工作

   注意:初始化方法只能调用一次, 否则报错,对activity和fragment的生命周期注册监听,初始化默认的设配策略(在manifest 中配置)如果对某个activiyh 进行了自定义策略,则使用自定义策略

/**

 *框架会在APP 启动时自动调用此方法进行初始化, 使用者无需手动初始化, 初始化方法只能调用一次, 否则报错

 *

 * @param application   {@link Application}

 * @param isBaseOnWidth详情请查看{@link #isBaseOnWidth} 的注释

 * @param strategy      {@link AutoAdaptStrategy},{@code null} 则使用{@link DefaultAutoAdaptStrategy}

 */

AutoSizeConfig init(final Application application, boolean isBaseOnWidth, AutoAdaptStrategy strategy) {

    Preconditions.checkArgument(mInitDensity == -1, "AutoSizeConfig#init() can only be called once");

    Preconditions.checkNotNull(application, "application == null");

    this.mApplication = application;

    this.isBaseOnWidth = isBaseOnWidth;

    final DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();

    //manifest中获取配置的宽或者高

    getMetaData(application);

//获取屏幕的真实宽度和高度

    int[] screenSize = ScreenUtils.getScreenSize(application);

    mScreenWidth = screenSize[0];

    mScreenHeight = screenSize[1];

    mInitDensity = displayMetrics.density;

    mInitDensityDpi = displayMetrics.densityDpi;

    mInitScaledDensity = displayMetrics.scaledDensity;

    application.registerComponentCallbacks(new ComponentCallbacks() {

        @Override

        public void onConfigurationChanged(Configuration newConfig) {

            if (newConfig != null) {

                if (newConfig.fontScale > 0) {

                    mInitScaledDensity =

                            Resources.getSystem().getDisplayMetrics().scaledDensity;

                int[] screenSize = ScreenUtils.getScreenSize(application);

                mScreenWidth = screenSize[0];

                mScreenHeight = screenSize[1];

            }

        }

        @Override

        public void onLowMemory() {

        }

    });

    mActivityLifecycleCallbacks = new ActivityLifecycleCallbacksImpl(strategy == null ? new DefaultAutoAdaptStrategy() : strategy);

    //Activity的生命周期事件进行监听

    application.registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks);

    return this;

}

3、获取使用者在Androidmanifest中填写的meta信息

           android:value="320"/>

           android:value="568"/>

private void getMetaData(final Context context) {

    new Thread(new Runnable() {

        @Override

        public void run() {

            PackageManager packageManager = context.getPackageManager();

            ApplicationInfo applicationInfo;

            try {

                applicationInfo = packageManager.getApplicationInfo(context

                        .getPackageName(), PackageManager.GET_META_DATA);

                if (applicationInfo != null && applicationInfo.metaData != null) {

                    if (applicationInfo.metaData.containsKey(KEY_DESIGN_WIDTH_IN_DP)) {

                        mDesignWidthInDp = (int) applicationInfo.metaData.get(KEY_DESIGN_WIDTH_IN_DP);

                    }

                    if (applicationInfo.metaData.containsKey(KEY_DESIGN_HEIGHT_IN_DP)) {

                        mDesignHeightInDp = (int) applicationInfo.metaData.get(KEY_DESIGN_HEIGHT_IN_DP);

                    }

                }

            } catch (PackageManager.NameNotFoundException e) {

                e.printStackTrace();

            }

        }

    }).start();

}

4、默认配置策略

这里是今日头条适配方案的核心代码, 核心在于根据当前设备的实际情况做自动计算并转换DisplayMetrics#density、DisplayMetrics#scaledDensity、DisplayMetrics#densityDpi这三个值, 有兴趣请看下面的链接设计图上的设计尺寸, sizeInDp设计图上的设计尺寸,单位dp, 如果isBaseOnWidth设置为true,则应该填写设计图的总宽度, 如果isBaseOnWidth 设置为false, sizeInDp 则应该填写设计图的总高度,isBaseOnWidth 是否按照宽度进行等比例适配, true为以宽度进行等比例适配, false 为以高度进行等比例适配

public static void autoConvertDensity(Activity activity, float sizeInDp, boolean isBaseOnWidth) {

    Preconditions.checkNotNull(activity, "activity == null");

    int screenSize = isBaseOnWidth ? AutoSizeConfig.getInstance().getScreenWidth()

            : AutoSizeConfig.getInstance().getScreenHeight();

    String key = sizeInDp + "|" + isBaseOnWidth + "|"

            + AutoSizeConfig.getInstance().isUseDeviceSize() + "|"

            + AutoSizeConfig.getInstance().getInitScaledDensity() + "|"

            + screenSize;

    DisplayMetricsInfo displayMetricsInfo = mCache.get(key);

    float targetDensity = 0;

    int targetDensityDpi = 0;

    float targetScaledDensity = 0;

    if (displayMetricsInfo == null) {

        if (isBaseOnWidth) {

            targetDensity = AutoSizeConfig.getInstance().getScreenWidth() * 1.0f / sizeInDp;

        } else {

            targetDensity = AutoSizeConfig.getInstance().getScreenHeight() * 1.0f / sizeInDp;

        }

        targetScaledDensity = targetDensity * (AutoSizeConfig.getInstance().

                getInitScaledDensity() * 1.0f / AutoSizeConfig.getInstance().getInitDensity());

        targetDensityDpi = (int) (targetDensity * 160);

        mCache.put(key, new DisplayMetricsInfo(targetDensity, targetDensityDpi, targetScaledDensity));

    } else {

        targetDensity = displayMetricsInfo.density;

        targetDensityDpi = displayMetricsInfo.densityDpi;

        targetScaledDensity = displayMetricsInfo.scaledDensity;

    }

   //activity applicationDisplayMetrics设置参数

     setDensity(activity, targetDensity, targetDensityDpi, targetScaledDensity);

}

相关文章

  • 2018-08-30

    2018-08-29 张shilian 2018-08-29 22:22 · 字数 333 · 阅读 1 · 日记...

  • 2018-08-30

    2018-08-29 c6_李晓红Dorothy 2018-08-29 07:12 · 字数 265 · 阅读 1...

  • 2018-08-29

    戴师傅 2018-08-29 2018-08-29 20:32 打开App (稻盛哲学学习会)打卡第125天 姓名...

  • (ACM)Bitcoin's Academic Pedi

    2018-08-29 Bitcoin's Academic Pedigree | ACM杂志 2017 Vol-1...

  • 【置顶】技术研发视频分享汇总

    Android 2018-08-29更新 Android架构技术 2018-08-28 更新 Android核心技...

  • 2018-08-29

    2018-08-28 张shilian 2018-08-29 22:28 · 字数 388 · 阅读 1 · 日记...

  • Hexo博客添加在线联系功能

    title: Hexo博客添加在线联系功能date: 2018-08-29 21:03:11tags:- 博客- ...

  • 非典型生意指标

    发表于2018-08-29[http://ibochina.com/archives/1542] 非典型生意指标[...

  • 2018-08-29

    2018-08-29 万千工品金秀 2018-08-28 22:22 · 字数 376 · 阅读 4 · 日记本 ...

  • 2018-08-30

    2018-08-30 万千工品金秀 2018-08-29 21:16 · 字数 464 · 阅读 2 · 日记本 ...

网友评论

      本文标题:2018-08-29

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