CtrlK
BlogDocsLog inGet started
Tessl Logo

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 时使用。

75

Quality

93%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Low

Low-risk findings worth noting

SKILL.md
Quality
Evals
Security

从源码生成 DataBinding BindingAdapter

模块路径(本地优先,与 viewtheme 共用锚点)

符号当前值(DevUtils)
DEVSIMPLE_ROOTlib/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

上游 fallback(仅工作区无模块时):https://github.com/afkT/DevUtils/tree/master/lib/DevSimple

必读搭配

生成或改写 方法体与文档 时,同时 Read 并遵守

本 Skill 负责 「是否该做 BindingAdapter、属性如何设计、时间戳与合并参数」;文档句式交给 code-method-normalize

风格对齐(执行要点)

  1. Read {BINDING_VIEW_DIR} 下与目标控件相关的 *.kt(至少一份同族文件 + 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

适合封装的正向例子removeAllViewsrequestLayoutsetText、滚动到某位置、设置可见性、设置图片资源等——参数为基本类型、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,以便区分「未绑定」与「显式关闭」)。
  • 适配器内统一约定:
    • nullreturn不修改 View(未提供 LiveData、或尚未赋值时保留 XML / 主题默认)。
    • true → 调用 开启 / 设置 API(如 TextViewUtils.setUnderlineText)。
    • false → 调用 关闭 / 移除 API(如 TextViewUtils.removeUnderlineText)。

§2 时间戳 的分工:

场景选用
需要 同步并保持 开/关状态,随 DataBinding 刷新更新 UIBoolean? 三态(本节)
无状态,每次都要 再触发一次 副作用(再次滚到底、再次清空)Long? 时间戳(§2)
工具类 仅有 set、无 remove,且 false 语义就是「不做事」Boolean?true 时执行;若业务要在布局里 关掉 已有效果,应补 remove 工具方法后改本节三态

禁止:底层已有 removeXxx 时仍写 if (flag != true) return,导致布局绑 false 无法撤销效果。

仓库参考实现TextView.bindingTVUnderlineTextView.bindingTVStrikeThru(见 {BINDING_VIEW_DIR}/TextView.kt,reference §优先范例)。

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 才执行。

本仓库已有:

fun Long?.qualifiesScroll(): Boolean = this != null && this > 0L

新代码若语义不是滚动(避免命名误导),可在同一模块抽取例如:

/** 数据绑定用:时间戳非空且大于 0 时执行一次副作用。 */
fun Long?.qualifiesBindingAction(): Boolean = this != null && this > 0L

具体命名与存放文件随模块惯例;禁止<=0null 仍执行(除非项目已有特例并在备注中写明)。


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_dyrequireAll = false)改为 binding_scroll_instant_rel_xy + XYI?(见用户提供的旧/新对照)。

5. 布局属性与 Kotlin 命名

  • XML:app:binding_snake_case@BindingAdaptervalue 与之一致。
  • Kotlin 扩展:fun View.bindingCamelCase(...),与文件内现有风格一致。
  • requireAll = false 仅当 确有独立缺省语义 时使用;能合并为实体类则优先合并。
  • 有返回值时:优先 Boolean 表示是否执行/成功,并满足 code-method-normalizeboolean/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.ktViewScroll.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

执行清单

  • 已 Read 本地 {BINDING_VIEW_DIR} 或 reference §优先范例,而非仅凭记忆写适配器。
  • 已对照 reference §DevSimple 前缀惯例,避免 binding_* 冲突。
  • 新 attribute 类落在 {BINDING_ATTR_DIR};成稿前已 Read code-method-normalize
Repository
afkT/DevUtils
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.