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

如何在RecyclerView中使用自定义FrameLayout及解决不支持的视图类型异常

异常根因

RecyclerView完全支持以FrameLayout作为item的根布局,和你报的异常没有任何关系。
你遇到的UnsupportedOperationException: Unsupported view type supplied本质是Adapter的视图类型逻辑写错了:

  • 报错的触发点是RecyclerView内部在获取ViewHolder时,传入了你在getItemViewType()方法里返回的int值(报错栈里的2131558525是典型的Android R资源id数值),但你的onCreateViewHolder()方法没有针对这个视图类型做对应处理,直接走到了方法末尾抛出异常的默认分支。
  • 最常见的错误写法就是:把布局资源的R.id值直接作为getItemViewType()的返回值,且没有在创建ViewHolder时匹配这个值加载对应布局。
正确实现「指定item点击后按钮隐藏、进度条显示」的方案

1. 修正Adapter的视图类型逻辑

如果你的RecyclerView所有item都是同一个带进度条、按钮的FrameLayout布局,根本不需要重写getItemViewType(),用默认的统一视图类型即可。
参考实现:

class ListAdapter(private val data: MutableList<ItemState>) : RecyclerView.Adapter<ListAdapter.ItemViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
        // 直接inflate你自定义的FrameLayout布局即可
        val itemView = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_with_loader_button, parent, false)
        return ItemViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        holder.bind(data[position])
    }

    override fun getItemCount() = data.size

    inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        private val progressBar: ProgressBar = view.findViewById(R.id.progress_loader)
        private val actionBtn: Button = view.findViewById(R.id.action_button)

        fun bind(state: ItemState) {
            // 根据数据状态控制View显示,避免复用错位
            progressBar.visibility = if (state.isLoading) View.VISIBLE else View.GONE
            actionBtn.visibility = if (state.isLoading) View.GONE else View.VISIBLE

            actionBtn.setOnClickListener {
                val currentPos = bindingAdapterPosition
                if (currentPos == RecyclerView.NO_POSITION) return@setOnClickListener
                
                // 修改对应位置的数据状态为加载中
                data[currentPos].isLoading = true
                // 定向刷新当前item,不要调用全量notifyDataSetChanged
                notifyItemChanged(currentPos)

                // 后续在此处插入你的实际异步加载逻辑,加载完成后将isLoading设为false,再次调用notifyItemChanged更新状态即可
            }
        }
    }

    // 对应的数据实体类,用来存每个item的加载状态
    data class ItemState(var isLoading: Boolean = false)
}

2. 修正原有布局的无效属性

你当前写的布局有两个属性失效,需要调整:

  • android:layout_centerInParent是RelativeLayout的专属属性,放在FrameLayout的子View上不会生效。要让ProgressBar在FrameLayout里居中,需要给ProgressBar加android:layout_gravity="center"。
  • 之前写的android:visibility="@{model.showSpinnerTrue}"存在数据绑定的类型不匹配问题:View的visibility接受int类型的枚举值,不直接接受布尔值。正确写法是android:visibility="@{model.showSpinnerTrue ? View.VISIBLE : View.GONE}",或者通过自定义BindingAdapter做布尔值到visibility的映射。
避坑提示
  • 绝对不要直接在View的点击事件里硬操作控件的显隐,RecyclerView的item是复用的,滑出屏幕再滑回时会出现状态错乱,所有UI状态都要跟着数据实体走,通过定向刷新绑定更新。
  • 如果你需要多种item视图类型,getItemViewType()要返回自定义的int常量(比如TYPE_NORMAL = 0、TYPE_LOADING = 1),不能直接把R布局资源id当视图类型返回,且要在onCreateViewHolder()里对每个返回的视图类型做对应布局加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 18:06:05