You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 07:37:52