如何在自定义View中统一管理两种布局绑定对象以减少重复代码?
解决方案:统一Binding对象消除重复代码
1. 定义Binding接口(统一公共操作)
创建一个接口,声明两个布局中所有共用的控件和方法,让自动生成的Binding类实现该接口,以此实现统一引用:
interface LoyaltyStampBindingInterface { // 声明两个布局中共有的控件属性(根据你的实际控件ID调整) val ivStar: ImageView val tvCount: TextView // 声明共用的初始化/操作方法(按需添加) fun setupInitialState() }
2. 修改XML布局,绑定接口
在两个布局文件的根元素中添加class属性,指定实现上面的接口。Data Binding会自动让生成的Binding类实现该接口:
普通尺寸布局loyalty_stamp_view.xml示例:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" class="com.yourpackage.LoyaltyStampBindingInterface"> <!-- 绑定接口 --> <ImageView android:id="@+id/ivStar" android:layout_width="48dp" android:layout_height="48dp" /> <TextView android:id="@+id/tvCount" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
小型尺寸布局loyalty_stamp_view_small.xml做同样修改,添加相同的class属性绑定接口。
3. 重构自定义View代码
移除两个独立的Binding变量,改用统一的接口类型变量,根据变体仅初始化对应布局,所有操作通过统一变量完成:
class LoyaltyStampView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = 0 ) : LinearLayout(context, attrs, defStyle) { private lateinit var binding: LoyaltyStampBindingInterface private var stampVariant = LoyaltyCardView.LoyaltyCardVariant.NORMAL init { val typedArray = context.obtainStyledAttributes(attrs, R.styleable.LoyaltyStamp) try { val variant = typedArray.getInt(R.styleable.LoyaltyStamp_stamp_variant, 0) stampVariant = LoyaltyCardView.LoyaltyCardVariant.values()[variant] // 根据变体初始化对应Binding,仅加载当前需要的布局 binding = when(stampVariant) { LoyaltyCardView.LoyaltyCardVariant.NORMAL -> LoyaltyStampViewBinding.inflate(LayoutInflater.from(context), this, true) LoyaltyCardView.LoyaltyCardVariant.SMALL -> LoyaltyStampViewSmallBinding.inflate(LayoutInflater.from(context), this, true) } // 统一执行初始化逻辑,无需分支判断 binding.apply { ivStar.setColorFilter(ContextCompat.getColor(context, R.color.star_default)) setupInitialState() } } finally { typedArray.recycle() } } fun stampBag(stamp: Boolean) { // 统一操作控件,消除重复分支 binding.apply { ivStar.isSelected = stamp tvCount.text = if(stamp) "已完成" else "待盖章" } } private fun repositionStarRandomly() { // 直接通过统一Binding操作控件,无需区分变体 val starView = binding.ivStar val randomX = (0..(width - starView.width)).random() val randomY = (0..(height - starView.height)).random() starView.x = randomX.toFloat() starView.y = randomY.toFloat() } }
额外优化说明
原代码同时加载两个布局会导致冗余View被添加到容器中,重构后仅加载当前变体对应的布局,既节省资源又避免布局层级混乱。
内容的提问来源于stack exchange,提问作者Ambran
相关产品推荐
相关产品推荐

