Diverse Recycle Adapter

Additional

Language
Kotlin
Version
0.9.15.1 (Jul 13, 2020)
Created
Dec 5, 2017
Updated
Feb 9, 2021 (Retired)
Owner
Trading 212 (Trading212)
Contributors
Svetlin Mollov (svetlin-mollov)
Petar Marinov (dragoncodes)
ivanminev
3
Activity
Badge
Generate
Download
Source code
APK file

Blurb

Diverse Recycler Adapter

DiverseRecyclerAdapter is a small and yet powerful library, which greatly simplifies building lists of different(as well as single type) items, by breaking each item type into separate class called RecyclerItem. This way the complexity of supporting multiple item types is moved out of the adapter, which makes the code easier to write, easier to maintain and better encapsulated. DiverseRecyclerAdapter provides a set of useful functions which do everything you would want to do with a list - add, insert, move, remove, find item(s).

As of version 0.9 DiverseRecyclerAdapter supports multiple or single item selection by having the RecyclerItem's ViewHolder implement a single interface and setting SelectionMode to the adapter. Item selection is designed to avoid calling notify*Changed on selection sate change, which causes some or all visible items to be rebound(detach->unbind->bind->attach), instead, DiverseRecyclerAdapter handles selection state changes internally, by calling Selectable.updateSelectionState(Boolean) only to the items which selection state has changed, which greatly improves the RecyclerView performance, especially when item's UI consists of complex and/or heavy hierarchies. See SingleSelectionListActivity and MultipleSelectionListActivity in the demo module for implementation details

Version 0.9 also adds support and greatly simplifies Drag to Reorder UX pattern. You only need to implement Draggable interface in the RecyclerItem's ViewHolder and set DragItemTouchHelperCallback as callback to Android's ItemTouchHelper class. See DragToReorderActivity in the demo for implementation details

Written in Kotlin, with full Java interoperability

Installation

implementation 'com.trading212:diverse-recycler-adapter:<version>'

Getting Started

ViewHolder

The well-known ViewHolder pattern. For more details see Android Documentation.

public class ViewHolder extends DiverseRecyclerAdapter.ViewHolder<String> {

    private TextView textView;

    public ViewHolder(@NotNull View itemView) {
        super(itemView);

        textView = findViewById(R.id.textView);
    }

    @Override
    protected void bindTo(@NotNull String data) {
        textView.setText(data);
    }
}

ViewHolder lifecycle

ViewHolder.bindTo(), ViewHolder.onAttachedToWindow() and ViewHolder.onDetachedFromWindow() are guaranteed to be called, while ViewHolder.unbind() is called only when the ViewHolder is going to be recycled(pushed to recycler view pool), i.e. prepared to be bound to another RecyclerItem, which may never happen. Thus, if you want to be sure that all resources are released as early as possible, you should use ViewHolder.onDetachedFromWindow() for that purpose.

Note: Use DiverseLinearLayoutManager, DiverseGridLayoutManager, DiverseStaggeredGridLayoutManager() or a subclass in the hosting RecyclerView.setLayoutManager() in order to have ViewHolder's attach/detach events work correctly. Otherwise ViewHolder.onDetachedFromWindow() will not be called when the hosting RecyclerView is detached from it's parent. Alternatively, you can use any subclass of LayoutManager and delegate LayoutManager.onAttachedToWindow() and LayoutManager.onDetachedFromWindow() events to delegateRecyclerViewAttachedToWindow() and delegateRecyclerViewDetachedFromWindow() respectively, which are located in LayoutManagerUtil class(Java only).

RecyclerItem

The RecyclerItem class describes a category(all items of the same type) in the adapter. It contains the data about a single item, as well as factory method for creating ViewHolders for that category.

public class SimpleTextRecyclerItem extends DiverseRecyclerAdapter.RecyclerItem<String, ViewHolder> {

    public static final int TYPE = 1;

    private String text;

    public SimpleTextRecyclerItem(String text) {
        this.text = text;
    }

    @Override
    public int getType() {
        return TYPE;
    }

    @Nullable
    @Override
    public String getData() {
        return text;
    }

    @NotNull
    @Override
    protected ViewHolder createViewHolder(@NotNull ViewGroup parent, @NotNull LayoutInflater inflater) {
        return new ViewHolder(inflater.inflate(R.layout.item_simple_text, parent, false));
    }
}

Working with DiverseRecyclerAdapter

  • Add item
adapter.addItem(new SimpleTextRecyclerItem("Item Text"));
  • Add multiple items
List<SimpleTextRecyclerItem> items = new ArrayList<>(30);
for (int i = 0; i < 30; i++) {
    items.add(new SimpleTextRecyclerItem("Item " + i));
}  
adapter.addItems(items);
  • Insert item
adapter.insertItem(5, new SimpleTextRecyclerItem("Item Text"));
  • Insert multiple items
List<SimpleTextRecyclerItem> items = new ArrayList<>(30);
for (int i = 0; i < 30; i++) {
    items.add(new SimpleTextRecyclerItem("Item " + i));
}  
adapter.insertItems(5, items);
  • Move item
adapter.moveItem(3, 4);
  • Remove item
adapter.removeItem(4);
  • Remove range
adapter.removeRange(0, 5);
  • Remove all items
adapter.removeAll();
  • Find the adapter position of the first RecyclerItem with the specified type, i.e. the position of the first item of a category
adapter.findFirstItemTypePosition(SimpleTextRecyclerItem.TYPE);
  • Find the adapter position of the last RecyclerItem with the specified type, i.e. the position of the last item of a category
adapter.findLastItemTypePosition(SimpleTextRecyclerItem.TYPE);
  • Get a reference to RecyclerItem by position
if (adapter.getItemViewType(4) == SimpleTextRecyclerItem.TYPE) {
    SimpleTextRecyclerItem textRecyclerItem = adapter.getItem(4);
}
  • Handle itemView events
adapter.setOnItemActionListener(new DiverseRecyclerAdapter.OnItemActionListener() {
    @Override
    public void onItemClicked(@NotNull View v, int position) {
        // Handle itemView click
    }
    
    @Override
    public boolean onItemLongClicked(@NotNull View v, int position) {
        // Handle itemView long click 
        return super.onItemLongClicked();
    }
    
    @Override
    public boolean onItemTouched(@NotNull View v, @NotNull MotionEvent event, int position) {
        // Handle itemView touch events
        return super.onItemTouched(v, event, position);
    }
});

For more details, explore and run the demo module, as well as the library itself

License

Copyright 2021 Trading 212 Ltd.

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.