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

如何将分组后的Map解构为RecyclerView所需的列表?

实现按国家分组的机场列表(适配RecyclerView)

核心思路

把分组后的Map<Country, List<Airport>>转换成单一扁平的混合列表,用多类型Adapter区分国家标题项和机场内容项,适配RecyclerView的展示需求。


步骤1:定义列表项类型

创建密封类区分两种列表项,让RecyclerView能识别不同类型的布局:

sealed class ListItem {
    data class CountryItem(val country: Country) : ListItem()
    data class AirportItem(val airport: Airport) : ListItem()
}

步骤2:转换分组数据为扁平列表

遍历分组后的Map,依次添加国家项和对应的机场项(可按需排序):

// 假设已通过groupBy得到分组结果:val groupedAirports: Map<Country, List<Airport>>
val flatListItemList = mutableListOf<ListItem>()

// 按国家名称排序,让列表更规整
groupedAirports.toSortedMap(compareBy { it.name }).forEach { (country, airports) ->
    flatListItemList.add(ListItem.CountryItem(country))
    // 按机场名称排序,优化展示顺序
    airports.sortedBy { it.name }.forEach { airport ->
        flatListItemList.add(ListItem.AirportItem(airport))
    }
}

步骤3:实现多类型RecyclerView Adapter

重写getItemViewType区分布局类型,创建对应的ViewHolder绑定数据:

class AirportListAdapter(private val items: List<ListItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    companion object {
        private const val VIEW_TYPE_COUNTRY = 0
        private const val VIEW_TYPE_AIRPORT = 1
    }

    override fun getItemViewType(position: Int): Int {
        return when (items[position]) {
            is ListItem.CountryItem -> VIEW_TYPE_COUNTRY
            is ListItem.AirportItem -> VIEW_TYPE_AIRPORT
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            VIEW_TYPE_COUNTRY -> {
                val view = inflater.inflate(R.layout.item_country, parent, false)
                CountryViewHolder(view)
            }
            else -> {
                val view = inflater.inflate(R.layout.item_airport, parent, false)
                AirportViewHolder(view)
            }
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (val item = items[position]) {
            is ListItem.CountryItem -> (holder as CountryViewHolder).bind(item.country)
            is ListItem.AirportItem -> (holder as AirportViewHolder).bind(item.airport)
        }
    }

    override fun getItemCount() = items.size

    // 国家项ViewHolder
    class CountryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(country: Country) {
            itemView.findViewById<TextView>(R.id.tv_country).text = country.name
            // 可添加样式调整,比如加粗背景色
        }
    }

    // 机场项ViewHolder
    class AirportViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(airport: Airport) {
            itemView.findViewById<TextView>(R.id.tv_airport_name).text = airport.name
            itemView.findViewById<TextView>(R.id.tv_airport_code).text = airport.code
            itemView.findViewById<TextView>(R.id.tv_city).text = airport.city.name
        }
    }
}

步骤4:创建对应布局文件

  • item_country.xml:用于展示国家标题,可设置加粗字体、灰色背景等区分样式
  • item_airport.xml:展示机场名称、代码、城市等详细信息,布局风格与标题项区分开

注意事项

  1. 确保Country类正确实现equals()和hashCode()(如果是数据类则默认实现),否则groupBy无法正确分组
  2. 可根据业务需求调整国家和机场的排序规则(比如按拼音、热门程度)
  3. 数据量大时,建议使用DiffUtil优化RecyclerView的更新性能,避免卡顿

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 22:48:50