安卓屏幕适配方案(根据今日头条方案,升级版)

转载自 https://blog.csdn.net/qq_33505109/article/details/81709021

前言

屏幕适配方案有很多,比如原生的dp,鸿洋大神的AutoLayout,宽高限定符,今天我用缺点比较小的今日头条方案

头条适配方案的文章链接:https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA

使用效果

测试后可以适配我身边的所有机型(其他的应该是都可以)

  • 设置Activity后Activity可以适配
  • 设置Activity后Activity内的Fragment可以适配
  • 设置Activity后Activity内的RecyclerView可以适配
  • 设置Activity后Activity弹出的Dialog可以适配

优缺点

优点:适配简单,无侵入,调用简单,未使用非官方api,不影响性能

缺点:基本可以通过骚操作来避免

使用方式

复制工具类


 
 
  1. import android.app.Activity;
  2. import android.util.DisplayMetrics;
  3. /**
  4. * 创 建: lt 2018/8/15--14:45
  5. * 作 用: 使用并优化今日头条的适配方案的工具类
  6. * 注意事项: 在Activity的onCreate里,并在setContextView之上调用,可以直接放在Base里
  7. */
  8. public class FitUtil {
  9. private static float width = 750; //todo 手动设置为设计图的宽,适配将根据宽为基准,也可以设置高,但是推荐设置宽,如果不需要px=dp则不设置也行
  10. private static int dpi = 375; //todo 手动设置设计图的dpi,不知道可以设计图的宽除2测试一下
  11. private static float nativeWidth = 0; //真实屏幕的宽,不需要手动改
  12. /**
  13. * 在Activity的onCreate中调用,修改该Activity的density,即可完成适配,使用宽高直接使用设计图上px相等的dp值
  14. *
  15. * @param activity 需要改变的Activity
  16. * @param isPxEqualsDp 是否需要设置为设计图上的px直接在xml上写dp值(意思就是不需要自己计算dp值,直接写设计图上的px值,并改单位为dp),但开启后可能需要手动去设置ToolBar的大小,如果不用可以忽略
  17. */
  18. public static void autoFit(Activity activity, boolean isPxEqualsDp) {
  19. if (nativeWidth == 0) {
  20. nativeWidth = activity.getWindowManager().getDefaultDisplay().getWidth();
  21. }
  22. DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
  23. displayMetrics.density = isPxEqualsDp ? nativeWidth / dpi / (width / dpi) : nativeWidth / dpi;
  24. displayMetrics.densityDpi = ( int) (displayMetrics.density * 160);
  25. }
  26. }

使用

在Activity的onCreate里,并在setContextView之上调用,可以直接放在Base里,比如:


 
 
  1. public class BaseActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. FitUtil.autoFit( this, true); //this
  6. }
  7. }

手动设置好UI给你的设计图的宽和dp(请查看注释自行计算)

单位用dp,字体单位也用dp,就可以自动适配了

需要注意方法的第二个参数

如果UI给你的图纸是按照dp为单位,就设置为false,然后页面上直接写相应的dp值就ok

如果UI给你的图纸是按照px为单位,就设置为true,然后页面上写对应的px值,但是单位写成dp,相当于直接从UI设计图上抄下来,很方便

但是推荐设置为false,如果设计图纸是px为单位则自行计算,因为设置为true会使其他的三方View变得偏小

某些可以避免的坑

  1. 字体单位的坑,sp可以通过修改scaledDensity属性来修改,不过为了防止用户调节字体导致字体显示不全,所以推荐使用dp,而不用去修改scaledDensity属性
  2. 听说8.0手机无效,不过我在自己的8.0手机上可以(华为)
  3. 本方案对纯竖屏应用支持较好,若是纯横屏或横竖屏相交叉的话需要自行修改方法即可

扩展

由于px=dp方案留有一些坑(三方View框架也会用到dp值,而部分无法手动去修改),所以该px=dp的方案并不推荐使用,但是若小伙伴又想如此适配,又想使用px=dp方案的话,接下来我会提供一下骚操作供参考

查看源码可知,系统在使用距离值的时候会把所有的单位值转换为px值来应用,而转换方法如下:


 
 
  1. TypedValue.java下
  2. public static float applyDimension(int unit, float value,
  3. DisplayMetrics metrics)
  4. {
  5. switch (unit) {
  6. case COMPLEX_UNIT_PX:
  7. return value;
  8. case COMPLEX_UNIT_DIP:
  9. return value * metrics.density;
  10. case COMPLEX_UNIT_SP:
  11. return value * metrics.scaledDensity;
  12. case COMPLEX_UNIT_PT:
  13. return value * metrics.xdpi * ( 1.0f/ 72);
  14. case COMPLEX_UNIT_IN:
  15. return value * metrics.xdpi;
  16. case COMPLEX_UNIT_MM:
  17. return value * metrics.xdpi * ( 1.0f/ 25.4f);
  18. }
  19. return 0;
  20. }

可以看到系统提供了六种单位,上面就是修改了dp的计算系数来适配屏幕,而一些三方框架可能会使用dp,sp甚至是px来给View设置宽高,所以可以将目光放在基本不用的单位上

骚操作来了

我们可以使用in这个单位(英寸),修改方法:


 
 
  1. public static void autoFit2(Activity activity, boolean isPxEqualsDp) {
  2. if (nativeWidth == 0) {
  3. nativeWidth = activity.getWindowManager().getDefaultDisplay().getWidth();
  4. }
  5. DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
  6. displayMetrics.xdpi = isPxEqualsDp ? nativeWidth / dpi / (width / dpi) : nativeWidth / dpi;
  7. }

然后所有值抄设计图上的,单位用in,则可以解决上述问题

亲测可以使用,并且适配三方框架,也不会影响到系统控件;但,该方案缺点也有,所以该方案仅供参考

  1. 预览惨不忍睹,因为in单位是英寸,手机才几英寸,而View的值动不动就是几十几百的,预览时基本上就是一个控件占满屏幕
  2. 由于本人只是测试了该方案(n多种情况下),但是并没有正式用在项目上,所以会不会出现奇葩情况也不得而知
  3. 由于修改了xdpi,测试过程中并没有什么其他变化,但目前不清楚修改后会不会有其他的影响(查看源码看到引用该值的地方并不多)
  4. 由于该操作属于比较骚的操作,所以可能不会得到认可(哈哈)

所以上面的几种方案需要自行选择判断

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值