Android Nested RecyclerView

GitHub

效果: 可以上下滑動看到分類, 左右滑動可以看到細項

Let’s Start

Step-by-Step Implementation

Step1 : Create Model classes for each of the RecyclerViews

CourseModel

package com.sqtek.nestedrecyclerview.model

data class CourseModel (val imageId: Int)

MainModel

package com.sqtek.nestedrecyclerview.model

data class MainModel (
    val title: String,
    val courseModels: List<CourseModel>
    )

Step 2: Create FakeData class

SampleData

package com.sqtek.nestedrecyclerview.model

import com.sqtek.nestedrecyclerview.R

object SampleData {
    private val courseModels = listOf(
        CourseModel(R.drawable.course1),
        CourseModel(R.drawable.course2),
        CourseModel(R.drawable.course3),
        CourseModel(R.drawable.course4),
        CourseModel(R.drawable.course5),
        CourseModel(R.drawable.course6),
        CourseModel(R.drawable.course7),
        CourseModel(R.drawable.course8),
    )

    val collections = listOf(
        MainModel("All Course", courseModels),
        MainModel("Want to take", courseModels.reversed()),
        MainModel("Popular Course", courseModels.shuffled()),
        MainModel("Top Rated", courseModels),
    )
}

Step 3: Create RecyclerViews layout

Child layout (course_item.xml )

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <androidx.cardview.widget.CardView
        android:layout_width="150dp"
        android:layout_height="170dp"
        android:layout_margin="5dp"
        app:cardCornerRadius="5dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <ImageView
            android:id="@+id/imageViewBook"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="8dp"
            android:scaleType="centerCrop"/>
    </androidx.cardview.widget.CardView>

</androidx.constraintlayout.widget.ConstraintLayout>

Parent layout ( collection_item.xml )

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/textViewCollectionTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="8dp"
            android:text="@string/app_name"
            android:textSize="16sp"
            android:textStyle="bold"/>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerViewBooks"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:padding="8dp"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            tools:listitem="@layout/course_item"/>
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Step 4 : Working with Main Activity layout :

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerViewCollections"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        tools:listitem="@layout/collection_item" />
</androidx.constraintlayout.widget.ConstraintLayout>

Step 5: Create an Adapter class for each of the RecyclerViews

Data需要通過Adapter來傳遞資料顯示在 RecyclerView 視圖中。 ChildItem 和 ParentItem 都需要Adapter。

Child Adapter (CourseAdapter.kt)

package com.sqtek.nestedrecyclerview

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.sqtek.nestedrecyclerview.databinding.CourseItemBinding
import com.sqtek.nestedrecyclerview.model.CourseModel


class CourseAdapter (private val courseModels: List<CourseModel>):
        RecyclerView.Adapter<CourseAdapter.CourseViewHolder>() {

    inner class CourseViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
        val binding = CourseItemBinding.bind(itemView)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CourseViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.course_item, parent, false)
        return CourseViewHolder(view)
    }

    override fun onBindViewHolder(holder: CourseViewHolder, position: Int) {
        holder.binding.apply {
            imageViewBook.setImageResource(courseModels[position].imageId)
        }
    }

    override fun getItemCount(): Int {
        return courseModels.size
    }
}

Parent Adapter (MainAdapter.kt)

package com.sqtek.nestedrecyclerview

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.sqtek.nestedrecyclerview.databinding.CollectionItemBinding
import com.sqtek.nestedrecyclerview.model.MainModel
import com.sqtek.nestedrecyclerview.model.SampleData.collections

class MainAdapter(private val collection: List<MainModel>):
        RecyclerView.Adapter<MainAdapter.CollectionViewHolder>() {

    class CollectionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val binding = CollectionItemBinding.bind(itemView)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CollectionViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.collection_item, parent, false)
        return CollectionViewHolder(view)
    }

    override fun onBindViewHolder(holder: CollectionViewHolder, position: Int) {
        holder.binding.apply {
            val collection= collections[position]
            textViewCollectionTitle.text =collections[position].title
            val courseAdapter = CourseAdapter(collection.courseModels)
            recyclerViewBooks.adapter= courseAdapter
        }
    }

    override fun getItemCount(): Int {
        return collections.size
    }
}

Step 6: Working with MainActivity.kt

package com.sqtek.nestedrecyclerview

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.sqtek.nestedrecyclerview.databinding.ActivityMainBinding
import com.sqtek.nestedrecyclerview.model.SampleData

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.apply {
            recyclerViewCollections.adapter = MainAdapter(SampleData.collections)
        }
    }
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

購物車