Convert Figma logo to code with AI

drakeet logoMultiType

Flexible multiple types for Android RecyclerView.

5,764
749
5,764
12

Top Related Projects

8,494

Epoxy is an Android library for building complex screens in a RecyclerView

"Favor composition over inheritance" for RecyclerView Adapters

The bullet proof, fast and easy to use adapter library, which minimizes developing time to a fraction...

An Adapter that allows a RecyclerView to be split into Sections with headers and/or footers. Each Section can have its state controlled individually.

Fast and versatile Adapter for RecyclerView which regroups several features into one library to considerably improve the user experience :-)

Migrated:

Quick Overview

MultiType is an Android library that simplifies the development of RecyclerViews with multiple item types. It provides a flexible and type-safe way to handle different view types in a single adapter, reducing boilerplate code and improving maintainability.

Pros

  • Type-safe and flexible approach to handling multiple view types
  • Reduces boilerplate code and simplifies adapter implementation
  • Supports easy addition and removal of item types
  • Promotes separation of concerns and modular design

Cons

  • Learning curve for developers new to the concept
  • May be overkill for simple RecyclerViews with few item types
  • Requires careful management of item types to avoid conflicts
  • Limited built-in support for DiffUtil (though can be implemented manually)

Code Examples

  1. Defining an ItemViewBinder:
class TextItemViewBinder : ItemViewBinder<TextItem, TextItemViewBinder.ViewHolder>() {
    override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder {
        return ViewHolder(inflater.inflate(R.layout.item_text, parent, false))
    }

    override fun onBindViewHolder(holder: ViewHolder, item: TextItem) {
        holder.textView.text = item.text
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val textView: TextView = itemView.findViewById(R.id.text)
    }
}
  1. Registering item types in the adapter:
val adapter = MultiTypeAdapter()
adapter.register(TextItem::class.java, TextItemViewBinder())
adapter.register(ImageItem::class.java, ImageItemViewBinder())
  1. Setting up the RecyclerView:
val recyclerView: RecyclerView = findViewById(R.id.recycler_view)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)

val items = listOf(TextItem("Hello"), ImageItem(R.drawable.image), TextItem("World"))
adapter.items = items
adapter.notifyDataSetChanged()

Getting Started

  1. Add the dependency to your build.gradle file:
dependencies {
    implementation 'com.drakeet.multitype:multitype:4.3.0'
}
  1. Create your item classes and corresponding ItemViewBinder classes.

  2. In your activity or fragment, set up the MultiTypeAdapter:

val adapter = MultiTypeAdapter()
adapter.register(YourItem::class.java, YourItemViewBinder())
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)

// Add items to the adapter
adapter.items = yourItemsList
adapter.notifyDataSetChanged()

Competitor Comparisons

8,494

Epoxy is an Android library for building complex screens in a RecyclerView

Pros of Epoxy

  • More comprehensive feature set, including view holders, data binding, and animations
  • Better support for complex layouts and nested RecyclerViews
  • Stronger type safety with generated models

Cons of Epoxy

  • Steeper learning curve due to more complex API
  • Requires annotation processing, which can increase build times
  • Heavier dependency compared to MultiType's lightweight approach

Code Comparison

MultiType:

class TextItemViewBinder : ItemViewBinder<String, TextItemViewBinder.ViewHolder>() {
    override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder {
        return ViewHolder(inflater.inflate(R.layout.item_text, parent, false))
    }
    override fun onBindViewHolder(holder: ViewHolder, item: String) {
        holder.textView.text = item
    }
    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val textView: TextView = itemView.findViewById(R.id.text)
    }
}

Epoxy:

@EpoxyModelClass(layout = R.layout.item_text)
abstract class TextItemModel : EpoxyModelWithHolder<TextItemModel.Holder>() {
    @EpoxyAttribute lateinit var text: String
    override fun bind(holder: Holder) {
        holder.textView.text = text
    }
    class Holder : EpoxyHolder() {
        lateinit var textView: TextView
        override fun bindView(itemView: View) {
            textView = itemView.findViewById(R.id.text)
        }
    }
}

"Favor composition over inheritance" for RecyclerView Adapters

Pros of AdapterDelegates

  • More flexible delegation system, allowing for easier composition of complex adapters
  • Better support for inheritance and subclassing of delegate types
  • Cleaner separation of concerns between item types and their corresponding views

Cons of AdapterDelegates

  • Slightly more verbose implementation, requiring more boilerplate code
  • Less intuitive for simpler use cases with fewer item types
  • Steeper learning curve for developers new to the delegate pattern

Code Comparison

MultiType:

class TextItemViewBinder : ItemViewBinder<TextItem, TextItemViewBinder.ViewHolder>() {
    override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder {
        return ViewHolder(inflater.inflate(R.layout.item_text, parent, false))
    }
    override fun onBindViewHolder(holder: ViewHolder, item: TextItem) {
        holder.textView.text = item.text
    }
}

AdapterDelegates:

class TextAdapterDelegate : AdapterDelegate<List<Any>>() {
    override fun isForViewType(items: List<Any>, position: Int): Boolean {
        return items[position] is TextItem
    }
    override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder {
        return TextViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_text, parent, false))
    }
    override fun onBindViewHolder(items: List<Any>, position: Int, holder: RecyclerView.ViewHolder, payloads: List<Any>) {
        val textItem = items[position] as TextItem
        (holder as TextViewHolder).textView.text = textItem.text
    }
}

The bullet proof, fast and easy to use adapter library, which minimizes developing time to a fraction...

Pros of FastAdapter

  • More comprehensive feature set, including drag & drop, swipe-to-dismiss, and expandable items
  • Extensive documentation and sample apps for easier implementation
  • Built-in support for different view types and layouts

Cons of FastAdapter

  • Steeper learning curve due to its extensive API and features
  • Potentially higher memory footprint for simple use cases
  • More complex setup process compared to MultiType

Code Comparison

MultiType:

class TextItemViewBinder : ItemViewBinder<TextItem, TextItemViewBinder.ViewHolder>() {
    override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder {
        return ViewHolder(inflater.inflate(R.layout.item_text, parent, false))
    }
    override fun onBindViewHolder(holder: ViewHolder, item: TextItem) {
        holder.textView.text = item.text
    }
}

FastAdapter:

class TextItem : AbstractItem<TextItem.ViewHolder>() {
    override val layoutRes: Int = R.layout.item_text
    override val type: Int = R.id.fastadapter_text_item
    override fun getViewHolder(v: View): ViewHolder = ViewHolder(v)
    class ViewHolder(view: View) : FastAdapter.ViewHolder<TextItem>(view) {
        val textView: TextView = view.findViewById(R.id.text)
    }
}

Both libraries offer efficient ways to handle multiple view types in RecyclerViews, but FastAdapter provides more built-in features at the cost of increased complexity. MultiType focuses on simplicity and flexibility, making it easier to use for basic scenarios.

An Adapter that allows a RecyclerView to be split into Sections with headers and/or footers. Each Section can have its state controlled individually.

Pros of SectionedRecyclerViewAdapter

  • Built-in support for section headers and footers
  • Easier management of complex, sectioned layouts
  • Provides helper methods for section-specific operations

Cons of SectionedRecyclerViewAdapter

  • More complex API, steeper learning curve
  • Less flexible for non-sectioned layouts
  • Potentially higher memory usage due to section management

Code Comparison

SectionedRecyclerViewAdapter:

SectionedRecyclerViewAdapter sectionAdapter = new SectionedRecyclerViewAdapter();
sectionAdapter.addSection(new MySection());
recyclerView.setAdapter(sectionAdapter);

MultiType:

MultiTypeAdapter adapter = new MultiTypeAdapter();
adapter.register(Item.class, new ItemViewBinder());
recyclerView.setAdapter(adapter);

SectionedRecyclerViewAdapter is designed specifically for sectioned layouts, providing built-in support for headers and footers. It offers easier management of complex, sectioned data structures and includes helper methods for section-specific operations.

However, SectionedRecyclerViewAdapter has a more complex API and a steeper learning curve compared to MultiType. It's less flexible for non-sectioned layouts and may have higher memory usage due to its section management system.

MultiType, on the other hand, offers a simpler and more flexible approach for handling multiple view types. It's easier to use for general-purpose RecyclerView implementations but requires more manual work for implementing sectioned layouts.

The code comparison shows that SectionedRecyclerViewAdapter requires creating section objects, while MultiType uses a more straightforward registration of item types and binders.

Fast and versatile Adapter for RecyclerView which regroups several features into one library to considerably improve the user experience :-)

Pros of FlexibleAdapter

  • More comprehensive feature set, including drag & drop, expandable items, and animations
  • Built-in support for headers, footers, and section headers
  • Extensive documentation and sample app showcasing various use cases

Cons of FlexibleAdapter

  • Steeper learning curve due to its extensive feature set
  • Larger library size, which may impact app size and performance
  • More complex setup process compared to MultiType's minimalist approach

Code Comparison

MultiType:

class TextItemViewBinder : ItemViewBinder<TextItem, TextItemViewBinder.Holder>() {
    override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): Holder {
        return Holder(inflater.inflate(R.layout.item_text, parent, false))
    }
    override fun onBindViewHolder(holder: Holder, item: TextItem) {
        holder.text.text = item.text
    }
    class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val text: TextView = itemView.findViewById(R.id.text)
    }
}

FlexibleAdapter:

class TextItem(val text: String) : AbstractFlexibleItem<TextItem.ViewHolder>() {
    override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: ViewHolder, position: Int, payloads: List<*>) {
        holder.text.text = text
    }
    override fun createViewHolder(view: View, adapter: FlexibleAdapter<*>): ViewHolder {
        return ViewHolder(view, adapter)
    }
    class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
        val text: TextView = view.findViewById(R.id.text)
    }
}

Pros of android-ui-toolkit-demos

  • Comprehensive collection of UI toolkit demos
  • Covers a wide range of Android UI components and patterns
  • Official Google repository, ensuring high-quality and up-to-date examples

Cons of android-ui-toolkit-demos

  • Not actively maintained (archived repository)
  • Focuses on general UI components rather than specific list/recycler view optimization
  • May contain outdated code examples due to its archived status

Code Comparison

MultiType:

class TextItemViewBinder : ItemViewBinder<TextItem, TextItemViewBinder.ViewHolder>() {
  override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder {
    return ViewHolder(inflater.inflate(R.layout.item_text, parent, false))
  }
  // ... rest of the implementation
}

android-ui-toolkit-demos:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
    private String[] mDataset;
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView mTextView;
        public ViewHolder(TextView v) {
            super(v);
            mTextView = v;
        }
    }
    // ... rest of the implementation
}

Summary

MultiType focuses on simplifying RecyclerView adapters for multiple view types, while android-ui-toolkit-demos provides a broader range of UI examples. MultiType is actively maintained and offers a more modern approach to list management, whereas android-ui-toolkit-demos serves as a reference for various Android UI components but may contain outdated information.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

MultiType

Easier and more flexible to create multiple types for Android RecyclerView.

Build Status License maven-central jetbrains-plugin

Previously, when we need to develop a complex RecyclerView / ListView, it is difficult and troublesome work. We should override the getItemViewType() of RecyclerView.Adapter , add some types, and create some ViewHolders relating to those types. Once we need to add a new item type, we have to go to the original adapter file and modify some old codes carefully, and these adapter classes will get more complicated.

Nowadays, I created a new intuitive and flexible way to easily create complex RecyclerViews, with the MultiType library, we could insert a new item type without changing any old adapter codes and make them more readable.

Getting started

In your build.gradle:

MultiType has been rebuilt based on AndroidX. If you are still using the android support library, please use me.drakeet.multitype:multitype:3.4.4 and me.drakeet.multitype:multitype-kotlin:3.4.4.

In addition, since 4.0.0 we have migrated to fully build with Kotlin. If you don't want to use Kotlin, you can use the last stable version me.drakeet.multitype:multitype:3.5.0 and see 3.x.

dependencies {
  implementation 'com.drakeet.multitype:multitype:4.3.0'
}

Usage

Step 1. Create a Kotlin class or data class, for example:

data class Foo(
  val value: String
)

Step 2. Create a class extends ItemViewDelegate<T, VH : ViewHolder>, for example:

class FooViewDelegate: ItemViewDelegate<Foo, FooViewDelegate.ViewHolder>() {

  override fun onCreateViewHolder(context: Context, parent: ViewGroup): ViewHolder {
    // If you want a LayoutInflater parameter instead of a Context,
    // you can use ItemViewBinder as the parent of this class.
    return ViewHolder(FooView(context))
  }

  override fun onBindViewHolder(holder: ViewHolder, item: Foo) {
    holder.fooView.text = item.value

    Log.d("ItemViewDelegate API", "position: ${holder.bindingAdapterPosition}")
    Log.d("ItemViewDelegate API", "items: $adapterItems")
    Log.d("ItemViewDelegate API", "adapter: $adapter")
    Log.d("More", "Context: ${holder.itemView.context}")
  }

  class ViewHolder(itemView : View): RecyclerView.ViewHolder(itemView) {
    val fooView: TextView = itemView.findViewById(R.id.foo)
  }
}
Or if you are using a custom View instead of XML layout, you can use ViewDelegate:

The ViewDelegate is a simple ItemViewDelegate that does not require to declare and provide a RecyclerView.ViewHolder.

class FooViewDelegate : ViewDelegate<Foo, FooView>() {

  override fun onCreateView(context: Context): FooView {
    return FooView(context).apply { layoutParams = LayoutParams(MATCH_PARENT, WRAP_CONTENT) }
  }

  override fun onBindView(view: FooView, item: Foo) {
    view.imageView.setImageResource(item.imageResId)
    view.textView.text = item.text

    view.textView.text = """
      |${item.text}
      |viewHolder: ${view.holder}
      |layoutPosition: ${view.layoutPosition}
      |absoluteAdapterPosition: ${view.absoluteAdapterPosition}
      |bindingAdapterPosition: ${view.bindingAdapterPosition}
    """.trimMargin()
  }
}

(See RichViewDelegate & RichView examples for more details)

Step 3. register your types and setup your RecyclerView, for example:

class SampleActivity : AppCompatActivity() {

  private val adapter = MultiTypeAdapter()
  private val items = ArrayList<Any>()

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_list)
    val recyclerView = findViewById<RecyclerView>(R.id.list)

    adapter.register(TextItemViewDelegate())
    adapter.register(ImageItemViewDelegate())
    adapter.register(RichItemViewDelegate())
    recyclerView.adapter = adapter

    val textItem = TextItem("world")
    val imageItem = ImageItem(R.mipmap.ic_launcher)
    val richItem = RichItem("小艾大人赛高", R.drawable.img_11)

    for (i in 0..19) {
      items.add(textItem)
      items.add(imageItem)
      items.add(richItem)
    }
    adapter.items = items
    adapter.notifyDataSetChanged()
  }
}

That's all, you're good to go!

Advanced usage

One to many:

adapter.register(Data::class).to(
  DataType1ViewDelegate(),
  DataType2ViewDelegate()
).withKotlinClassLinker { _, data ->
  when (data.type) {
    Data.TYPE_2 -> DataType2ViewDelegate::class
    else -> DataType1ViewDelegate::class
  }
}

See OneDataToManyActivity, OneToManyFlow and OneToManyEndpoint for more details.

More methods that you can override from ItemViewDelegate:

open fun onBindViewHolder(holder: VH, item: T, payloads: List<Any>)
open fun getItemId(item: T): Long
open fun onViewRecycled(holder: VH)
open fun onFailedToRecycleView(holder: VH): Boolean
open fun onViewAttachedToWindow(holder: VH)
open fun onViewDetachedFromWindow(holder: VH)

Android Studio Plugin

An intellij idea plugin for Android to generate MultiType Item and ItemViewDelegate easily.

Screenshots

Pages created with MultiType:

License

Copyright (c) 2016-present. Drakeet Xu

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.