UniversalAdapter
A single adapter implementation for any scrolling view or ViewGroup
.
This library consolidates the differences between BaseAdapter
, RecyclerView.Adapter
, PagerAdapter
, and binding to ViewGroup
into one unified API.
Its underlying implementation is based on the ViewHolder
pattern and abstracts it to work with all of the adapter views.
Including in your project
Gradle
By standard Gradle use:
dependencies {
compile 'com.raizlabs:UniversalAdapter:2.2.0'
}
Usage
This library comes packed with some notable features:
- One adapter implementation to rule them all. Enforces
ViewHolder
pattern and binds to a range ofViewGroup
such asLinearLayout
,GridView
,ListView
,RecyclerView
,ViewPager
, and more! - List observability: when an adapter's inner content changes, notifications to the parent adapter view happen automatically
- Merged adapter: add an arbitrary amount of
UniversalAdapter
's together to enable diverse view-data sets! - Unified header and footer support: add an arbitrary number of headers and footers to any
UniversalAdapter
and let the library handle it for you, no matter the parent view!
Adapters
This library comes with two main adapter classes: UniversalAdapter
and ListBasedAdapter
.
UniversalAdapter
: The base class that all adapters should derive from. It's strongly based on the BaseAdapter
class, while not relying on subclassing it.
ListBasedAdapter
supports a List
of items. Note: use ObservableListWrapper to pass changes from this list to this adapter automatically!
How Binding Works
Any UniversalAdapter
can bind to the ViewGroup
you need it to by using the UniversalConverterFactory
, which exposes a UniversalConverter
class. Depending on the parent ViewGroup
passed to UniversalConverterFactory.create()
, it returns the appropriate adapter implementation.
The UniversalConverter
provides methods for:
- Clicks on items, footers, and headers
- Long Clicks on items, footers, and headers
- Swapping in another adapter.
- Retrieving the contained adapter
- And more
Example
To define an adapter:
ListBasedAdapter<Item, Holder> adapter = new ListBasedAdapter<>() {
@Override
protected void onBindViewHolder(Holder viewHolder, Item item, int position) {
// bind here
}
@Override
protected Holder onCreateViewHolder(ViewGroup parent, int itemType) {
return new Holder(inflateView(parent, R.layout.my_layout));
}
}
To add items to this list-based adapter:
adapter.loadItemsList(myItems);
adapter.add(item);
Now to connect it to a ListView
, RecyclerView
, ViewPager
, or ViewGroup
:
UniversalConverter<Item, Holder> universalConverter = UniversalConverterFactory.create(adapter, someViewGroup);
// each UniversalConverter determines how the click events works // you just worry about the callback! universalConverter.setItemClickedListener(new ItemClickedListener<>() {
@Override
public void onItemClicked(UniversalAdapter<Item, Holder> adapter, Item item, Holder holder, int position) {
// do something here
}
}
)
This method "converts" the UniversalAdapter
to the appropriate adapter for the ViewGroup
passed. If it cannot find a more specific adapter, it utilizes a ViewGroupAdapter
, which adds all views from the adapter to a ViewGroup
.
Merged Adapter
Ever need multiple kinds of uniform adapter data and want to display them together?
A MergedUniversalAdapter
allows you to add multiple UniversalAdapter
and display them all together!
MergedUniversalAdapter merged = new MergedUniversalAdapter();
merged.addAdapter(listAdapter);
merged.addAdapter(anotherAdapter);
// bind the adapter to the ViewGroup you want to use. UniversalConverterFactory.create(merged, viewGroup);
Header and Footers
One of the pain points of RecyclerView
is that it does not natively support header and footer views. ListView
does provide a mechanism, but this is not done uniformly at the adapter level. We added header and footer support to UniversalAdapter
to merge the two concepts together at the Adapter
level, so no matter the parent container, it works the same way.
To use it:
ListBasedAdapter<Item, Holder adapter = new ListBasedAdapter<>();
// add items you want to display adapter.loadItemList(someList);
// now we want some headers, no problem! adapter.addHeaderView(myHeaderView);
// we can also add ViewHolders too! adapter.addHeaderHolder(myViewHolder);
// same for footers adapter.addFooterView(myFooter);
adapter.addFooterHolder(myFooterHolder);
// bind to ViewGroup of your choice: UniversalConverterFactory.create(adapter, viewGroup);
Please note that these must be added before binding the adapter to the ViewGroup
. This is because the adapter treats headers and footers as different item types. Unfortunately, ListView
and RecyclerView
do not treat dynamic viewtypes too kindly.
ViewGroup adapter
Sometimes we want to simply add a homogenous set of data to a LinearLayout
or parent ViewGroup
and don't want to or can't use a ListView
. Instead of having to create a BaseAdapter
, write methods to bind the views to the ViewGroup
, and handle changes to the adapter, we wrote ViewGroupAdapter
.
You don't even need to worry about it because its the same interface for ListView
, RecyclerView
, and ViewPager
.
LinearLayout layout = (LinearLayout) findViewById(R.id.my_list);
// ties the adapter to this layout // any changes to the adapter will refresh the content on this layout UniversalConverterFactory.create(myListAdapter, layout);
That's it!
Maintainers
Contributors
To become a contributor, please make pull requests against the develop
branch and once code is merged, we'll add you!