设备旋转后RecyclerView内容消失问题求助
问题根源
竖屏正常、旋转后卡片消失的核心原因是:在SportAdapter的onCreateViewHolder方法中,通过parent.measuredWidth / 3设置卡片宽度时,设备旋转后RecyclerView的父容器尚未完成测量流程,此时parent.measuredWidth的值为0,导致卡片宽度被设为0,因此虽然视图已创建,但无法显示。
解决方案
以下提供三种可靠的解决方式,按推荐优先级排序:
方案1:使用GridLayoutManager替代手动设置宽度
直接利用GridLayoutManager的横向布局+3列配置,自动分配每个卡片的宽度,无需手动计算,旋转后会自动适配新的屏幕宽度。
修改Activity中初始化LayoutManager的代码:
// 替换原LinearLayoutManager为GridLayoutManager val gridLayoutManager = GridLayoutManager(this, 3, LinearLayoutManager.HORIZONTAL, false) sportRV.layoutManager = gridLayoutManager
同时删除SportAdapter中onCreateViewHolder里设置宽度的代码:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.card_view, parent, false) // 删除原设置lp.width的代码 return ViewHolder(view) }
方案2:在Activity中计算宽度并传递给Adapter
在Activity中获取屏幕的有效宽度,将计算好的单张卡片宽度传递给Adapter,避免在Adapter中依赖未完成测量的父容器。
修改Activity代码:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_show_profile) sportRV = findViewById(R.id.idRVSport) // ...其他代码... val sportModelArrayList: ArrayList<SportModel> = ArrayList() sports.map { sportModelArrayList.add(SportModel(it)) } // 计算单张卡片的宽度:屏幕宽度的1/3 val screenWidth = resources.displayMetrics.widthPixels val itemWidth = screenWidth / 3 val linearLayoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false) sportRV.layoutManager = linearLayoutManager // 将itemWidth传入Adapter val sportAdapter = SportAdapter(this, sportModelArrayList, itemWidth) sportRV.adapter = sportAdapter }
修改SportAdapter的构造方法和onCreateViewHolder:
class SportAdapter( private val context: Context, sportModelArrayList: ArrayList<SportModel>, private val itemWidth: Int // 添加itemWidth参数 ) : RecyclerView.Adapter<SportAdapter.ViewHolder>() { private var sportModelArrayList: ArrayList<SportModel> override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.card_view, parent, false) val lp = view.layoutParams lp.width = itemWidth view.layoutParams = lp // 确保参数生效 return ViewHolder(view) } // ...其他方法不变... }
方案3:监听视图布局完成事件再设置宽度
在Adapter中通过ViewTreeObserver监听视图的布局完成事件,确保父容器测量完成后再设置卡片宽度。
修改SportAdapter的onCreateViewHolder:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.card_view, parent, false) view.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { // 移除监听,避免重复触发 view.viewTreeObserver.removeOnGlobalLayoutListener(this) val lp = view.layoutParams lp.width = parent.measuredWidth / 3 view.layoutParams = lp } }) return ViewHolder(view) }
额外布局优化建议
检查RecyclerView的布局参数,将layout_height从match_parent改为wrap_content,避免父容器(LinearLayout为wrap_content)出现高度计算异常:
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/idRVSport" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
内容的提问来源于stack exchange,提问作者Juan José Jaramillo

