赞
踩
简介
为了提升用户体验,经理要求移动端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/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。