添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
You might come up with a different set of ideas to do it. But the most common idea to do this would be using RecyclerView with multiple view types inside one recyclerView. But with the above given the solution, the major problem comes up is managing a lot of view types. In the above example, we have three types of views, one with a container to contain name and description of the user, second is a list of user and third is a banner. But in a real-life example, there can be a lot of different views and not just three. So how can we design a view in an easy way without having to manage different view types? Concat Adapter is the solution for it. In this, let us understand the ConcatAdapter by building the above screen. Step 01. First, let us add the dependency required by the concat adapter. It is a part of recyclerView. In the app's build.gradle
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha04"
PS: The current build is in the alpha02 version. Step 02. For the above screen, we have three different types of Views. So, for that to structure the data we need to create three different data classes namely - User, MyDetail, Banner, inside the model package. Where User is used for structuring the data for a list of users. MyDetail is used for displaying the used for my user data and Banner is used for displaying the banner. looks like,
data class User(
     val id: Int = 0,
     val name: String = "",
     val avatar: String = ""
                    MyDetail
                  data class looks like,
                 
data class MyDetail(
     val id: Int = 0,
     val name: String = "",
     val aboutMe: String = ""
                    Banner
                  looks like,
                 
data class Banner(
     val bannerImage: Int = 0
                  Step 03:
                  In this, we will create a data source for a list of users to display the list. For that, we will create an object of
                    DataSource
                  and in that,
                 
object DataSource {
    fun getUser() = ArrayList<User>().apply {
        add(User(1, "Himanshu", "https://s3.amazonaws.com/uifaces/faces/twitter/sunlandictwin/128.jpg"))
        add(User(2, "Alford Hoeger", "https://s3.amazonaws.com/uifaces/faces/twitter/mufaddal_mw/128.jpg"))
        add(User(3, "Terrance Halvorson", "https://s3.amazonaws.com/uifaces/faces/twitter/mufaddal_mw/128.jpg"))
        add(User(3, "Morgan McGlynn", "https://s3.amazonaws.com/uifaces/faces/twitter/allfordesign/128.jpg"))
        add(User(4, "Ms. Ramiro DuBuque", "https://s3.amazonaws.com/uifaces/faces/twitter/shaneIxD/128.jpg"))
        add(User(5, "Kolby Orn", "https://s3.amazonaws.com/uifaces/faces/twitter/johnsmithagency/128.jpg"))
        add(User(6, "Elijah Schoen MD", "https://s3.amazonaws.com/uifaces/faces/twitter/alxndrustinov/128.jpg"))
    fun getBanner() = Banner(R.drawable.publication_site_cover)
                  Where
                   getUser
                  () will be used to get a list of User type, and
                   getBanner
                  () is used for getting the banner image from the drawable folder.
                  Step 04.
                  In RecyclerView, what happens is, Concat Adapter helps to display the RecyclerView Adapters in sequential order. So, now in our use-case first we will define three different adapters,
                  To display MyDetails, will create MyDetailAdapter,
                 
class MyDetailAdapter(
        private val myDetail: MyDetail
) : RecyclerView.Adapter<MyDetailAdapter.DataViewHolder>() {
    class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(user: MyDetail) {
            itemView.textViewUser.text = user.name
            itemView.textViewAboutMe.text = user.aboutMe
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
            DataViewHolder(
                    LayoutInflater.from(parent.context).inflate(
                            R.layout.item_layout_my_detail, parent,
                            false
    override fun getItemCount(): Int = 1
    override fun onBindViewHolder(holder: DataViewHolder, position: Int) =
            holder.bind(myDetail)
                  This adapter will be used for displaying MyUserDetails, basically the first section of the list. Where,
                   R.layout.item_layout_my_detail
                  looks like,
                 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/black"
    android:orientation="vertical"
    android:paddingStart="16dp"
    android:paddingTop="16dp"
    android:paddingEnd="16dp"
    android:paddingBottom="16dp">
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/textViewUser"
        style="@style/TextAppearance.AppCompat.Large"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@android:color/white"
        tools:text="MindOrks" />
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/textViewAboutMe"
        style="@style/TextAppearance.AppCompat.Small"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@android:color/darker_gray" />
</LinearLayout>
Then to display the list of user, we will create another adapter UsersAdapter,
class UsersAdapter(
        private val users: ArrayList<User>
) : RecyclerView.Adapter<UsersAdapter.DataViewHolder>() {
    class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(user: User) {
            itemView.textViewUserName.text = user.name
            Glide.with(itemView.imageViewAvatar.context)
                    .load(user.avatar)
                    .into(itemView.imageViewAvatar)
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
            DataViewHolder(
                    LayoutInflater.from(parent.context).inflate(
                            R.layout.item_layout, parent,
                            false
    override fun getItemCount(): Int = users.size
    override fun onBindViewHolder(holder: DataViewHolder, position: Int) =
            holder.bind(users[position])
                  This adapter will be used to display the list of the user, where
                   R.layout.item_layout
                  looks like,
                 
<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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="60dp">
    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/imageViewAvatar"
        android:layout_width="60dp"
        android:layout_height="0dp"
        android:padding="4dp"
        app:civ_border_color="@android:color/black"
        app:civ_border_width="2dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/textViewUserName"
        style="@style/TextAppearance.AppCompat.Large"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="4dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageViewAvatar"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        tools:text="MindOrks" />
</androidx.constraintlayout.widget.ConstraintLayout>
and at last, will create another Adapter to show the banner at the end of User's list. For that will create BannerAdapter , which looks like
class BannerAdapter(
        private val banner: Banner
) : RecyclerView.Adapter<BannerAdapter.DataViewHolder>() {
    class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(banner: Banner) {
            Glide.with(itemView.imageViewBanner.context)
                    .load(user.bannerImage)
                    .into(itemView.imageViewBanner)
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
            DataViewHolder(
                    LayoutInflater.from(parent.context).inflate(
                            R.layout.item_layout_banner, parent,
                            false
    override fun getItemCount(): Int = 1
    override fun onBindViewHolder(holder: DataViewHolder, position: Int) =
            holder.bind(banner)
                  and the
                   R.layout.item_layout_banner
                  looks like,
                 
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/imageViewBanner"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
Now, we are done designing three different types of adapters, which are responsible for displaying the three types of views in a recyclerView. Step05. Now, to use the adapters we create in ConcatAdapter, first, we will create an activity called MainActivity which will be our launcher activity as well.
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
                  Now, in the
                   R.layout.activity_main
                  , First, we will add a recyclerView. It will look like,
                 
<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/recyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Now, we will add four variables in MainActivity,
lateinit var adapter: ConcatAdapter
lateinit var myDetailAdapter: MyDetailAdapter
lateinit var userVerticalAdapter: UsersAdapter
lateinit var bannerAdapter: BannerAdapter
we will also create another variable which will be structured according to MyDetail data class and contain my details,
val myDetail = MyDetail(1, "Himanshu Singh", "I am an writer and Open Source contributor in MindOrks.")
                  and lastly, we will create, a function called,
                 
setupDataInRecyclerView()
and will call this in onCreate of Activity. Now, in the function, we will initialize the variables and set them to adapter
private fun setupDataInRecyclerView() {
    recyclerView.layoutManager = LinearLayoutManager(this)
    userVerticalAdapter = UsersAdapter(DataSource.getUser())
    bannerAdapter = BannerAdapter(DataSource.getBanner())
    myDetailAdapter = MyDetailAdapter(myDetail)
    adapter = ConcatAdapter(myDetailAdapter,  userVerticalAdapter,bannerAdapter)
    recyclerView.adapter = adapter
                  Here, we will initialize the adapters,
                   UserAdapter
                   BannerAdapter,
                   MyDetailAdapter
                  and pass the data from the
                   DataSource
                  object.
                  Now, we will initialize the layout manager for the recyclerView using,
                 
recyclerView.layoutManager = LinearLayoutManager(this) 
and, at last, we will create a ConcatAdapter and pass the adapters in its constructor. Note: The Sequence on which we will pass the adapter, the ConcatAdapter will draw the list in the same sequence in the recyclerView. And when we run the app, we will get the desired output on the screen. This is how you can design a recyclerView with multiple view types in sequential order by using data from individual adapters. Point to remember: For example, let us say that we need to use the same recyclerView adapter multiple times in a recyclerView, then we can create multiple instances for the same adapter and add it in the constructor of ConcatAdapter. We should implement the logic in individual adapters. When we update data in any adapter using the notifyDataSetChanged() then, concat adapter will also call its notifyDataSetChanged() In place of passing the adapters individually, we can pass the list of adapters in the constructor of ConcatAdapter. So, here in our example, we can create a list of adapter like,
val listOfAdapters = listOf<RecyclerView.Adapter<out RecyclerView.ViewHolder>>(myDetailAdapter, userVerticalAdapter, bannerAdapter)
and then in the constructor, we can pass like,
adapter = ConcatAdapter(listOfAdapters)
Now, let's talk about a use case In general, we basically use one view holder for one RecyclerView Adapter. But in some cases when we need to re-use the view holder for multiple adapters then, we need to pass a config in the constructor where we need to set the isolateViewTypes false To create a config we use,
val configBuilder = ConcatAdapter.Config.Builder()
configBuilder.setIsolateViewTypes(false)
and then in ConcatAdapter, we pass it like,
val adapter = ConcatAdapter(configBuilder.build(),myDetailAdapter, userVerticalAdapter, bannerAdapter)
Similarly, here as well we can pass the list of adapter like,
val adapter = ConcatAdapter(configBuilder.build(),listOfAdapters)
2. Let say, we don't want to pass the adapter in the constructor and want to add it later in the Concat Adapter. To add an adapter we use,
val adapter = ConcatAdapter(listOfAdapters)
adapter.addAdapter(bannerAdapter)
This will add the adapter at the last position in the list. Now, let's say that we want to add the adapter at a specific position then we will pass the position alongside it,
adapter.addAdapter(0,bannerAdapter)
Here, we have added an adapter at the position i.e the start of the list. Now, the recyclerView looks like,
adapter.removeAdapter(//adapter)
4. To get the number of items in the recyclerView combining all the adapters we use,
adapter.itemCount
5. To get the list of adapters added in Concat Adapter wee call,
adapter.adapters
This is how you can get started with ConcatAdapter and build a recyclerView with multiple different views. In this blog, we will learn how to use Bubbles in Android. Bubbles are a new feature introduced in the Beta version of Android Q. These are used to display notifications of any application over some other application and you can launch any activity by using these Bubbles, something like Facebook Messenger's app. In this blog, we will learn how to implement the Preferences Settings Screen in Android. Settings screen are used to change the functionality and behavior of a particular application without changing the system settings. For example, you can change the background of a particular application by using the Settings feature.