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

Android电商App:如何默认选中首个地址MaterialCardView

问题描述

开发电商App时,地址列表支持用户添加多个地址,每次操作需手动选择地址。每个地址有独立的address id标识选中项。需求是:当地址列表非空时,默认选中首个地址(位置0的MaterialCardView)。尝试初始化时将selectedAddressPos设为0,仅能显示选中状态,但无法获取对应的address id,地址数据存储在Firebase,无法通过XML设置默认选中。

解决方案

问题核心是仅设置了selectedAddressPos,但未同步更新lastCheckedAddress、lastCheckedCard等状态变量,也未触发选中后的逻辑(比如样式更新、通知外部选中的地址ID)。通过以下步骤修复:

  • 在Adapter初始化时同步默认选中的状态变量
  • 统一卡片样式设置逻辑,确保默认选中与手动选中的样式一致
  • 新增回调通知外部组件默认选中的地址ID
修改后的完整代码
import android.content.Context
import android.util.Log
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.card.MaterialCardView
import com.sbhs.stone.R
import com.sbhs.stone.data.UserData
import com.sbhs.stone.databinding.LayoutAddressCardBinding
import com.sbhs.stone.ui.getCompleteAddress

private const val TAG = "AddressAdapter"

class AddressAdapter(
    private val context: Context,
    addresses: List<UserData.Address>,
    private val isSelect: Boolean,
) :
    RecyclerView.Adapter<AddressAdapter.ViewHolder>() {

    lateinit var onClickListener: OnClickListener
    var data: List<UserData.Address> = addresses

    var lastCheckedAddress: String? = null
    private var lastCheckedCard: MaterialCardView? = null
    var selectedAddressPos = -1

    init {
        // 初始化默认选中首个地址(如果列表非空)
        if (data.isNotEmpty()) {
            selectedAddressPos = 0
            lastCheckedAddress = data[0].addressId
        }
    }

    inner class ViewHolder(private var binding: LayoutAddressCardBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(address: UserData.Address, position: Int) {
            val isSelected = position == selectedAddressPos
            binding.addressCard.isChecked = isSelected
            
            // 根据选中状态设置卡片样式
            updateCardStyle(binding.addressCard, isSelected)

            binding.addressPersonNameTv.text =
                context.getString(R.string.person_name, address.fName, address.lName)
            binding.addressCompleteAddressTv.text = getCompleteAddress(address)
            binding.addressMobileTv.text = address.phoneNumber
            
            if (isSelect) {
                binding.addressCard.setOnClickListener {
                    onCardClick(position, address.addressId, it as MaterialCardView)
                }
            }

            binding.addressEditBtn.setOnClickListener {
                onClickListener.onEditClick(address.addressId)
            }
            binding.addressDeleteBtn.setOnClickListener {
                onClickListener.onDeleteClick(address.addressId)
                notifyDataSetChanged()
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            LayoutAddressCardBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false
            )
        )
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(data[position], position)
        // 首次绑定默认选中项时,保存对应的卡片引用
        if (position == selectedAddressPos && lastCheckedCard == null) {
            lastCheckedCard = holder.binding.addressCard
            // 通知外部默认选中的地址
            onClickListener.onAddressSelected(data[position].addressId)
        }
    }

    override fun getItemCount(): Int = data.size

    interface OnClickListener {
        fun onEditClick(addressId: String)
        fun onDeleteClick(addressId: String)
        // 新增回调,通知外部选中的地址(包括默认选中)
        fun onAddressSelected(addressId: String)
    }

    private fun onCardClick(position: Int, addressId: String, card: MaterialCardView) {
        if (addressId != lastCheckedAddress) {
            updateCardStyle(card, true)
            lastCheckedCard?.let { updateCardStyle(it, false) }

            lastCheckedAddress = addressId
            lastCheckedCard = card
            selectedAddressPos = position
            
            // 通知外部选中的地址
            onClickListener.onAddressSelected(addressId)
            Log.d(TAG, "onCardClick: selected address = $addressId")
        }
    }

    // 统一更新卡片样式的方法
    private fun updateCardStyle(card: MaterialCardView, isSelected: Boolean) {
        card.apply {
            strokeColor = if (isSelected) {
                context.getColor(R.color.blue_accent_300)
            } else {
                context.getColor(R.color.light_gray)
            }
            isChecked = isSelected
            strokeWidth = TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP,
                if (isSelected) 2F else 1F,
                resources.displayMetrics
            ).toInt()
        }
    }
}
关键修改说明
  1. 初始化同步状态:在Adapter的init块中判断地址列表非空时,直接设置selectedAddressPos=0并赋值lastCheckedAddress,确保状态变量同步。
  2. 统一样式逻辑:提取updateCardStyle方法,避免重复代码,保证默认选中和手动选中的样式一致。
  3. 保存卡片引用:在onBindViewHolder中保存默认选中项的卡片引用,确保后续切换选中时能正确重置之前的样式。
  4. 新增选中回调:扩展OnClickListener添加onAddressSelected方法,在默认选中或手动选中时通知外部组件当前的地址ID,解决无法获取地址ID的问题。

内容的提问来源于stack exchange,提问作者kushal bardiya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 01:50:20