如何使用DataBinding查找GridLayout中带tag的目标View
问题背景
需要将GridLayout内通过tag匹配查找View的传统视图查找逻辑,迁移为纯DataBinding实现,原有可正常运行的代码如下:
val layout: GridLayout = binding.quickCommandGridLayout val view: CardView = layout.findViewWithTag(name.toString()) val tileLayout: CardView = view.findViewById(R.id.tileLayout)
已知GridLayout内的子View都提前设置了tag用于定位,要求替换findViewWithTag、findViewById调用,和项目全量DataBinding的代码风格保持一致。
实现方案
方案1:子项绑定映射表(优先选用,完全贴合DataBinding设计思路)
放弃依赖tag做运行时视图遍历查找的思路,在GridLayout填充子项的阶段,直接把每个子项的绑定实例和对应的匹配key(也就是原来设置tag用的name值)存在Map里,后续需要用的时候直接通过key取绑定对象即可,没有额外的遍历开销。
- 先给GridLayout的每个子项对应的布局开启DataBinding,子项布局内部的
tileLayout设置好id,DataBinding会自动生成对应的访问属性,不需要手动调用findViewById。 - 在填充GridLayout子项的逻辑里,维护一个绑定映射表:
// key为原来匹配用的name值,value为对应子项的Binding实例 private val gridItemBindings = mutableMapOf<String, GridItemBinding>() // 每添加一个子项,就把绑定实例存入映射表 private fun addGridChild(itemName: String) { val itemBinding = GridItemBinding.inflate(layoutInflater, binding.quickCommandGridLayout, false) gridItemBindings[itemName] = itemBinding binding.quickCommandGridLayout.addView(itemBinding.root) } - 需要获取目标
tileLayout时,直接从映射表取对应绑定实例访问即可:val tileLayout = gridItemBindings[name.toString()]?.tileLayout ?: error("不存在对应名称的子项:$name")
这个方案性能最好,没有运行时遍历View树的开销,代码风格和DataBinding完全统一。
方案2:绑定实例关联tag(改动量最小,兼容现有tag逻辑)
如果暂时不想调整现有子项填充的逻辑,可以保留现有tag设置的逻辑,只需要把findViewById的部分替换为DataBinding绑定实例访问即可,改动成本极低。
- 给子项布局开启DataBinding,根节点CardView的tag继续用原有逻辑赋值,保证
findViewWithTag可以正常匹配。 - 找到带目标tag的根View后,直接通过DataBinding工具类拿到对应的子项绑定实例,直接访问内部的
tileLayout属性:val targetRoot: CardView = binding.quickCommandGridLayout.findViewWithTag(name.toString()) val itemBinding = DataBindingUtil.getBinding<GridItemBinding>(targetRoot)!! val tileLayout: CardView = itemBinding.tileLayout
这个方案只需要给子项布局开启DataBinding,不需要改动现有子项添加、tag设置的逻辑,几行代码就能完成迁移。
注意事项
- 不要为了完全去掉
findViewWithTag强行写自定义BindingAdapter做View树遍历,本质和原有逻辑没有差异,反而会增加不必要的代码复杂度。 - 如果当前网格布局实际是用RecyclerView + GridLayoutManager实现,而非原生GridLayout,直接配合DataBinding实现的ListAdapter使用即可,ViewHolder会直接持有子项绑定实例,不需要额外维护映射表。
内容的提问来源于stack exchange,提问作者Seb
相关产品推荐
相关产品推荐

