由于自己在开发中遇到的问题,所有弄了一个 Android Shape 的工具 Duck ,能帮助开发者直接在 xml 的任意控件上实现 Shape 效果,无需创建额外的xml文件,并且没有任何侵入性。

废话不多说,直接看效果:

项目地址:Duck

初衷

这个库的由来,是因为公司一个维护了 4 年的项目。

经历 4 年的项目,产品设计不知道改了多少版,期间产生并堆砌大量shape.xml 文件,这些文件因为索引的问题往往还无法清理。

同时,同一个 shape.xml 文件,因为设计存在不规范的问题,在不同页面改动了一点颜色、倒角或线宽等,就无法复用,必须据此创建新的文件。

最后,大量的文件堆积,开发人员开发时,花时间找 shape.xml ,还不如自己创建新的方便,这样恶性循环, 只能 GG。

我想说,Android 设计 Shape 的初衷是好的: 一个 APP,统一的设计规范,就应该复用 Shape

但这种情况对于国内的生态来说并不适用。

首先,相同屏幕尺寸,中文承载信息的能力远大于英文,这就导致国外大部分 APP 界面设计简洁清爽,国内就显得非常复杂,同时国内互联网更新速度很快,界面是生命周期短,人员流动,很难做到界面统一。

所有,Android 的 Shape 并不适合国内生态。

开发时,超级羡慕对面 IOS 开发们可以直接在控件上进行花式倒角、加线框等骚操作,想不通为啥 Android 不能在这一点上借鉴IOS。哎,Android 与 IOS 的宿命之争,说多了都是泪。

基于上面种种原因,所以出现了想开发这个库。

这个库只实现最常用的 Shape 功能,selector 及 layout-list 并未实现,因为有两点考虑:

  1. shape 使用场景更多,并且更频繁,其他两种只在少数特定场景中使用。
  2. selector 及 layout-list 需要更多精细的代码控制,如全部挤在 xml 中一个控件上,会非常臃肿,难以维护。

原理

在考虑用什么技术实现时,考虑这几点:

  1. 任何控件都能有效,即使是自定义控件。
  2. 不能有侵入性,即使更换或废弃本库,也能保证稳定性。

最开始,第一个想到的是 LayoutInflater.Factory ,xml 控件解析成 View时,必须经过它,也是换肤的解决方案,但这样得一个个替换成自己的,非常麻烦。

有没有更好的解决方案呢?

得益于 AspectJ 的 AOP(面向切面编程)能力,我们可以在编译时期,直接在 View 及其子类的构造方法中插入相关代码,解析xml 中自定义的属性,最后设置到控件上。

    @Pointcut("execution(android.view.View+.new(..))")public void callViewConstructor() {}@After("callViewConstructor()")public void inject(JoinPoint joinPoint) throws Throwable {Signature signature = joinPoint.getSignature();Object target = joinPoint.getTarget();Object[] args = joinPoint.getArgs();int length = args.length;if (!(target instanceof View) || length < 2 || target.hashCode() == lastHash || !(args[0] instanceof Context) || !(args[1] instanceof AttributeSet)) {return;}lastHash = target.hashCode();Context context = (Context) args[0];AttributeSet attrs = (AttributeSet) args[1];int count = attrs.getAttributeCount();for (int i = 0; i < count; i++) {Log.i(TAG, attrs.getAttributeName(i) + " = " + attrs.getAttributeValue(i));}Log.i(TAG, "inject =====> " + signature.toString());DuckFactor.getFactor().inject((View) target, context, attrs);}
复制代码

AOP 相关内容,可以查看AOP 系列 包含:

1.OOP 与 AOP

2.Java 注解处理器

3.Aspect

4.Android中使用 Javassist

由于 AspectJ 能遍历项目中所有依赖包,因此,无论是 support 库,还是第三方库都能得到很好支持。

但是 AOP 也存在一定问题,我们的 apk 中是不会存在系统原生 Android SDK 的,例如 TextView 这个系统控件,在编译时是不会打包到 apk 中,因此,AOP 技术对这种原生控件无能为力。

幸好,我们绝大部分项目为了兼容性,一般都会直接依赖官方的兼容库,即 support 相关的库。

在 support· 库中,会将一些原生控件,直接替换成 support 相关控件。相关代码如下:

android/support/v7/app/AppCompatViewInflaterswitch (name) {case "TextView":view = createTextView(context, attrs);verifyNotNull(view, name);break;case "ImageView":view = createImageView(context, attrs);verifyNotNull(view, name);break;case "Button":view = createButton(context, attrs);verifyNotNull(view, name);break;case "EditText":view = createEditText(context, attrs);verifyNotNull(view, name);break;......}
复制代码

而对于这些控件,我们的 AOP 都能够生效了。

在 support 库中,没有替换掉 ViewGroup 的几个常用子类,如LinearLayoutRelativeLayoutFrameLayout等,

所以,我们我们仿照 support 的替换方式,直接在 LayoutInflater.Factory.onCreateView 方法中注入相应的替换代码。

    @Pointcut("execution(* *..LayoutInflater.Factory+.onCreateView(..))")public void callLayoutInflater() {}@Around("callLayoutInflater()")public Object replaceView(ProceedingJoinPoint joinPoint) throws Throwable {....switch (name) {case "RelativeLayout":return new DuckRelativeLayout(context, attrs);case "LinearLayout":return new DuckLinearLayout(context, attrs);case "FrameLayout":return new DuckFrameLayout(context, attrs);case "TableLayout":return new DuckTableLayout(context, attrs);case "ScrollView":return new DuckScrollView(context, attrs);default:break;}return result;}复制代码

这个库的代码其实很少,我这里也只是实现了 Shape 这一个功能。

    private static Injector mInjector;public static void setFactor(Injector injector) {mInjector = injector;}public static Injector getFactor() {if (mInjector == null) {mInjector = new ShapeInjector();}return mInjector;}
复制代码

这里保留的 Duck 的扩展性,如果觉得不够,可以自行实现功能更强大的 Injector。

AOP 的能力远不止如此,还有很多事情可以做,建议大家可以发挥想象,进行更多的扩展。

优化

核心原理已经搞定,还有两点需要优化:

  1. 在 xml 中使用时,没有提示不方便,这一点可以通过Live Template 来解决。

  2. 无法预览,AOP 在编译时工作,所有无法实时预览,看到别人的库是替换成自定义 View 来查看效果,感觉这种实现方式不够完美,所有就放弃了,后续想着能否通过 AS 插件实现预览。

项目地址:Duck

小插曲

这个库的出现挺坎坷的。

在 18 年 8 月份左右,就开始写了这个库,当时核心功能的实现,xml 的代码提示问题都已经想好了解决方案。

但写到一半出现了功能相同的库,

BackgroundLibrary

仔细看了项目代码,对比发现实现原理不一样,xml 提示解决方案相同,预览问题通过替换解决。

额~

好吧!就瞬间没写下去的动力了,再加上公司赶工期,代码就扔在那没动了。

直到最近空闲了,突然想着不管这样,还是弄完吧,搞个烂尾实在是不好。

转载于:https://juejin.im/post/5cee6d475188254aeb17e542

Android Shape工具 Duck相关推荐

  1. Android 开发工具集合 - (Android Dev Tools)

    收集整理Android开发所需的Android SDK.开发中用到的工具.Android开发教程.Android设计规范,免费的设计素材等. 欢迎大家推荐自己在Android开发过程中用的好用的工具. ...

  2. Android开发工具集合

    Android Studio Android开发环境,基于IntelliJ IDEA,谷歌2013年I/O大会发布,类似 Eclipse ADT:现已更新到1.3版本(截止15年8月),并支持NDK开 ...

  3. Android开发工具类集合

    各种帮助类汇总:https://github.com/Blankj/AndroidUtilCode 常用的 ios 风格 dialog 和 meterial design 风格的 dialog:htt ...

  4. 【转】Android开发工具--android-studio-bundle-141.2288178

    原文网址:http://www.androiddevtools.cn/ AndroidDevTools简介 Android Dev Tools官网地址:www.androiddevtools.cn 收 ...

  5. android 开发工具

    549  Star3,430 Fork 1,325 inferjay/AndroidDevTools  Code Issues 4 Pull requests 0WikiPulseGraphs 收集整 ...

  6. Android开发工具类、样式、一些配置

    Android Studio 开发工具类.样式.其余的配置 一.工具类 1.Log输出 2.轻量存储SharedPreferences 二.主题与样式 1.主题 2.常用样式 1.按钮圆角背景 2.按 ...

  7. android开发工具简介及下载地址

    AndroidDevTools简介 Android Dev Tools官网地址:www.androiddevtools.cn 收集整理Android开发所需的Android SDK.开发中用到的工具. ...

  8. Android Shape 的使用

    学而时习,温故而知新. 今天复习shape 画各种常见类型的背景图 使用: 当在 java 代码R.drawable.文件的名称 当在布局中时 android:background="@dr ...

  9. java安卓开发工具_推荐几个非常实用的Android开发工具

    工欲善其事,必先利其器.我们进行Android开发也要有好的开发工具辅助才能更好更高效的完成各种开发,为用户提供更实用的应用程序.本文就为大家推荐几个非常实用的Android开发工具,及几个常用的编辑 ...

最新文章

  1. 获清华特奖又上“最强大脑”!这位90后学神去一线抗疫的理由是……
  2. P6271 [湖北省队互测2014]一个人的数论(莫比乌斯反演,拉格朗日插值)
  3. 内网通 去广告_新高一攻略|让我们一起跟升学e网通名师看看如何学好高中化学...
  4. Shell(8)——for、while、until
  5. 海量数据处理(二) :常见海量数据处理方法
  6. 安装win7系统不能开机启动服务器,win7系统开机启动项不能加载的原因分析及解决...
  7. usb转232线驱动_为什么越来越多人用USB,却不用RS232?USB有什么好?
  8. 7系统内部系统组件禁止休眠_海康监控系统平台设计思路(二)
  9. SQL中Left Join 与Right Join 与 Inner Join 与 Full Join的区别
  10. 20165301陈潭飞2017-2018-2 20165301 实验三《Java面向对象程序设计》实验报告
  11. winform基础,主要控件简单介绍,以及小练习
  12. 计算机毕业论文任务书模板,平面设计毕业论文任务书范文
  13. win10 专业版 explorer.exe下载 (完全Free)
  14. 社会网络分析中的基本概念
  15. Mybatis-四大神兽
  16. 你未必知道的 WebRTC – 前世、今生、未来
  17. python邮件合并的基本操作步骤_邮件合并的基本操作步骤 - 卡饭网
  18. 2018-03-08,模板消息推送,全代码,多多指教
  19. dede在添加文章页增加附件上传后点击浏览找不到文件提示No Exsits Path解决
  20. Linux root密码修改

热门文章

  1. PL/SQL程序设计(七)—— 触发器
  2. spring框架入门day02
  3. [BZOJ] 1610: [Usaco2008 Feb]Line连线游戏
  4. 使用线程池应该注意的问题
  5. 新秀发挥云17号:RHEL改变以太网地址克隆虚拟机后,
  6. 【CSS3】---only-child选择器+only-of-type选择器
  7. Eclipse中Mybatis的自动提示的配置
  8. 软件测试:测试一个网站
  9. selenium 定位方式3-css_selector
  10. net 去掉第一位和最后一位_本赛季英超门将的扑救成功率,第一位和最后一位竟来自同家俱乐部...