XML Shape/Selector → Kotlin 动态创建

XML Shape/Selector → Kotlin 动态创建

老写法(XML drawable)

res/drawable/bg_rounded_button.xml:

xml 复制代码
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#4CAF50"/>
    <corners android:radius="8dp"/>
    <stroke android:width="1dp" android:color="#388E3C"/>
</shape>

res/drawable/selector_button.xml:

xml 复制代码
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape>
            <solid android:color="#388E3C"/>
            <corners android:radius="8dp"/>
        </shape>
    </item>
    <item>
        <shape>
            <solid android:color="#4CAF50"/>
            <corners android:radius="8dp"/>
        </shape>
    </item>
</selector>

Java 中使用:

java 复制代码
view.setBackgroundResource(R.drawable.selector_button);

问题在哪里

XML drawable 有三个局限:颜色写死不能动态改、不同状态下要写多份 shape 重复代码、需要在 res/drawable 里维护一堆小文件。

新写法(Kotlin 动态创建)

kotlin 复制代码
fun roundedButtonBg(
    context: Context,
    normalColor: Int,
    pressedColor: Int,
    cornerRadiusDp: Int,
    strokeColor: Int,
    strokeWidthDp: Int = 1
): StateListDrawable {
    val density = context.resources.displayMetrics.density
    val radius = cornerRadiusDp * density
    val strokeWidth = strokeWidthDp * density

    val normal = GradientDrawable().apply {
        shape = GradientDrawable.RECTANGLE
        setColor(normalColor)
        cornerRadius = radius
        setStroke(strokeWidth.toInt(), strokeColor)
    }

    val pressed = GradientDrawable().apply {
        shape = GradientDrawable.RECTANGLE
        setColor(pressedColor)
        cornerRadius = radius
        setStroke(strokeWidth.toInt(), strokeColor)
    }

    return StateListDrawable().apply {
        addState(intArrayOf(android.R.attr.state_pressed), pressed)
        addState(intArrayOf(), normal)
    }
}

使用:

kotlin 复制代码
view.background = roundedButtonBg(
    context = context,
    normalColor = Color.parseColor("#4CAF50"),
    pressedColor = Color.parseColor("#388E3C"),
    cornerRadiusDp = 8,
    strokeColor = Color.parseColor("#388E3C")
)

一句话注意

GradientDrawable.cornerRadius 和 setStroke 的参数单位是像素,不是 dp。传 dp 值必须乘以 density,否则不同分辨率手机上圆角大小不一致。StateListDrawable.addState 的状态数组顺序很重要,越具体的状态(如 state_pressed)要放在前面,默认状态(空数组)放最后。


Java Android 老项目迁移系列,持续更新中。

相关推荐
古法老登瞎折腾7 小时前
大数据智能运维实战(十一):运维 MCP 的工程化——权限、限流、审计与错误处理
java·大数据·运维·spring ai·mcp
海水冷却7 小时前
Android 群组聊天怎么实现:基于 ZIM 的完整落地指南(附可运行 Demo)
android
智能运维指南8 小时前
研制过程“两张皮“怎么破:研制一体化支撑平台的定位、能力边界与落地前提
java·前端·人工智能·嘉为蓝鲸
yz_aiks8 小时前
Spring AI 2.1 ChatMemory 已过时用什么替代:迁移到 Session Memory 实战(JDBC 存储与会话压缩)
java·spring boot·大模型·ai agent·spring ai
金銀銅鐵9 小时前
[Java] 用 GUI 展示 EnumMap 增删键值对时的内部变化
java·后端·ai编程
学长毕设9 小时前
基于SpringBoot的上门洗车服务系统设计与实现
java·spring boot·后端
jason成都9 小时前
RTKLIB-Java 多基线联合RTK:FIX率从0%到91.5%的三层根因修复
java·gnss·rtklib·rtklib_java
鱼宵9 小时前
Stream 终端操作一次讲透:collect、count、reduce 怎么选
java·stream·终端操作
白山编程大哥9 小时前
Java 后端如何优雅地把 List 集合返回给前端
java·前端·list
Linux运维技术栈10 小时前
CVE-2026-91403 高危漏洞修复:Rocky Linux 9 多版本 JDK 环境清理实操
java·linux·运维