如何用Kotlin实现带标题的横竖RecyclerView嵌套并支持整体上滑
实现带标题的双RecyclerView布局(顶部横向+下方纵向,整体滚动)
需求:
- 顶部添加带标题的横向滚动RecyclerView,使用
job_description_card_horizontal_scroll.xml作为卡片布局 - 保留原有纵向滚动RecyclerView
- 触摸纵向RecyclerView时,整个屏幕能向上滚动(解决嵌套ScrollView的滚动异常问题)
第一步:修改HomeFragment的布局文件
替换原有单独的纵向RecyclerView,改用NestedScrollView作为根布局,包裹标题、横向RecyclerView和纵向RecyclerView,避免普通ScrollView的滚动冲突:
<androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!-- 横向RecyclerView标题 --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="热门商家" android:textSize="18sp" android:textStyle="bold" android:padding="16dp"/> <!-- 顶部横向滚动RecyclerView --> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerViewHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingHorizontal="8dp" tools:listitem="@layout/job_description_card_horizontal_scroll"/> <!-- 纵向RecyclerView标题 --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="所有职位" android:textSize="18sp" android:textStyle="bold" android:padding="16dp"/> <!-- 原有纵向RecyclerView --> <androidx.recyclerview.widget.RecyclerView android:layout_gravity="center_horizontal" android:id="@+id/recyclerView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:nestedScrollingEnabled="false" <!-- 关键:禁用自身滚动,交给外层NestedScrollView --> tools:listitem="@layout/job_description_card_hori"/> </LinearLayout> </androidx.core.widget.NestedScrollView>
第二步:创建横向RecyclerView的适配器
复制现有MyAdapter,修改布局引用为横向卡片布局,命名为HorizontalJobAdapter:
class HorizontalJobAdapter(val context: Activity, val jobDetailsDataClass: List<job_details_data_class>) : RecyclerView.Adapter<HorizontalJobAdapter.MyViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { // 替换为横向卡片布局 val itemView = LayoutInflater.from(context).inflate(R.layout.job_description_card_horizontal_scroll, parent, false) return MyViewHolder(itemView) } override fun getItemCount(): Int { return jobDetailsDataClass.size } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val currentItem = jobDetailsDataClass[position] // 根据横向卡片的控件绑定数据,示例: holder.brand_name.text = currentItem.businessName holder.ratings.text = currentItem.ratings.toString() // 其他控件请根据你的横向布局自行添加 } class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { // 定义横向卡片内的控件,示例: val brand_name: TextView = itemView.findViewById(R.id.brand_name) val ratings: TextView = itemView.findViewById(R.id.ratings) val brand_image: ShapeableImageView = itemView.findViewById(R.id.brand_image) // 其他控件请根据你的横向布局自行添加 } }
第三步:修改HomeFragment.kt代码
在onViewCreated中添加横向RecyclerView的初始化,并确保Firebase数据更新时同时通知两个适配器:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) dataInitialized() // --- 原有筛选栏RecyclerView代码保持不变 --- val layoutManager= LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL, false) filterRecyclerView = view.findViewById(R.id.recyclerViewFilter) filterRecyclerView.layoutManager = layoutManager filterRecyclerView.setHasFixedSize(true) Sort_header_recycler_Adpater1= Sort_header_recycler_Adpater(sorts_list_array) filterRecyclerView.adapter = Sort_header_recycler_Adpater1 // --- 新增:初始化横向RecyclerView --- val jobsList = mutableListOf<job_details_data_class>() val horizontalRecyclerView = view.findViewById<RecyclerView>(R.id.recyclerViewHorizontal) val horizontalLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) horizontalRecyclerView.layoutManager = horizontalLayoutManager horizontalRecyclerView.setHasFixedSize(true) val horizontalAdapter = HorizontalJobAdapter(requireActivity(), jobsList) horizontalRecyclerView.adapter = horizontalAdapter // --- 原有纵向RecyclerView代码保持不变 --- recyclerView = view.findViewById(R.id.recyclerView) myAdapter = MyAdapter(requireActivity(), jobsList) recyclerView.adapter = myAdapter recyclerView.layoutManager = LinearLayoutManager(requireActivity()) // --- Firebase数据获取代码不变,仅添加横向适配器的更新通知 --- val databaseRef = FirebaseDatabase.getInstance().reference.child("user_business") databaseRef.addValueEventListener(object : ValueEventListener { @SuppressLint("NotifyDataSetChanged") override fun onDataChange(dataSnapshot: DataSnapshot) { jobsList.clear() for (userBusinessSnapshot in dataSnapshot.children) { // 原有数据解析代码直接复用 val businessName = userBusinessSnapshot.child("businessName").value.toString() val businessLogo = userBusinessSnapshot.child("businessLogo").value.toString() val address = userBusinessSnapshot.child("address").value.toString() val ratings = userBusinessSnapshot.child("ratings").value.toString().toDouble() val formattedRatings = if (ratings > 5.0) "5.0".toDouble() else ratings.toString().toDouble() val jobsSnapshot = userBusinessSnapshot.child("Jobs") for (jobSnapshot in jobsSnapshot.children) { val jobId = jobSnapshot.key.toString() val jobTitle = jobSnapshot.child("jobTitle").value.toString() val payPerHour = jobSnapshot.child("payPerHour").value.toString() val startTime = jobSnapshot.child("startTime").value.toString() val endTime = jobSnapshot.child("endTime").value.toString() val description = jobSnapshot.child("description").value.toString() val durationInSeconds = jobSnapshot.child("durationInSeconds").value.toString().toLong() val payPerDay = jobSnapshot.child("payPerDay").value.toString().toDouble() val job = job_details_data_class( businessName, address, businessLogo, formattedRatings, jobId, jobTitle, payPerHour, startTime, endTime, description, durationInSeconds, payPerDay ) jobsList.add(job) } } // 同时通知两个适配器更新数据 myAdapter.notifyDataSetChanged() horizontalAdapter.notifyDataSetChanged() } override fun onCancelled(error: DatabaseError) { Toast.makeText(activity, "unable to retrive data", Toast.LENGTH_LONG).show() } }) }
核心原理说明
- NestedScrollView替代普通ScrollView:专门解决滚动嵌套冲突,支持子View和父View的滚动事件协同处理
- 纵向RecyclerView禁用自身滚动:通过
android:nestedScrollingEnabled="false"让纵向RecyclerView把滚动事件交给外层的NestedScrollView,实现触摸纵向列表时整体屏幕滚动 - 横向RecyclerView无需特殊设置:水平滚动和NestedScrollView的垂直滚动方向不冲突,可正常独立滚动
内容的提问来源于stack exchange,提问作者Akhil Bhatnagar
相关产品推荐
相关产品推荐

