// infix用法用于去掉括号更加简洁,详细后面说明 image src shapeDrawable { //指定shape样式 shape(ShapeBuilder.Shape.RECTANGLE) //圆角,支持4个角单独设置 corner(20f) //solid 颜色 solid("#ABE2E3") //stroke 颜色,边框dp,虚线设置 stroke(R.color.white, 2f, 5f, 8f) } //按钮点击样式 btn.background = selectorDrawable { //默认样式 normal = shapeDrawable { corner(20f) gradient(90, R.color.F97794, R.color.C623AA2) } //点击效果 pressed = shapeDrawable { corner(20f) solid("#84232323") } }
实现思路
----
### xml如何转换成drawable
xml变成drawable,通过`android.graphics.drawable.DrawableInflater`这个类来IO解析标签创建,然后通过解析标签再设置属性:
//标签创建 private Drawable inflateFromTag(@NonNull String name) { switch (name) { case “selector”: return new StateListDrawable(); case “level-list”: return new LevelListDrawable(); case “layer-list”: return new LayerDrawable(); … case “color”: return new ColorDrawable(); case “shape”: return new GradientDrawable(); case “vector”: return new VectorDrawable(); … } } //反射创建 private Drawable inflateFromClass(@NonNull String className) { try { Constructor<? extends Drawable> constructor; synchronized (CONSTRUCTOR_MAP) { constructor = CONSTRUCTOR_MAP.get(className); if (constructor == null) { final Class<? extends Drawable> clazz = mClassLoader.loadClass(className).asSubclass(Drawable.class); constructor = clazz.getConstructor(); CONSTRUCTOR_MAP.put(className, constructor); } } return constructor.newInstance(); } catch (NoSuchMethodException e) { … }
### 代码实现
由于创建`shape`等需要设置各种属性来构建,比较符合[`build`设计模式](
),那我们首先封装`build`模式的`shapeBuilder`,这样做虽然代码比起直接使用`apply{}`要多,但是可以让纯`java`项目用起来很舒服,其他实现请查看源码:
class ShapeBuilder : DrawableBuilder { private var mRadius = 0f private var mWidth = 0f private var mHeight = 0f … private var mShape = GradientDrawable.RECTANGLE private var mSolidColor = 0
/**分别设置四个角的圆角*/
fun corner(leftTop: Float,rightTop: Float,leftBottom: Float,rightBottom: Float): ShapeBuilder {
....if(dp)dp2px(leftTop) else leftTop
return this
}
fun solid(@ColorRes colorId: Int): ShapeBuilder {
mSolidColor = ContextCompat.getColor(context, colorId)
return this
}
// 省略其他参数设置方法 详细代码查看源码
override fun build(): Drawable {
val gradientDrawable = GradientDrawable()
gradientDrawable = GradientDrawable()
gradientDrawable.setColor(mSolidColor)
gradientDrawable.shape = mShape
....其他参数设置
return gradientDrawable
}
}
### 把build模式转换为dsl
理论上所有的build模式都可以轻松转换为dsl写法:
inline fun shapeDrawable(builder: ShapeBuilder.() -> Unit): Drawable { return ShapeBuilder().also(builder).build() } //使用方法 val drawable = shapeDrawable{ … }
备注:dsl用法参见[juejin.cn/post/695318…](
) 中dsl小节
### 函数去括号
通过上面封装已经实现了dsl的写法,通常`setBackground`可以通过`setter`简化,但是我发现由于有些api设计还需要加括号,这样不太kotlin:
//容易阅读 iv1.background = shapeDrawable { shape(ShapeBuilder.Shape.RECTANGLE) solid("#ABE2E3") } //多了括号看起来不舒服 iv2.setImageDrawable(shapeDrawable { solid("#84232323") })
怎么去掉括号呢?🈶2种方式`infix函数`(中缀表达)和`property setter`
1. `infix函数`特点和规范:
* Kotlin允许在不使用`括号`和点号的情况下调用函数
* 必须只有一个参数
* 必须是成员函数或扩展函数
* 不支持可变参数和带默认值参数
# **总结**
最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,**从来都是我们去适应环境,而不是环境来适应我们!**
这里附上上述的技术体系图相关的几十套**腾讯、头条、阿里、美团等公司20年的面试题**,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含**知识脉络 + 诸多细节**,由于篇幅有限,这里以图片的形式给大家展示一部分。
**相信它会给大家带来很多收获:**
![](https://img-blog.csdnimg.cn/img_convert/bf35b9ea6baec659732d0617f84cbfa7.png)
![](https://img-blog.csdnimg.cn/img_convert/ddfa88f9fe9202e0daea76ce9be2af80.png)
> 本文在**[CodeChina开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》](https://codechina.csdn.net/m0_60958482/android_p7)**中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中...
> 当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中...
> 当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
|