Skip to main content

project-binding-adapter-from-source

根据用户给出的 Java/Kotlin 工具类或 View 相关源码,设计并实现 androidx.databinding.BindingAdapter。 工作区内优先 Read lib/DevSimple 下 bindingadapters;范例文件表见 references/reference.md。 过滤不适合 XML 的 API;Long? 时间戳、Boolean? 三态、attribute 合并(参照 XYI);成稿按 code-method-normalize。 在用户要求生成 BindingAdapter、补全 DataBinding 属性、或评审 DevSimple bindingadapters 时使用。

Source facts

Repository
afkT/DevUtils
Last source activity
June 27, 2026 at 19:12
Detected SKILL.md language
Chinese
Stars
1,613
Forks
315

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
project-binding-adapter-from-source
description
根据用户给出的 Java/Kotlin 工具类或 View 相关源码,设计并实现 androidx.databinding.BindingAdapter。 工作区内优先 Read lib/DevSimple 下 bindingadapters;范例文件表见 references/reference.md。 过滤不适合 XML 的 API;Long? 时间戳、Boolean? 三态、attribute 合并(参照 XYI);成稿按 code-method-normalize。 在用户要求生成 BindingAdapter、补全 DataBinding 属性、或评审 DevSimple bindingadapters 时使用。
# 从源码生成 DataBinding BindingAdapter ## 模块路径(本地优先,与 viewtheme 共用锚点) | 符号 | 当前值(DevUtils) | |------|-------------------| | `DEVSIMPLE_ROOT` | `lib/DevSimple` | | `BINDING_VIEW_DIR` | `{DEVSIMPLE_ROOT}/src/main/java/dev/simple/bindingadapters/view` | | `BINDING_ATTR_DIR` | `{DEVSIMPLE_ROOT}/src/main/java/dev/simple/bindingadapters/view/attribute` | 存在 `{DEVSIMPLE_ROOT}` 时 **Read 本地 `*.kt`**,勿用 WebFetch 代替。生成前在 `{BINDING_VIEW_DIR}` 下列出并对照现有实现;**优先范例文件名、前缀惯例、判定表** → [references/reference.md](references/reference.md)。 **上游 fallback**(仅工作区无模块时):https://github.com/afkT/DevUtils/tree/master/lib/DevSimple ## 必读搭配 生成或改写 **方法体与文档** 时,**同时 Read 并遵守**: - [code-method-normalize/SKILL.md](../code-method-normalize/SKILL.md)(JavaDoc/KDoc、`<pre>`、首段规则、`@param`/`@return`、`boolean` 对举、异常内消化等) 本 Skill 负责 **「是否该做 BindingAdapter、属性如何设计、时间戳与合并参数」**;文档句式交给 **code-method-normalize**。 ## 风格对齐(执行要点) 1. **Read** `{BINDING_VIEW_DIR}` 下与目标控件相关的 `*.kt`(至少一份同族文件 + [references/reference.md §优先范例](references/reference.md#优先范例文件按主题选读) 中对应行)。 2. 合并参数实体放在 `{BINDING_ATTR_DIR}`;`XYI` 等写法对照同目录 `XYI.kt`。 3. 文件头「不适合 BindingAdapter」的说明以 **`View.kt`** 为准(路径见 reference)。 --- ## 1. 核心门槛:方法是否适合 BindingAdapter + XML BindingAdapter 绑定在 **布局里的单个 View 节点**;只封装 **对该接收者 View(及合理子类型)有意义、且能在 XML 表达参数** 的操作。 **应跳过或不要求用户封装**(与 `View.kt` 文件头说明一致)的典型类别: - 需要 **LayoutInflater / 非当前节点上下文** 的:`inflate` 等 - 返回 **Activity / Fragment / 任意非 View** 且无法在绑定中作为稳定入参的:`getActivity` 等 - 依赖 **任意子下标访问**、且语义不属于「当前节点自身配置」的:`getChildAt` 等(除非业务明确绑定的是容器且参数是 index,再按列表类控件单独设计) - **ViewGroup 结构转换** 等与当前节点单次属性语义不符的:`convertViewGroup` 等 **适合封装的正向例子**:`removeAllViews`、`requestLayout`、`setText`、滚动到某位置、设置可见性、设置图片资源等——参数为基本类型、`String`、Drawable、`XYI` 等可在 Binding / LiveData 中传递的类型。 若某方法 **仅 `View`/`TextView`/… 一个参数**,除「纯状态同步」(如设置某个由 XML 已绑定的 bool)外,**重复触发**(同值不刷新)往往成问题 → 见第 2 节 **时间戳**。 --- ## 2. 仅 View(接收者)型副作用:`Long?` 时间戳触发 当底层 API 形如 `FooUtils.action(view)` **仅有当前接收者、无业务参数**,又需要在 MVVM 里 **多次触发同一逻辑**(例如再次滑到底、再次清空)时: - **唯一绑定入参** 使用 `timestamp: Long?`(或与其它参数组合时,时间戳作为触发列之一) - 在适配器开头使用 **与项目一致的正时间戳判断**(见第 3 节) - 在 KDoc `<pre>` 中写明:建议绑定 `System.currentTimeMillis()` 或 ViewModel 内递增时间戳;**优于** `LiveData<Boolean>` 固定 `true` 不二次刷新 **成对语义(示例)**:已有 `EditTextUtils.setText(view, text)` 对应「设文本」;可另增 **「清空文本」** 适配器,入参仅为 `timestamp: Long?`,内部在通过校验后调用 `EditTextUtils.setText(view, "")`(或项目等价 API)。文档中说明与 `binding_et_text` 等的关系,避免重复绑定冲突。 --- ## 2.5 Boolean 三态开关(开启 / 关闭 / 不修改) 当底层工具类提供 **成对的 set / remove**(或语义等价的 enable / disable)API,且布局需要绑定 **可切换、可保持的 View 效果**(下划线、删除线、`paintFlags` 装饰、部分可见性样式等)时: - 绑定入参使用 **`Boolean?`**(不用非空 `Boolean`,以便区分「未绑定」与「显式关闭」)。 - 适配器内统一约定: - **`null`** → `return`,**不修改** View(未提供 LiveData、或尚未赋值时保留 XML / 主题默认)。 - **`true`** → 调用 **开启 / 设置** API(如 `TextViewUtils.setUnderlineText`)。 - **`false`** → 调用 **关闭 / 移除** API(如 `TextViewUtils.removeUnderlineText`)。 与 **§2 时间戳** 的分工: | 场景 | 选用 | |------|------| | 需要 **同步并保持** 开/关状态,随 DataBinding 刷新更新 UI | **`Boolean?` 三态**(本节) | | **无状态**,每次都要 **再触发一次** 副作用(再次滚到底、再次清空) | **`Long?` 时间戳**(§2) | | 工具类 **仅有 set、无 remove**,且 `false` 语义就是「不做事」 | 可 `Boolean?` 仅 `true` 时执行;若业务要在布局里 **关掉** 已有效果,应补 remove 工具方法后改本节三态 | **禁止**:底层已有 `removeXxx` 时仍写 `if (flag != true) return`,导致布局绑 `false` 无法撤销效果。 **仓库参考实现**:`TextView.bindingTVUnderline`、`TextView.bindingTVStrikeThru`(见 `{BINDING_VIEW_DIR}/TextView.kt`,reference §优先范例)。 ```kotlin fun TextView.bindingTVUnderline( underline: Boolean?, antiAlias: Boolean?, ) { if (underline == null) return if (underline) { TextViewUtils.setUnderlineText(this, antiAlias ?: true) } else { TextViewUtils.removeUnderlineText(this) } } ``` - 可选第二参数(如 `antiAlias`)仅在 **`true` 开启分支** 使用;`requireAll = false` 时缺省与工具类一致。 - KDoc `<pre>` 中写明三态与对应的 `set*` / `remove*` 工具方法名。 --- ## 3. 时间戳判定:可复用扩展 逻辑统一为:**非 null 且大于 0** 才执行。 本仓库已有: ```kotlin fun Long?.qualifiesScroll(): Boolean = this != null && this > 0L ``` **新代码**若语义不是滚动(避免命名误导),可在同一模块抽取例如: ```kotlin /** 数据绑定用:时间戳非空且大于 0 时执行一次副作用。 */ fun Long?.qualifiesBindingAction(): Boolean = this != null && this > 0L ``` 具体命名与存放文件随模块惯例;**禁止**用 `<=0` 或 `null` 仍执行(除非项目已有特例并在备注中写明)。 --- ## 4. 多参数合并为实体类(减少绑定次数与属性数量) **避免** 多个密切相关、应同事务触发的量拆成多个 `binding_*`,导致 **多次调用适配器**、LiveData 数量膨胀。 做法: 1. 在 `dev.simple.bindingadapters.view.attribute`(即 `{BINDING_ATTR_DIR}`,或用户指定包的 `attribute` 子包)新增 **Kotlin data class / open class**,字段覆盖原工具方法参数(含可选默认值)。 2. **单个** `@BindingAdapter("binding_…_single_snake_name")`,入参为该类型可空;`null` 时跳过。 3. 命名与 **XYI** 对齐习惯:简短后缀表意(如位移用 `XYI`);补充 `equals`/`hashCode`(data class 自带)、`toString`、伴生工厂方法视需要。 4. 迁移示例:由 `binding_scroll_instant_rel_dx` + `binding_scroll_instant_rel_dy`(`requireAll = false`)改为 **`binding_scroll_instant_rel_xy`** + `XYI?`(见用户提供的旧/新对照)。 --- ## 5. 布局属性与 Kotlin 命名 - XML:`app:binding_snake_case`;`@BindingAdapter` 的 `value` 与之一致。 - Kotlin 扩展:`fun View.bindingCamelCase(...)`,与文件内现有风格一致。 - `requireAll = false` 仅当 **确有独立缺省语义** 时使用;能合并为实体类则优先合并。 - 有返回值时:优先 `Boolean` 表示是否执行/成功,并满足 **code-method-normalize** 中 `boolean`/`Boolean` 的 `@return` 写法。 --- ## 6. 生成工作流(Agent 执行顺序) 1. **Read** 用户给出的源文件,列出候选 `public`/`internal` 方法。 2. **过滤** 第 1 节不适配 XML 的 API。 3. 对每个保留方法:**映射接收者类型**(`View` / `TextView` / `ImageView` / `ViewGroup` / `RecyclerView` 等)、**参数拆分或合并**(第 4 节)、**是否需要时间戳**(第 2 节)或 **Boolean 三态开关**(第 2.5 节)。 4. 落文件:新适配器写入 `{BINDING_VIEW_DIR}/`(按控件分文件,与现有 `TextView.kt`、`ViewScroll.kt` 等并列);attribute 类写入 `{BINDING_ATTR_DIR}/`。 5. **Read** `code-method-normalize` 并整理文档与返回类型。 6. 自检:`@BindingAdapter` 不与 `{BINDING_VIEW_DIR}` 内已有属性名冲突;`try/catch` 与日志风格参照 reference 中 **TextView** / **ImageViewLoadNative** 范例。 判定表、XML 示例、`binding_*` 前缀表见 [references/reference.md](references/reference.md)。 ## 执行清单 - [ ] 已 Read 本地 `{BINDING_VIEW_DIR}` 或 reference §优先范例,而非仅凭记忆写适配器。 - [ ] 已对照 reference §DevSimple 前缀惯例,避免 `binding_*` 冲突。 - [ ] 新 attribute 类落在 `{BINDING_ATTR_DIR}`;成稿前已 Read `code-method-normalize`。
View on GitHub