Convert Figma logo to code with AI

donkingliang logoGroupedRecyclerViewAdapter

GroupedRecyclerViewAdapter可以很方便的实现RecyclerView的分组显示,并且每个组都可以包含组头、组尾和子项;可以方便实现多种Type类型的列表,可以实现如QQ联系人的列表一样的列表展开收起功能,还可以实现头部悬浮吸顶功能等。

1,643
216
1,643
31

Top Related Projects

BRVAH:Powerful and flexible RecyclerAdapter

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

"Favor composition over inheritance" for RecyclerView Adapters

Flexible multiple types for Android RecyclerView.

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

[UNMAINTAINED] Sticky Headers decorator for Android's RecyclerView

Quick Overview

GroupedRecyclerViewAdapter is an Android library that simplifies the creation of grouped lists in RecyclerView. It provides a flexible and efficient way to display hierarchical data structures, such as expandable lists or sectioned content, within a single RecyclerView.

Pros

  • Easy implementation of grouped lists without nested RecyclerViews
  • Supports various group types and layouts, including headers, footers, and child items
  • Efficient performance through view recycling and minimal adapter calls
  • Customizable group expansion and collapse functionality

Cons

  • Limited documentation and examples available
  • May require additional setup compared to standard RecyclerView adapters
  • Potential learning curve for developers unfamiliar with grouped list concepts
  • Might not be suitable for very complex nested structures

Code Examples

  1. Creating a basic grouped adapter:
public class MyGroupedAdapter extends GroupedRecyclerViewAdapter {
    public MyGroupedAdapter(Context context) {
        super(context);
    }

    @Override
    public int getGroupCount() {
        return 3; // Number of groups
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return 5; // Number of children in each group
    }

    // Implement other required methods...
}
  1. Binding data to a group header:
@Override
public void onBindHeaderViewHolder(BaseViewHolder holder, int groupPosition) {
    TextView textView = holder.get(R.id.tv_header);
    textView.setText("Group " + groupPosition);
}
  1. Handling child item clicks:
@Override
public void onBindChildViewHolder(BaseViewHolder holder, int groupPosition, int childPosition) {
    TextView textView = holder.get(R.id.tv_child);
    textView.setText("Child " + childPosition);
    
    holder.itemView.setOnClickListener(v -> {
        // Handle child item click
    });
}

Getting Started

  1. Add the dependency to your app's build.gradle:
dependencies {
    implementation 'com.github.donkingliang:GroupedRecyclerViewAdapter:2.4.0'
}
  1. Create a custom adapter extending GroupedRecyclerViewAdapter:
public class MyAdapter extends GroupedRecyclerViewAdapter {
    // Implement required methods
}
  1. Set up the RecyclerView in your activity or fragment:
RecyclerView recyclerView = findViewById(R.id.recycler_view);
MyAdapter adapter = new MyAdapter(this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));

Competitor Comparisons

BRVAH:Powerful and flexible RecyclerAdapter

Pros of BaseRecyclerViewAdapterHelper

  • More comprehensive feature set, including animations, drag & drop, and swipe actions
  • Larger community and more frequent updates
  • Extensive documentation and examples

Cons of BaseRecyclerViewAdapterHelper

  • Steeper learning curve due to its extensive features
  • Potentially higher memory footprint for simpler use cases
  • May introduce unnecessary complexity for basic list implementations

Code Comparison

BaseRecyclerViewAdapterHelper:

class MyAdapter : BaseQuickAdapter<String, BaseViewHolder>(R.layout.item_layout) {
    override fun convert(holder: BaseViewHolder, item: String) {
        holder.setText(R.id.textView, item)
    }
}

GroupedRecyclerViewAdapter:

class MyAdapter(context: Context) : GroupedRecyclerViewAdapter(context) {
    override fun getGroupCount(): Int = // group count
    override fun getChildrenCount(groupPosition: Int): Int = // children count
    override fun onBindChildViewHolder(holder: RecyclerView.ViewHolder, groupPosition: Int, childPosition: Int) {
        // Bind child view
    }
}

BaseRecyclerViewAdapterHelper offers a more concise implementation for simple lists, while GroupedRecyclerViewAdapter provides a structured approach for grouped data. The former is more versatile but may require additional setup for grouped layouts, whereas the latter is specifically designed for hierarchical data presentation.

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

Pros of FastAdapter

  • More comprehensive and feature-rich, offering a wide range of functionalities beyond just grouping
  • Actively maintained with frequent updates and a larger community
  • Supports multiple item types and complex layouts out of the box

Cons of FastAdapter

  • Steeper learning curve due to its extensive feature set
  • May be overkill for simpler projects that only require basic grouping functionality
  • Larger library size, which could impact app size and performance

Code Comparison

GroupedRecyclerViewAdapter:

GroupedRecyclerViewAdapter adapter = new GroupedRecyclerViewAdapter(this, list);
adapter.setOnHeaderClickListener(new GroupedRecyclerViewAdapter.OnHeaderClickListener() {
    @Override
    public void onHeaderClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder, int groupPosition) {
        // Handle header click
    }
});

FastAdapter:

val fastAdapter = FastAdapter.with(itemAdapter)
fastAdapter.onClickListener = { view, adapter, item, position ->
    // Handle item click
    false
}
recyclerView.adapter = fastAdapter

Both libraries provide solutions for working with RecyclerView, but FastAdapter offers a more comprehensive set of features at the cost of increased complexity. GroupedRecyclerViewAdapter focuses specifically on grouping functionality, making it simpler for projects with basic grouping needs.

"Favor composition over inheritance" for RecyclerView Adapters

Pros of AdapterDelegates

  • Promotes better separation of concerns by delegating view type handling to separate classes
  • Easier to maintain and scale for complex RecyclerViews with multiple view types
  • Supports composition over inheritance, allowing for more flexible adapter structures

Cons of AdapterDelegates

  • May require more initial setup and boilerplate code for simple use cases
  • Learning curve for developers unfamiliar with the delegation pattern
  • Potentially higher memory usage due to multiple delegate objects

Code Comparison

AdapterDelegates:

class CatAdapterDelegate : AdapterDelegate<List<DisplayableItem>>() {
    override fun isForViewType(items: List<DisplayableItem>, position: Int): Boolean {
        return items[position] is Cat
    }
    // ... onCreateViewHolder and onBindViewHolder methods
}

GroupedRecyclerViewAdapter:

public class MyAdapter extends GroupedRecyclerViewAdapter {
    @Override
    public int getGroupCount() {
        return groups.size();
    }
    // ... other group and child methods
}

AdapterDelegates focuses on delegating view type handling to separate classes, promoting modularity and easier maintenance for complex RecyclerViews. GroupedRecyclerViewAdapter, on the other hand, specializes in creating grouped layouts within a RecyclerView, which can be beneficial for specific use cases but may be less flexible for general-purpose adapters with multiple view types.

Flexible multiple types for Android RecyclerView.

Pros of MultiType

  • More flexible and extensible architecture for handling multiple view types
  • Simpler API with less boilerplate code required
  • Better support for composition and delegation patterns

Cons of MultiType

  • Less built-in support for grouped or sectioned data
  • May require more custom implementation for complex hierarchical structures
  • Steeper learning curve for developers new to the concept of item delegates

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)
    }
}

GroupedRecyclerViewAdapter:

class MyAdapter(context: Context) : GroupedRecyclerViewAdapter(context) {
    override fun getGroupCount(): Int = // Return group count
    override fun getChildrenCount(groupPosition: Int): Int = // Return children count for group
    override fun onBindHeaderViewHolder(holder: RecyclerView.ViewHolder, groupPosition: Int) {
        // Bind header view
    }
    override fun onBindChildViewHolder(holder: RecyclerView.ViewHolder, groupPosition: Int, childPosition: Int) {
        // Bind child view
    }
}

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

Pros of FlexibleAdapter

  • More feature-rich, offering advanced functionalities like expandable items, multi-level sections, and drag & drop
  • Extensive documentation and examples, making it easier for developers to implement complex list structures
  • Active community and regular updates, ensuring ongoing support and improvements

Cons of FlexibleAdapter

  • Steeper learning curve due to its extensive feature set and more complex implementation
  • Potentially higher memory footprint and performance overhead for simpler list structures
  • May require more boilerplate code for basic use cases

Code Comparison

GroupedRecyclerViewAdapter:

GroupedRecyclerViewAdapter adapter = new GroupedRecyclerViewAdapter(this, list);
adapter.setOnHeaderClickListener(this);
adapter.setOnFooterClickListener(this);
adapter.setOnChildClickListener(this);

FlexibleAdapter:

FlexibleAdapter<IFlexible> adapter = new FlexibleAdapter<>(items);
adapter.addListener(this);
adapter.setDisplayHeadersAtStartUp(true);
adapter.setStickyHeaders(true);

Both adapters offer group/section functionality for RecyclerView, but FlexibleAdapter provides a more comprehensive solution with additional features. GroupedRecyclerViewAdapter is simpler and may be easier to implement for basic grouped lists. FlexibleAdapter is better suited for complex list structures and advanced requirements, albeit with a steeper learning curve.

[UNMAINTAINED] Sticky Headers decorator for Android's RecyclerView

Pros of sticky-headers-recyclerview

  • Specialized focus on sticky headers, providing a smooth and efficient implementation
  • Lightweight library with minimal dependencies
  • Easy integration with existing RecyclerView implementations

Cons of sticky-headers-recyclerview

  • Limited to sticky header functionality, lacking support for grouped data structures
  • Less active maintenance and updates compared to GroupedRecyclerViewAdapter
  • May require additional customization for complex grouping scenarios

Code Comparison

GroupedRecyclerViewAdapter:

GroupedRecyclerViewAdapter adapter = new GroupedRecyclerViewAdapter(this, list);
adapter.setOnHeaderClickListener(new GroupedRecyclerViewAdapter.OnHeaderClickListener() {
    @Override
    public void onHeaderClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder, int groupPosition) {
        // Handle header click
    }
});

sticky-headers-recyclerview:

StickyRecyclerHeadersAdapter adapter = new StickyRecyclerHeadersAdapter<RecyclerView.ViewHolder>() {
    @Override
    public long getHeaderId(int position) {
        // Return header ID for position
    }
    @Override
    public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
        // Create header view holder
    }
    @Override
    public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder, int position) {
        // Bind header view holder
    }
};

Both libraries offer solutions for handling grouped or sectioned data in RecyclerViews, but they differ in their approach and feature set. GroupedRecyclerViewAdapter provides a more comprehensive solution for grouped data structures, while sticky-headers-recyclerview focuses specifically on implementing sticky headers efficiently.

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

GroupedRecyclerViewAdapter

GroupedRecyclerViewAdapter可以很方便的实现RecyclerView的分组显示,并且每个组都可以包含组头、组尾和子项;可以方便实现多种Type类型的列表,可以实现如QQ联系人的列表一样的列表展开收起功能,还可以实现头部悬浮吸顶功能等。下面先让我们看一下它所能够实现的一些效果:

效果图

分组的列表 不带组尾的列表 不带组头的列表 子项为Grid的列表 子项为Grid的列表(各组子项的Span不同) 头、尾和子项都支持多种类型的列表

多种子项类型的列表

还可以很容易的实时列表的展开收起效果:

可展开收起的列表

还可以轻松实现头部悬浮吸顶的效果:

头部吸顶的列表

以上展示的只是GroupedRecyclerViewAdapter能实现的一些常用效果,其实使用GroupedRecyclerViewAdapter还可以很容易的实现一些更加复杂的列表效果。在我的GroupedRecyclerViewAdapter项目的Demo中给出了上面几种效果的实现例子,并且有详细的注释说明,有兴趣的同学可以到我的GitHub下载源码。下面直接讲解GroupedRecyclerViewAdapter的使用。

引入依赖

在Project的build.gradle在添加以下代码

	allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}

在Module的build.gradle在添加以下代码


implementation 'com.github.donkingliang:GroupedRecyclerViewAdapter:2.4.3'

基本使用

1、继承GroupedRecyclerViewAdapter

public class GroupedListAdapter extends GroupedRecyclerViewAdapter {
}

2、实现GroupedRecyclerViewAdapter里的方法

GroupedRecyclerViewAdapter是一个抽象类,它提供了一系列需要子类去实现的方法。

	//返回组的数量
	public abstract int getGroupCount();

	//返回当前组的子项数量
    public abstract int getChildrenCount(int groupPosition);

	//当前组是否有头部
    public abstract boolean hasHeader(int groupPosition);

	//当前组是否有尾部
    public abstract boolean hasFooter(int groupPosition);

	//返回头部的布局id。(如果hasHeader返回false,这个方法不会执行)
    public abstract int getHeaderLayout(int viewType);

	//返回尾部的布局id。(如果hasFooter返回false,这个方法不会执行)
    public abstract int getFooterLayout(int viewType);

	//返回子项的布局id。
    public abstract int getChildLayout(int viewType);

	//绑定头部布局数据。(如果hasHeader返回false,这个方法不会执行)
    public abstract void onBindHeaderViewHolder(BaseViewHolder holder, int groupPosition);

	//绑定尾部布局数据。(如果hasFooter返回false,这个方法不会执行)
    public abstract void onBindFooterViewHolder(BaseViewHolder holder, int groupPosition);

	//绑定子项布局数据。
    public abstract void onBindChildViewHolder(BaseViewHolder holder,
                                               int groupPosition, int childPosition);

还可是重写GroupedRecyclerViewAdapter方法实现头、尾和子项的多种类型item。效果就像上面的第6张图一样。

	//返回头部的viewType。
	public int getHeaderViewType(int groupPosition);

	//返回尾部的viewType。
    public int getFooterViewType(int groupPosition) ;

	//返回子项的viewType。
    public int getChildViewType(int groupPosition, int childPosition) ;

3、设置点击事件的监听

GroupedRecyclerViewAdapter提供了对列表的点击事件的监听方法。

	//设置组头点击事件
    public void setOnHeaderClickListener(OnHeaderClickListener listener) {
        mOnHeaderClickListener = listener;
    }

    //设置组尾点击事件
    public void setOnFooterClickListener(OnFooterClickListener listener) {
        mOnFooterClickListener = listener;
    }

    // 设置子项点击事件
    public void setOnChildClickListener(OnChildClickListener listener) {
        mOnChildClickListener = listener;
    }

4、设置空布局

GroupedRecyclerViewAdapter提供设置空布局的功能,如果列表没有数据的情况下可以显示一个空布局。

// 显示空布局。默认不显示
adapter.showEmptyView(true);

框架提供的默认空布局比较简单,可以通过复写getEmptyView自定义空布局

    @Override
    public View getEmptyView(ViewGroup parent) {
    // 返回自定义空布局
        View view = LayoutInflater.from(mContext).inflate(R.layout.adapter_empty_view, parent, false);
        return view;
    }

框架只提供空布局的设置方法,不会管理空布局。所以如果你的空布局有点击事件等其他的业务逻辑,也需要自己在这个方法实现。

5、使用ItemDecoration

从2.4.0版本开始,支持使用ItemDecoration。之前一直没有对GroupedRecyclerViewAdapter提供ItemDecoration的支持,是因为对于分组的列表,每个分组的ItemDecoration和组头、组尾的ItemDecoration都应该是可以单独设置样式的。这对于自定义ItemDecoration的实现比较麻烦,而且难以实现统一的设置和扩展方式。后来我实现了一个自定义ItemDecoration的库:VariedItemDecoration。使用VariedItemDecoration可以实现在一个列表里显示多种不同样式的ItemDecoration,并且可以非常简单的实现自定义ItemDecoration。基于VariedItemDecoration的实现基础,我实现了多样式ItemDecoration的分组管理,使ItemDecoration可以使用于GroupedRecyclerViewAdapter列表。我在库里提供了可直接使用的GroupedLinearItemDecoration/GroupedGridItemDecoration和用于自定义ItemDecoration的基类AbsGroupedLinearItemDecoration/AbsGroupedGridItemDecoration。

下面我以线性列表为例,说明ItemDecoration使用。

// 空白分割线,只需要设置分割线大小,不需要设置样式,divider为空则只添加间隔,不绘制样式
GroupedLinearItemDecoration itemDecoration = new GroupedLinearItemDecoration(adapter,20, null,20,null,20,null);

// 普通分割线,设置分割线大小和头、尾、子项的分割线样式
GroupedLinearItemDecoration itemDecoration = new GroupedLinearItemDecoration(adapter,20, mHeaderDivider,20,mFooterDivider,20,mChildDivider);

// 自定义分割线,可以根据需要设置每个item的分割线大小和样式
CustomLinearItemDecoration itemDecoration = new CustomLinearItemDecoration(this,adapter);

// 添加分割线
recyclerView.addItemDecoration(itemDecoration);

// 自定义分割线
public class CustomLinearItemDecoration extends AbsGroupedLinearItemDecoration {

    private Drawable headerDivider;
    private Drawable footerDivider;
    private Drawable childDivider1;
    private Drawable childDivider2;

    public CustomLinearItemDecoration(Context context,GroupedRecyclerViewAdapter adapter) {
        super(adapter);

        headerDivider = context.getResources().getDrawable(R.drawable.green_divider);
        footerDivider = context.getResources().getDrawable(R.drawable.purple_divider);
        childDivider1 = context.getResources().getDrawable(R.drawable.pink_divider);
        childDivider2 = context.getResources().getDrawable(R.drawable.orange_divider);
    }

    @Override
    public int getChildDividerSize(int groupPosition, int ChildPosition) {
        // 根据position返回分割线的大小
        return 20;
    }

    @Override
    public Drawable getChildDivider(int groupPosition, int ChildPosition) {
        // 根据position返回Drawable 可以为null
        if(groupPosition % 2 == 0){
            return childDivider1;
        } else {
            return childDivider2;
        }
    }

    @Override
    public int getHeaderDividerSize(int groupPosition) {
        // 根据position返回分割线的大小
        return 30;
    }

    @Override
    public Drawable getHeaderDivider(int groupPosition) {
        // 根据position返回Drawable 可以为null
        return headerDivider;
    }

    @Override
    public int getFooterDividerSize(int groupPosition) {
        // 根据position返回分割线的大小
        return 30;
    }

    @Override
    public Drawable getFooterDivider(int groupPosition) {
        // 根据position返回Drawable 可以为null
        return footerDivider;
    }
}

对于网格列表的ItemDecoration,使用也是一样的,大家可以看我demo中的例子。

如果你想在普通的RecyclerView中使用这种多样式的ItemDecoration,请使用VariedItemDecoration。

注意事项

1、对方法重写的注意。

如果我们直接继承RecyclerView.Adapter去实现自己的Adapter时,一般会重写Adapter中的以下几个方法:

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType);

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position);

public int getItemCount();

public int getItemViewType(int position);

但如果是使用GroupedRecyclerViewAdapter,就一定不能去重写这几个方法,因为在GroupedRecyclerViewAdapter中已经对这几个方法做了实现,而且是对实现列表分组至关重要的,如果子类重写了这几个方法,可能会破坏GroupedRecyclerViewAdapter的功能。 从前面给出的GroupedRecyclerViewAdapter的方法我们可以看到,这些方法其实就是对应RecyclerView.Adapter的这4个方法的,所以我们直接使用GroupedRecyclerViewAdapter提供的方法即可。 RecyclerView.Adapter中的

	public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType);

对应GroupedRecyclerViewAdapter中的

	//返回头部的布局id。(如果hasHeader返回false,这个方法不会执行)
    public abstract int getHeaderLayout(int viewType);

	//返回尾部的布局id。(如果hasFooter返回false,这个方法不会执行)
    public abstract int getFooterLayout(int viewType);

	//返回子项的布局id。
    public abstract int getChildLayout(int viewType);

这里之所以返回的是布局id而不是ViewHolder ,是因为在GroupedRecyclerViewAdapter项目中已经提供了一个通用的ViewHolder:BaseViewHolder。所以使用者只需要提供布局的id即可,不需要自己去实现ViewHolder。

	@Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(getLayoutId(mTempPosition, viewType), parent, false);
        return new BaseViewHolder(view);
    }

    private int getLayoutId(int position, int viewType) {
        int type = judgeType(position);
        if (type == TYPE_HEADER) {
            return getHeaderLayout(viewType);
        } else if (type == TYPE_FOOTER) {
            return getFooterLayout(viewType);
        } else if (type == TYPE_CHILD) {
            return getChildLayout(viewType);
        }
        return 0;
    }

RecyclerView.Adapter中的

	public void onBindViewHolder(RecyclerView.ViewHolder holder, int position);

对应GroupedRecyclerViewAdapter中的

	//绑定头部布局数据。(如果hasHeader返回false,这个方法不会执行)
    public abstract void onBindHeaderViewHolder(BaseViewHolder holder, int groupPosition);

	//绑定尾部布局数据。(如果hasFooter返回false,这个方法不会执行)
    public abstract void onBindFooterViewHolder(BaseViewHolder holder, int groupPosition);

	//绑定子项布局数据。
    public abstract void onBindChildViewHolder(BaseViewHolder holder,
                                               int groupPosition, int childPosition);

RecyclerView.Adapter中的

	public int getItemCount();

对应GroupedRecyclerViewAdapter中的

	//返回组的数量
	public abstract int getGroupCount();

	//返回当前组的子项数量
    public abstract int getChildrenCount(int groupPosition);

RecyclerView.Adapter中的

	public int getItemViewType(int position);

对应GroupedRecyclerViewAdapter中的

	//返回头部的viewType。
	public int getHeaderViewType(int groupPosition);

	//返回尾部的viewType。
    public int getFooterViewType(int groupPosition) ;

	//返回子项的viewType。
    public int getChildViewType(int groupPosition, int childPosition) ;

2、对列表操作的注意

RecyclerView.Adapter提供了一系列对列表进行操作的方法。如:

//更新操作
public final void notifyDataSetChanged();
public final void notifyItemChanged(int position);
public final void notifyItemChanged(int position, Object payload);
public final void notifyItemRangeChanged(int positionStart, int itemCount);
public final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload);

//插入操作
public final void notifyItemInserted(int position);
public final void notifyItemRangeInserted(int positionStart, int itemCount);

//删除操作
public final void notifyItemRemoved(int position)
public final void notifyItemRangeRemoved(int positionStart, int itemCount);

在GroupedRecyclerViewAdapter不建议使用RecyclerView.Adapter的任何对列表的操作方法,因为这些方法都是基于列表的操作,它的position是相对于整个列表而言的,而GroupedRecyclerViewAdapter是分组的列表,它对列表的操作应该是基于组的。同时GroupedRecyclerViewAdapter使用了组结构来维护整个列表的结构,使我们可以对列表进行组的操作,在列表发生变化时GroupedRecyclerViewAdapter需要及时对组结构进行调整,如果使用了RecyclerView.Adapter中的方法对列表进行更新,GroupedRecyclerViewAdapter可能因为无法及时调整组结构而发生异常。所以在使用中应该避免使用这些方法。GroupedRecyclerViewAdapter同样提供了一系列对列表进行操作的方法,我们应该使用GroupedRecyclerViewAdapter所提供的方法。

	 //****** 刷新操作 *****//

    //通知数据列表刷新。对应 notifyDataSetChanged();
    public void notifyDataChanged();

    //通知一组数据刷新,包括组头,组尾和子项
    public void notifyGroupChanged(int groupPosition);

    //通知多组数据刷新,包括组头,组尾和子项
    public void notifyGroupRangeChanged(int groupPosition, int count);

    // 通知组头刷新
    public void notifyHeaderChanged(int groupPosition);

    // 通知组尾刷新
    public void notifyFooterChanged(int groupPosition);

    // 通知一组里的某个子项刷新
    public void notifyChildChanged(int groupPosition, int childPosition);

    // 通知一组里的多个子项刷新
    public void notifyChildRangeChanged(int groupPosition, int childPosition, int count);

    // 通知一组里的所有子项刷新
    public void notifyChildrenChanged(int groupPosition);

    //****** 删除操作 *****//
    // 通知所有数据删除
    public void notifyDataRemoved();

    // 通知一组数据删除,包括组头,组尾和子项
    public void notifyGroupRemoved(int groupPosition);

    // 通知多组数据删除,包括组头,组尾和子项
    public void notifyGroupRangeRemoved(int groupPosition, int count);

    // 通知组头删除
    public void notifyHeaderRemoved(int groupPosition);

    // 通知组尾删除
    public void notifyFooterRemoved(int groupPosition);

    // 通知一组里的某个子项删除
    public void notifyChildRemoved(int groupPosition, int childPosition);

    // 通知一组里的多个子项删除
    public void notifyChildRangeRemoved(int groupPosition, int childPosition, int count);

    // 通知一组里的所有子项删除
    public void notifyChildrenRemoved(int groupPosition);
    
    //****** 插入操作 *****//
    // 通知一组数据插入
    public void notifyGroupInserted(int groupPosition);

    // 通知多组数据插入
    public void notifyGroupRangeInserted(int groupPosition, int count);

    // 通知组头插入
    public void notifyHeaderInserted(int groupPosition);
    
    // 通知组尾插入
    public void notifyFooterInserted(int groupPosition);

    // 通知一个子项到组里插入
    public void notifyChildInserted(int groupPosition, int childPosition);

    // 通知一组里的多个子项插入
    public void notifyChildRangeInserted(int groupPosition, int childPosition, int count);

    // 通知一组里的所有子项插入
    public void notifyChildrenInserted(int groupPosition);

注意: GroupedRecyclerViewAdapter不管理列表数据源,在调用notifyxxxRemoved或者notifyxxxInserted等方法刷新列表前,请相应的刷新数据源。也就是说,对数据的操作应该写在对列表的刷新前。

3、使用GridLayoutManager的注意

如果要使用GridLayoutManager,一定要使用项目中所提供的GroupedGridLayoutManager。因为分组列表如果要使用GridLayoutManager实现网格布局,就要保证组的头部和尾部是要单独占用一行的。否则组的头、尾可能会跟子项混着一起,造成布局混乱。同时GroupedGridLayoutManager提供了对子项的SpanSize的修改方法,使用GroupedGridLayoutManager可以实现更多的复杂列表布局。

	//直接使用GroupedGridLayoutManager实现子项的Grid效果
    GroupedGridLayoutManager gridLayoutManager = new GroupedGridLayoutManager(this, 2, adapter);
   rvList.setLayoutManager(gridLayoutManager);
   

   GroupedGridLayoutManager gridLayoutManager = new GroupedGridLayoutManager(this, 4, adapter){
       //重写这个方法 改变子项的SpanSize。
       //这个跟重写SpanSizeLookup的getSpanSize方法的使用是一样的。
       @Override
       public int getChildSpanSize(int groupPosition, int childPosition) {
            if(groupPosition % 2 == 1){
                 return 2;
            }
            return super.getChildSpanSize(groupPosition, childPosition);
       }
   };
   rvList.setLayoutManager(gridLayoutManager);

4、BaseViewHolder的使用

项目中提供了一个通用的ViewHolder:BaseViewHolder。提供了根据viewId获取View的方法和对View、TextView、ImageView的常用设置方法。

//根据id获取View
TextView  textView = holder.get(R.id.tv_header);

//View、TextView、ImageView的常用设置方法。并且支持方法连缀调用
holder.setText(R.id.tv_header, "内容")
                .setImageResource(R.id.iv_image, 资源id)
                .setBackgroundRes(R.id.view,资源id);

BaseViewHolder是可以通用的,在普通的Adapter中也可以使用,可以省去每次都要创建ViewHolder的麻烦。

5、头部悬浮吸顶功能

应一些朋友的反馈,我在1.2.0版本中新加了列表的头部悬浮吸顶功能。使用起来非常的简单,只需要用框架里提供的StickyHeaderLayout包裹一下你的RecyclerView就可以了。当然,你需要使用GroupedRecyclerViewAdapter才能看到效果。

    <!-- 用StickyHeaderLayout包裹RecyclerView -->
    <com.donkingliang.groupedadapter.widget.StickyHeaderLayout
        android:id="@+id/sticky_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </com.donkingliang.groupedadapter.widget.StickyHeaderLayout>

StickyHeaderLayout提供了一个设置是否显示悬浮吸顶的方法。

	//是否吸顶,默认为true。
	stickyLayout.setSticky(true);

6、使用DataBinding

GroupedRecyclerViewAdapter在1.3.0版本加入了对DataBinding的支持。要想在Adapter中使用DataBinding,只需要在GroupedRecyclerViewAdapter的构造函数的useBinding参数传true即可。

public class BindingAdapter extends GroupedRecyclerViewAdapter {

    public BindingAdapter(Context context) {
    	//只要在这里传true,Adapter就会用DataBinding的方式加载列表的item布局。默认为false。
        super(context, true);
    }
}

然后同过BaseViewHolder的getBinding()就可以获取到item对应的ViewDataBinding对象。

    @Override
    public void onBindHeaderViewHolder(BaseViewHolder holder, int groupPosition) {
    	//获取ViewDataBinding对象。
        AdapterBindingHeaderBinding binding = holder.getBinding();
    }

    @Override
    public void onBindFooterViewHolder(BaseViewHolder holder, int groupPosition) {
    	//获取ViewDataBinding对象。
        AdapterBindingFooterBinding binding = holder.getBinding();
    }

    @Override
    public void onBindChildViewHolder(BaseViewHolder holder, int groupPosition, int childPosition) {
    	//获取ViewDataBinding对象。
        AdapterBindingChildBinding binding = holder.getBinding();
    }