封装一个适合自己的AutoLayout(基于鸿洋AutoLayout)
来源:互联网 发布:nginx指定ip访问服务器 编辑:程序博客网 时间:2024/05/23 13:57
简介
为了提升用户体验,经理要求移动端app适配竖屏版平板,我看了下资源包中的layout包,共计200+个xml布局文件,不管是做适配文件,还是进行自动适配ViewGroup(PrecentRelativelayout、Constraintlayout)进行适配,都是一个不小的工作量,更不用说中间还少不了各种测试......繁琐的操作流程并不适合我这种懒人,对我来说,追吼的就是找个能用的轮子改改,于是,看上了鸿洋的Autolayout。
要解决的问题
在适配过称中发现一下几个问题:
1、平板适配图片畸形(拉宽)
2、Auto控件不稳定、已成型的布局替换不方便
3、dp在适配中的坑
解决方案
1、适配畸形(过宽、过长)
读了下AutoLayout中适配部分的源码,原理就是取出View中内外间距、宽高等基础距离数据,然后按照给定的参考机型数据进行计算(mf中定义的分辨率),计算出对应的数值。
虽然说这样通过设置pix可以同比放大尺寸和间距,但必然会导致一个问题,在类HeighAttr和WidthAttr以及他们的父类AutoAttr中可以看出,高度和宽度按照的比例是高度对高度、宽度对宽度,如果1080p的手机对应1080p的平板这固然没问题,但是若是1080p的手机对应到小米那种(4:3)的2k平板上呢,或者更长的S8上呢,很显然宽高比不同步,必然会出问题,相较于1080p,2k的小米平板显得更宽,这也自然的会导致原本正方形、圆形等图片发生明显的形变。
其实这个问题很好解决,按照固定比例计算就可以了,但是这里有个小问题,按照谁的固定比例更合适?理论上来讲,如果页面是静态的(不可滚动的),理应按照屏幕对应的宽高与参考宽高的最小比值进行计算,这样才会防止图片的遮盖、畸形,但是显示区域过窄并不适合用户观看,但是如果按照最大比例计算,则会出现试图的重叠、消失......这需要手工的在外层加上一层ScrollVeiw。
2、Auto控件不稳定、已成型的布局替换不方便
在AutoLayout提供的实例中,有个ListView的案例,其中的子View并不是通过使用AutoLayout进行布局适配的,而是调用了AutoUtils中的auto
com.zhy.autolayout.utils;,再进一步看,auto方法中还有其他四个方法的调用
public static void auto(View view) { if(view instanceof TabLayout) return; autoSize(view); autoPadding(view); autoMargin(view); autoTextSize(view, AutoAttr.BASE_DEFAULT); }不读源码也可以通过名字看出,这四种方法针对的是View的尺寸、内间距、外间距、字体尺寸,一autoSize为例,继续往下看
public static void autoSize(View view) { auto(view, Attrs.WIDTH | Attrs.HEIGHT, AutoAttr.BASE_DEFAULT); }
public static void auto(View view, int attrs, int base) { AutoLayoutInfo autoLayoutInfo = AutoLayoutInfo.getAttrFromView(view, attrs, base); if (autoLayoutInfo != null) autoLayoutInfo.fillAttrs(view); }
public static AutoLayoutInfo getAttrFromView(View view, int attrs, int base) { ViewGroup.LayoutParams params = view.getLayoutParams(); if (params == null) return null; AutoLayoutInfo autoLayoutInfo = new AutoLayoutInfo(); // width & height if ((attrs & Attrs.WIDTH) != 0 && params.width > 0) { autoLayoutInfo.addAttr(WidthAttr.generate(params.width, base)); } if ((attrs & Attrs.HEIGHT) != 0 && params.height > 0) { autoLayoutInfo.addAttr(HeightAttr.generate(params.height, base)); } ...... return autoLayoutInfo; }在以宽度为例进入
public static WidthAttr generate(int val, int baseFlag) { WidthAttr widthAttr = null; switch (baseFlag) { case AutoAttr.BASE_WIDTH: widthAttr = new WidthAttr(val, Attrs.WIDTH, 0); break; case AutoAttr.BASE_HEIGHT: widthAttr = new WidthAttr(val, 0, Attrs.WIDTH); break; case AutoAttr.BASE_DEFAULT: widthAttr = new WidthAttr(val, 0, 0); break; } return widthAttr; }
private List<AutoAttr> autoAttrs = new ArrayList<>(); public void addAttr(AutoAttr autoAttr) { autoAttrs.add(autoAttr); }最终的属性加入到了一个list里边
回到方法auto中,查看autoInfo.fillattrs(view);
public void fillAttrs(View view) { for (AutoAttr autoAttr : autoAttrs) { autoAttr.apply(view); } }可以看出,这段其实就是将我们所便利的属性结果进行了实际运行,也就是说auto这个方案和AutoLayout的试试方案是类似的,只不过这个方案针对于已经成型的View,而不在需要进行布局替换。
明白了其中的道理问题就好解决了,在auto方案外层再次封装一个autoVp,让其遍历所持有的ViewGroup的属性,如果子View是ViewGroup,则继续向下便利:
public static boolean isVp(View view){ return view instanceof ViewGroup ?true: false; }
public static void autoVP(View view){ if(isVp(view)){ for(int i=0;i<((ViewGroup)view).getChildCount();i++){ AutoUtils.auto(((ViewGroup)view).getChildAt(i)); autoVP(((ViewGroup)view).getChildAt(i)); } } }这样的话,把从布局文件的中获得的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中引入:
private void getMetaData(Context context) { PackageManager packageManager = context.getPackageManager(); ApplicationInfo applicationInfo; try { applicationInfo = packageManager.getApplicationInfo(context .getPackageName(), PackageManager.GET_META_DATA); if (applicationInfo != null && applicationInfo.metaData != null) { mDesignWidth = (int) applicationInfo.metaData.get(KEY_DESIGN_WIDTH); mDesignHeight = (int) applicationInfo.metaData.get(KEY_DESIGN_HEIGHT); mPhoneSize = (float) applicationInfo.metaData.get(KEY_PHONE_SIZE); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( "you must set " + KEY_DESIGN_WIDTH + " and " + KEY_DESIGN_HEIGHT + " in your manifest file.", e); } L.e(" designWidth =" + mDesignWidth + " , designHeight = " + mDesignHeight); }AutoUtils中增加方法
public static int getPercentPhoneSizeBigger(int val){ float designPhoneSize = (float) AutoLayoutConifg.getInstance().getPhoneSize(); float mPhoneSize = AutoLayoutConifg.getInstance().getScreenSize(); float res = val * mPhoneSize; if (res % designPhoneSize == 0) { return (int)(res / designPhoneSize); } else { return (int)(res / designPhoneSize + 1); } }我这里直接在原有的基础上修改了宽高的计算方式,如果有原有参数使用的需求,大可独立出来一个方法:
protected int getPercentWidthSize() {// return AutoUtils.getPercentWidthSizeBigger(pxVal); return AutoUtils.getPercentPhoneSizeBigger(pxVal); } protected int getPercentHeightSize() {// return AutoUtils.getPercentHeightSizeBigger(pxVal); return AutoUtils.getPercentPhoneSizeBigger(pxVal); }这样修改就完成了,对使用autoVp的View添加子View时,需要现对子View使用autoVP
参考文档 鸿洋http://blog.csdn.net/lmj623565791/article/details/49990941/
- 封装一个适合自己的AutoLayout(基于鸿洋AutoLayout)
- 基于Autolayout的动画
- Autolayout
- autolayout
- AutoLayout
- autolayout
- AutoLayout
- autolayout
- AutoLayout
- autolayout
- autolayout
- autolayout
- AutoLayout
- Autolayout
- AutoLayout
- Autolayout
- AutoLayout
- autolayout
- Python的基本运行机制
- 第10章 重积分
- 交换排序
- php正则表达式实例
- 今天在看Head First 设计模式的时候发现了一点问题,可能是翻译的原因吧
- 封装一个适合自己的AutoLayout(基于鸿洋AutoLayout)
- 深入理解BootStrap-- 栅格系统(布局)
- spirng data学习(一)
- Mysql数据库单表查询
- 检测到在集成的托管管道模式下不适用的 ASP.NET 设置
- 技术文章 | 用Python写一个NoSQL数据库
- 前端跨域知识总结
- csdn如何转载别人的文章
- PHP学习笔记--字符串操作 作者:yezi33 字符串的整理: trim():除去字符串开头和末尾的空格或其他字符。函数执行成功时返回删除了string字符串首部和尾部空格的字符串,发生错误时返回空