You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Fynn Godau 86bdb8aaab Pass list of recycler views to handlers 3 months ago
app Pass list of recycler views to handlers 3 months ago
demo Add primitive view holder 6 months ago
gradle/wrapper Update android plugin and gradle version 1 year ago
.gitignore Add gradle.properties 1 year ago
LICENSE Initial commit 1 year ago
README.md Update README 6 months ago
build.gradle Update android plugin and gradle version 1 year ago
gradle.properties Add gradle.properties 1 year ago
gradlew Add necessary gradle files 1 year ago
gradlew.bat Add necessary gradle files 1 year ago
settings.gradle Allow static or separate type handler classes 1 year ago

README.md

TypedRecyclerView

A small library to improve working with recycler views that contain different view types.

minSdkVersion 14

About

The following section will assume basic knowledge about the RecyclerView.Adapter class.

Say you would like a recycler view to display two different types of items: Image and Text.

public interface Item {}

public class Image implements Item { … }

public class Text implements Item { … }

With just the RecyclerView.Adapter class, you could implement it like this:

public class Adapter extends RecyclerView.Adapter {
    
    private List<Item> list;
    
    …
    
    public int getItemViewType(int position) {
        if (list.get(position) instanceof Image) return 0;
        else return 1;
    }
    
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        if (viewType == 0) …
        else if (viewType == 1) …
        else return null;
    }
    
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        Item item = list.get(position);
        
        if (item instanceof Image) {
            Image image = (Image) item;
            …
        } else if (item instanceof Text) {
            Text text = (Text) item;
            …
        }
    }
    
    public int getItemCount() {
        return list.size();
    }
}

So, RecyclerView already supports different view types, but it's not very pretty – see how in every method, there is now an if branch for each kind of view type it should handle?

With TypedRecyclerView, you can write the following class instead:

public class Adapter extends TypedRecyclerViewAdapter<Item, RecyclerView.ViewHolder> {

    …
    
    protected Class<? extends TypeHandler> getItemHandlerClass(Item item, int position) {
        if (item instanceof Image) return ImageHandler.class;
        else if (item instanceof Text) return TextHandler.class;
    }
    
    public static class ImageHandler extends TypeHandler<PrimitiveViewHolder<ImageView>, Image> {
        public PrimitiveViewHolder<ImageView> createViewHolder(ViewGroup parent) {
            return new PrimitiveViewHolder<ImageView>(
                (ImageView) (inflater.inflate(…))
            );
        }
        public void bindViewHolder(PrimitiveViewHolder<ImageView> holder, Image item, int position) {
            holder.itemView.setBitmapImage(…);
        }
    }
    
    public static class TextHandler extends TypeHandler<PrimitiveViewHolder<TextView>, Text> {
        public PrimitiveViewHolder<TextView> createViewHolder(ViewGroup parent) { …(inflater.inflate(…)… }
        public void bindViewHolder(PrimitiveViewHolder<TextView> holder, Text item, int position) { … }
    }
}

This has the following advantages:

  • Note how the Item provided to the ImageHandler is already an Image. In the other implementation it had to be casted in each case separately. This reduces the amount of repetitive code.
  • You need not use RecyclerView.ViewHolder for the two handlers, but can replace it with one implementation for each case. TypedRecyclerViewAdapter supports this. The RecyclerView.ViewHolder parameter would also have to be been cast otherwise.
  • The library provides the PrimitiveViewHolder<V> class, which can be used as a simple ViewHolder class which provides access to just one view of type V.
  • The code is cleaner because completely different cases are clearly separated.
  • You may move the handler classes to their own class files, separating the code even more nicely.
  • You could reuse one of the handler classes for another recycler view easily.
  • No viewType ints are involved. The superclass manages all of it.

TypeHandler

The TypeHandler class has the fields context, inflater and content as well. They are set by TypedRecyclerViewAdapter. Your implementation may access them.

You have two options for providing TypeHandlers to TypedRecyclerViewAdapter superclass:

  • Pass a reference. Implement getItemHandler(V, int). Please do not construct new objects each time and store references in a field instead.
  • Pass a class. Implement getItemHandlerClass(V, int. Your class must be public, have a constructor without parameters and, if it is an inner class, be static.

SimpleRecyclerViewAdapter

If you don't need different types but like the convenience of not having to store context, content and inflater yourself, have a look at SimpleRecyclerViewAdapter.

Including in your project

Please use Jitpack to download compiled AAR packages. See how here.

Migration guide

1.1 to 2.0

  • TypeHandler is now a separate class and no longer an inner class of TypedRecyclerViewAdapter. Therefore, import godau.fynn.typedrecyclerview.TypeHanlder in each TypedRecylerViewAdapter implementation.
    Your IDE will likely suggest you to do this.

License

TypedRecyclerView is licensed CC0.

Even though TypedRecyclerView is a very small library, it took some effort to draft and implement it. If you appreciate it, you are welcome to give credits.

If you are using librariesDirect, you can use this code to construct a Library object for this library:

new Library("TypedRecyclerView", License.CC0_LICENSE, null, "Fynn Godau", "https://codeberg.org/fynngodau/TypedRecyclerView");