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

如何实现带圆形图标的自定义Spinner下拉选择项?

实现步骤

1. 新建单选状态选择器(替代两个ImageView的切换逻辑)

在res/drawable目录下新建selector_spinner_radio.xml,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_oval_selected" android:state_selected="true" />
    <item android:drawable="@drawable/ic_oval_unselected" />
</selector>

2. 简化自定义Spinner项布局

把原来的两个ImageView合并为一个,减少不必要的视图开销,修改后的custom_spinner_layout.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:paddingVertical="12dp"
    android:paddingStart="17dp">

    <ImageView
        android:id="@+id/imgRadio"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/selector_spinner_radio"/>

    <TextView
        android:id="@+id/txtSpnPoolName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:text="Pool"
        android:textSize="@dimen/font_size_2"
        android:fontFamily="@font/averta_semibold"/>
</LinearLayout>

这里直接去掉了冗余的ConstraintLayout嵌套,用LinearLayout就足够满足布局需求

3. 优化适配器,加入ViewHolder复用和状态绑定

修改PoolNameAdapter代码,新增ViewHolder模式提升性能,同时绑定选中状态:

class PoolNameAdapter(var context: Context, var countryNames: MutableList<MockPoolName>) : BaseAdapter() {
    // ViewHolder复用视图
    inner class ViewHolder(itemView: View) {
        val imgRadio: ImageView = itemView.findViewById(R.id.imgRadio)
        val txtName: TextView = itemView.findViewById(R.id.txtSpnPoolName)
    }

    override fun getCount(): Int = countryNames.size

    override fun getItem(i: Int): Any = countryNames[i]

    // 修正getItemId返回对应位置id,避免后续逻辑异常
    override fun getItemId(i: Int): Long = i.toLong()

    override fun getView(i: Int, convertView: View?, viewGroup: ViewGroup): View {
        val view: View
        val viewHolder: ViewHolder
        if (convertView == null) {
            view = LayoutInflater.from(context).inflate(R.layout.custom_spinner_layout, viewGroup, false)
            viewHolder = ViewHolder(view)
            view.tag = viewHolder
        } else {
            view = convertView
            viewHolder = view.tag as ViewHolder
        }
        val currentItem = countryNames[i]
        viewHolder.txtName.text = currentItem.name
        // 绑定选中状态,自动切换选择器显示
        viewHolder.imgRadio.isSelected = currentItem.isSelected
        return view
    }
}

4. 给Spinner添加选中监听,同步选中状态

在Spinner初始化的位置添加选中监听,修改选中项的状态后刷新适配器:

poolNameAdapter = PoolNameAdapter(context!!, mockPoolList)
sp_pools.adapter = poolNameAdapter

// 新增选中监听
sp_pools.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
    override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
        // 先把所有项的选中状态重置为false
        mockPoolList.forEach { it.isSelected = false }
        // 把当前选中的项状态设为true
        mockPoolList[position].isSelected = true
        // 刷新适配器更新UI
        poolNameAdapter.notifyDataSetChanged()
    }

    override fun onNothingSelected(parent: AdapterView<*>?) {
        // 不需要处理的话留空即可
    }
}

补充说明

如果需要下拉弹窗和关闭状态的Spinner显示样式一致,可以重写适配器的getDropDownView方法,逻辑和getView完全一致即可。

内容的提问来源于stack exchange,提问作者Alejandro Vargas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 20:09:03