首页 > 其他分享 >Kotlin 风格,应该这样写drawable

Kotlin 风格,应该这样写drawable

时间:2023-08-22 11:37:51浏览次数:42  
标签:return shapeDrawable Kotlin ShapeBuilder shape 风格 build drawable

Kotlin 风格,应该这样写drawable_查看源码

前言

通常我们在res/drawable下面自定义shapeselector来满足一些UI的设计,但是由于xml最终转换为drawable需要经过IO或反射创建,会有一些性能损耗,另外随着项目的增大和模块化等,很多通用的样式并不能快速复用,需要合理的项目资源管理规范才能实施。那么通过代码直接创建这些drawable,可以在一定程度上降低这些副作用。本篇介绍用kotlin DSL简洁的语法特性来实现常见的drawable

代码对应效果预览

Kotlin 风格,应该这样写drawable_查看源码_02

Kotlin 风格,应该这样写drawable_封装_03

Kotlin 风格,应该这样写drawable_xml_04

Kotlin 风格,应该这样写drawable_查看源码_05

集成和使用

在项目级的build.gradle文件种添加仓库Jitpack:

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

添加依赖

dependencies {  
 implementation 'com.github.forJrking:DrawableDsl:0.0.3’
}

抛弃xml创建方式示例(其他参见demo)

// 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")
})

怎么去掉括号呢?

标签:return,shapeDrawable,Kotlin,ShapeBuilder,shape,风格,build,drawable
From: https://blog.51cto.com/u_16163452/7187510

相关文章

  • WPF实现Element UI风格的日期时间选择器
    背景业务开发过程中遇到一个日期范围选择的需求,和ElementUI的DateTimePicker组件比较类似,由两个日历控件组成,联动选择起始时间和结束时间。问题WPF中提供了一个DatePicker的控件,主要由DatePickerTextBox、Button和一个Calendar组成,其中Calendar是后台代码动态添加的,因此不能直......
  • kotlin协程异常处理之-CoroutineExceptionHandler
    转载请标明出处:https://www.cnblogs.com/tangZH/p/17307406.htmlkotlin协程小记协程的async使用kotlin协程异常处理之-trycatchkotlin协程异常处理之-CoroutineExceptionHandlerCoroutineExceptionHandler用于在协程中捕获异常。一、CoroutineExceptionHandler只能处......
  • Kotlin-大师班 第三章-随笔
    1.Kotlin中,不管是用val或是var声明的变量,都是不可为空的。想让变量可空,需要在声明语句的类型后面加个问号。 2.elvis运算符?:  当你要把一个nullable变量赋值给一个不可空变量时,使用该运算符。否则被赋值变量会被定义为可空变量。 3.doubleexclamation......
  • Kotlin-大师班 第二章-随笔
    1.AppCompatActicity.onCreate()每次Activity创建时调用。Activity对应一个屏幕,如果你的应用程序中有多个屏幕,如登录屏幕、客人资料等,所有这些都是不同的Activity。 可以理解为Activity对等于屏幕。2. setContentView设置View的内容。R代表Resources3.sp:......
  • 安卓kotlin的继续
    https://developer.android.google.cn/jetpack/compose/tutorial?hl=zh-cn#animate-messages-while-expandinghttps://gitee.com/createmaker/my_android_empty_compose_act1这几天请假办理个人事情,真想赶紧能找个合适的合伙人一起创业!......
  • 人与人之间的情感纽带:探索依恋风格
    引言当我第一次踏入人际关系的领域时,一个词汇深深吸引了我:依恋(Attachment)。这是一种无形的力量,将人们紧密相连,但又是何等复杂和微妙。在人类心灵的迷宫里,依恋是导航的指南针。就像孩子与母亲间的纽带,它引导我们走向彼此。通过深入探索依恋风格,我们可以更好地理解自己和他人,以及这......
  • Vuejs装饰器风格开发教程(计算属性、事件派发、侦听器)
    计算属性计算属性的设计背景:在Vuejs开发时我们可以在模板中通过编写表达式的方式做一系列的逻辑处理,但这就偏离的模板的概念,还会使得模板的内容变得臃肿且难以维护,所以引入了计算属性的来对不该出现在模板中的复杂逻辑处理进行重构,使用计算属性重构后的依然保持了状态的响应式......
  • 花点时间寻找适合自己的交易风格,优化利润——外汇110
    交易风格通常与交易者的个性相关。在选择交易策略和制定交易计划之前,对性格和生活方式进行内部反思非常重要 。这是因为使用与你的性格相反的交易风格会导致日后难以坚持你的交易计划。当交易者找到最适合他们的交易风格时,这种风格通常会持续很长时间。在交易中的表现取决于你如何......
  • 【腾讯云 Cloud Studio 实战训练营】在线 IDE 编写 canvas 转换黑白风格头像
    关于CloudStudioCloudStudio是基于浏览器的集成式开发环境(IDE),为开发者提供了一个永不间断的云端工作站。用户在使用CloudStudio时无需安装,随时随地打开浏览器就能在线编程。CloudStudio作为在线IDE,包含代码高亮、自动补全、Git集成、终端等IDE的基础功能,同时支持实......
  • Vuejs装饰器风格开发教程(前言、模板项目、类属性、类方法)
    教程前言AOP切面编程是面向对象开发中的一种经典的编程范式,旨在将横切关注点与核心业务逻辑分离来提高代码的模块性和可维护性。如:日志记录、事务管理等就属于横切关注点。在为H5提供Android原生支持时,曾将插件模块改造为AOP模式,实现插件的自动注册。Java领域的SpringBoo......