前言
新年快乐,大家好,我又来了。。。
这篇文章主要是介绍我之前的一个框架BackgroundLibrary,预览功能的实现。
相信很多人看过我之前的文章: 无需自定义View,彻底解放shape,selector吧 , 通过自定义标签去设置shape、selector的属性,省去了一大部分的shape.xml文件。
项目发布5个月,也累计了1500+的star,现在也基本稳定运行在各个项目中了。
问题
但是美中不足的是,虽然BackgroundLibrary这个库解决了繁琐的xml问题,确始终无法解决预览问题(下图所示),开发者只能直接在app中看到效果,无法在as中看到效果。这让我们开发的时候造成了一定的不便。
BackgroundLibrary原理是通过给原生控件添加自定义属性,然后在运行时期生成drawable,这样产生了shape、selector。而as是不会去编译代码的,这就导致了,在没有编译的时候编译器无法进行预览。
如何实现预览
Anko
首先我想到了一个同样类似原理的框架Anko,通过动态生成布局来提高app性能,它实现预览的方式是通过实现一个自定义预览插件,然后需要预览的时候,每次build一下项目,然后进行预览,显然这种方式和我们直接运行app没有太大的区别,而且开发插件的成本较高,不适合采用这种方法。
Android Studio编译器
那么as是如何实现view的预览的呢?
我们简单看一下TextView的源码:
而这种方法对于这个框架来说是可行的,因此为了方便大家可以预览,我同样实现了对应的自定义View。
效果及使用方法
效果
使用方法
1、如果需要对View进行预览,直接把原来的View换成框架内对应的BLView即可,即可展示预览效果,如果不需要预览可以直接忽略这些用于预览的自定义View;
2、如果没有效果,make project一下即可;
3、如果BLView中没有对应的需要预览的View,可以很简单的自己实现一下,以BLTextView为例:
public class BLTextView extends AppCompatTextView {
public BLTextView(Context context) {
super(context);
}
public BLTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public BLTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs){
BackgroundFactory.setViewBackground(context, attrs, this);
}
}
复制代码
继承所需要预览的View,然后在构造函数中添加BackgroundFactory.setViewBackground(context, attrs, this)方法即可。
注意:
为了提高性能,这些View在编译的时候会自动替换为对应原生的View,所以除了再xml中,不要在代码中出现任何的BLTextView,否则会报类似如下的错误:
//错误
BLTextView button = findViewById(R.id.text);
//正确
BLTextView button = findViewById(R.id.text);
Caused by: java.lang.ClassCastException: android.support.v7.widget.AppCompatTextView cannot be cast to com.noober.background.view.BLTextView
复制代码
总结
上面就是我实现思路的一个方式,只需一行代码setViewBackground去实现自定义View,来进行预览,并且在运行时替换自定义View,这样在开发的时候除了需要预览的情况,我们完全可以忽略这些自定义控件的存在,这对android sdk的升级改变都不会产生任何影响。欢迎大家提供更多的思路。