当前位置:   article > 正文

封装一个适合自己的AutoLayout(基于鸿洋AutoLayout)_基于autolayout封装

基于autolayout封装

简介

为了提升用户体验,经理要求移动端app适配竖屏版平板,我看了下资源包中的layout包,共计200+xml布局文件,不管是做适配文件,还是进行自动适配ViewGroupPrecentRelativelayoutConstraintlayout)进行适配,都是一个不小的工作量,更不用说中间还少不了各种测试......繁琐的操作流程并不适合我这种懒人,对我来说,追吼的就是找个能用的轮子改改,于是,看上了鸿洋的Autolayout

 

要解决的问题

在适配过称中发现一下几个问题:

1、平板适配图片畸形(拉宽)

2、Auto控件不稳定、已成型的布局替换不方便

3、dp在适配中的坑

解决方案

1、适配畸形(过宽、过长)

读了下AutoLayout中适配部分的源码,原理就是取出View中内外间距、宽高等基础距离数据,然后按照给定的参考机型数据进行计算(mf中定义的分辨率),计算出对应的数值。

虽然说这样通过设置pix可以同比放大尺寸和间距,但必然会导致一个问题,在类HeighAttrWidthAttr以及他们的父类AutoAttr中可以看出,高度和宽度按照的比例是高度对高度、宽度对宽度,如果1080p的手机对应1080p的平板这固然没问题,但是若是1080p的手机对应到小米那种(43)的2k平板上呢,或者更长的S8上呢,很显然宽高比不同步,必然会出问题,相较于1080p,2k的小米平板显得更宽,这也自然的会导致原本正方形、圆形等图片发生明显的形变。

     其实这个问题很好解决,按照固定比例计算就可以了,但是这里有个小问题,按照谁的固定比例更合适?理论上来讲,如果页面是静态的(不可滚动的),理应按照屏幕对应的宽高与参考宽高的最小比值进行计算,这样才会防止图片的遮盖、畸形,但是显示区域过窄并不适合用户观看,但是如果按照最大比例计算,则会出现试图的重叠、消失......这需要手工的在外层加上一层ScrollVeiw。


2、Auto控件不稳定、已成型的布局替换不方便

AutoLayout提供的实例中,有个ListView的案例,其中的子View并不是通过使用AutoLayout进行布局适配的,而是调用了AutoUtils中的auto

com.zhy.autolayout.utils;
, 再进一步看, auto方法中还有其他四个方法的调用
  1. public static void auto(View view)
  2. {
  3. if(view instanceof TabLayout)
  4. return;
  5. autoSize(view);
  6. autoPadding(view);
  7. autoMargin(view);
  8. autoTextSize(view, AutoAttr.BASE_DEFAULT);
  9. }
不读源码也可以通过名字看出,这四种方法针对的是View的尺寸、内间距、外间距、字体尺寸,一autoSize为例,继续往下看
  1. public static void autoSize(View view)
  2. {
  3. auto(view, Attrs.WIDTH | Attrs.HEIGHT, AutoAttr.BASE_DEFAULT);
  4. }
  1. public static void auto(View view, int attrs, int base)
  2. {
  3. AutoLayoutInfo autoLayoutInfo = AutoLayoutInfo.getAttrFromView(view, attrs, base);
  4. if (autoLayoutInfo != null)
  5. autoLayoutInfo.fillAttrs(view);
  6. }
  1. public static AutoLayoutInfo getAttrFromView(View view, int attrs, int base)
  2. {
  3. ViewGroup.LayoutParams params = view.getLayoutParams();
  4. if (params == null) return null;
  5. AutoLayoutInfo autoLayoutInfo = new AutoLayoutInfo();
  6. // width & height
  7. if ((attrs & Attrs.WIDTH) != 0 && params.width > 0)
  8. {
  9. autoLayoutInfo.addAttr(WidthAttr.generate(params.width, base));
  10. }
  11. if ((attrs & Attrs.HEIGHT) != 0 && params.height > 0)
  12. {
  13. autoLayoutInfo.addAttr(HeightAttr.generate(params.height, base));
  14. }
  15. ......
  16. return autoLayoutInfo;
  17. }
在以宽度为例进入
  1. public static WidthAttr generate(int val, int baseFlag)
  2. {
  3. WidthAttr widthAttr = null;
  4. switch (baseFlag)
  5. {
  6. case AutoAttr.BASE_WIDTH:
  7. widthAttr = new WidthAttr(val, Attrs.WIDTH, 0);
  8. break;
  9. case AutoAttr.BASE_HEIGHT:
  10. widthAttr = new WidthAttr(val, 0, Attrs.WIDTH);
  11. break;
  12. case AutoAttr.BASE_DEFAULT:
  13. widthAttr = new WidthAttr(val, 0, 0);
  14. break;
  15. }
  16. return widthAttr;
  17. }

  1. private List<AutoAttr> autoAttrs = new ArrayList<>();
  2. public void addAttr(AutoAttr autoAttr)
  3. {
  4. autoAttrs.add(autoAttr);
  5. }
最终的属性加入到了一个list里边

回到方法auto中,查看autoInfo.fillattrs(view);

  1. public void fillAttrs(View view)
  2. {
  3. for (AutoAttr autoAttr : autoAttrs)
  4. {
  5. autoAttr.apply(view);
  6. }
  7. }
可以看出,这段其实就是将我们所便利的属性结果进行了实际运行,也就是说auto这个方案和AutoLayout的试试方案是类似的,只不过这个方案针对于已经成型的View,而不在需要进行布局替换。

明白了其中的道理问题就好解决了,在auto方案外层再次封装一个autoVp,让其遍历所持有的ViewGroup的属性,如果子View是ViewGroup,则继续向下便利:

  1. public static boolean isVp(View view){
  2. return view instanceof ViewGroup ?true: false;
  3. }
  1. public static void autoVP(View view){
  2. if(isVp(view)){
  3. for(int i=0;i<((ViewGroup)view).getChildCount();i++){
  4. AutoUtils.auto(((ViewGroup)view).getChildAt(i));
  5. autoVP(((ViewGroup)view).getChildAt(i));
  6. }
  7. }
  8. }
这样的话,把从布局文件的中获得的View直接扔进autoVp里就可以自动适配了。


3、dp在适配中的坑

看下dp转px的公式,你会发现其实dp对应的应该是一个物理单位,也就是说理想情况下,dp并不会因为设备的大小与分辨率的变化而变化,但是这样的话在使用autoVp时就会出现很古怪的现象,比如在mf的meta中设置的是1080p,放在720p的手机上就会显的特别小,放在小米平板上也不会显示的大多少,而且还会变宽。所以,在使用autoVp时,就需要引入一个新的meta,这个meta设置为模型手机的尺寸(以nexus5为模型机,尺寸4.9)

<meta-data android:name="phone_size" android:value="4.9"></meta-data>
在AutoLayoutConfig中引入:
  1. private void getMetaData(Context context)
  2. {
  3. PackageManager packageManager = context.getPackageManager();
  4. ApplicationInfo applicationInfo;
  5. try
  6. {
  7. applicationInfo = packageManager.getApplicationInfo(context
  8. .getPackageName(), PackageManager.GET_META_DATA);
  9. if (applicationInfo != null && applicationInfo.metaData != null)
  10. {
  11. mDesignWidth = (int) applicationInfo.metaData.get(KEY_DESIGN_WIDTH);
  12. mDesignHeight = (int) applicationInfo.metaData.get(KEY_DESIGN_HEIGHT);
  13. mPhoneSize = (float) applicationInfo.metaData.get(KEY_PHONE_SIZE);
  14. }
  15. } catch (PackageManager.NameNotFoundException e)
  16. {
  17. throw new RuntimeException(
  18. "you must set " + KEY_DESIGN_WIDTH + " and " + KEY_DESIGN_HEIGHT + " in your manifest file.", e);
  19. }
  20. L.e(" designWidth =" + mDesignWidth + " , designHeight = " + mDesignHeight);
  21. }
AutoUtils中增加方法

  1. public static int getPercentPhoneSizeBigger(int val){
  2. float designPhoneSize = (float) AutoLayoutConifg.getInstance().getPhoneSize();
  3. float mPhoneSize = AutoLayoutConifg.getInstance().getScreenSize();
  4. float res = val * mPhoneSize;
  5. if (res % designPhoneSize == 0)
  6. {
  7. return (int)(res / designPhoneSize);
  8. } else
  9. {
  10. return (int)(res / designPhoneSize + 1);
  11. }
  12. }
我这里直接在原有的基础上修改了宽高的计算方式,如果有原有参数使用的需求,大可独立出来一个方法:

  1. protected int getPercentWidthSize()
  2. {
  3. // return AutoUtils.getPercentWidthSizeBigger(pxVal);
  4. return AutoUtils.getPercentPhoneSizeBigger(pxVal);
  5. }
  6. protected int getPercentHeightSize()
  7. {
  8. // return AutoUtils.getPercentHeightSizeBigger(pxVal);
  9. return AutoUtils.getPercentPhoneSizeBigger(pxVal);
  10. }
这样修改就完成了,对使用autoVp的View添加子View时,需要现对子View使用autoVP


参考文档 鸿洋http://blog.csdn.net/lmj623565791/article/details/49990941/





 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/283452
推荐阅读
  

闽ICP备14008679号