如何实现带圆形图标的自定义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
相关产品推荐
相关产品推荐

