Last active
August 16, 2017 16:15
-
-
Save yolapop/00477a3152efdd0f11fdd59a913b4eaf to your computer and use it in GitHub Desktop.
Generic FastAdapter's AbstractItem to be used for all types of ViewHolders
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Functional interface for binding data to a view | |
*/ | |
public interface ViewBinder<V extends View> { | |
void bindView(V view, ViewItem<V> item); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Functional interface for generating a View | |
*/ | |
public interface ViewGenerator<V extends View> { | |
V generateView(Context ctx, ViewGroup parent); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.support.annotation.IdRes; | |
import android.support.v4.view.ViewCompat; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import com.mikepenz.fastadapter.FastAdapter; | |
import com.mikepenz.fastadapter.IClickable; | |
import com.mikepenz.fastadapter.IExpandable; | |
import com.mikepenz.fastadapter.ISubItem; | |
import com.mikepenz.fastadapter.items.AbstractItem; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
/** | |
* Usage: | |
* | |
* public ViewItem<TextView> textViewItem(String title) { | |
* return new ViewItem<>(TextView.class.hashCode(), | |
* (ctx, parent) -> new TextView(ctx) | |
* .withBinder((view, item) -> { | |
* view.setText(title); | |
* }); | |
* } | |
* | |
* Then you add this ViewItem to FastItemAdapter | |
*/ | |
public class ViewItem<V extends View> extends AbstractItem<ViewItem<V>, ViewWrapper<V>> implements | |
IExpandable<ViewItem, ViewItem>, ISubItem<ViewItem, ViewItem>, IClickable<ViewItem<V>> { | |
private boolean mExpanded = false; | |
private int type; | |
private ViewItem mParent; | |
private List<ViewItem> mSubItems; | |
private ViewGenerator<V> generator; | |
private ViewBinder<V> binder, unbinder; | |
private Map<Class, Object> typedTags; | |
/** | |
* View to rotate when the item is clicked, perfect for expandable animation | |
*/ | |
@IdRes private int idViewToRotate; | |
private int rotation = 0; | |
private FastAdapter.OnClickListener<ViewItem<V>> onItemClickListener; | |
private FastAdapter.OnClickListener<ViewItem<V>> defaultOnItemClickListener = (v, adapter, item, position) -> { | |
View viewToRotate = getViewToRotate(v); | |
if (item.getSubItems() != null && viewToRotate != null && rotation != 0) { | |
if (item.isExpanded()) { | |
ViewCompat.animate(viewToRotate).rotation(rotation).start(); | |
} else { | |
ViewCompat.animate(viewToRotate).rotation(0).start(); | |
} | |
return onItemClickListener == null || onItemClickListener.onClick(v, adapter, item, position); | |
} | |
return onItemClickListener != null && onItemClickListener.onClick(v, adapter, item, position); | |
}; | |
/** | |
* Build the view item. there are 2 mandatory parameters: it's type and the view generator | |
* | |
* @param type must be globally unique | |
* @param generator functional interface for generating the view when needed | |
*/ | |
public ViewItem(int type, ViewGenerator<V> generator) { | |
this.generator = generator; | |
this.type = type; | |
} | |
/** | |
* Utility function to create list of view items in a declarative way. It also filters out nulls from the input | |
* | |
* @param items | |
* @return | |
*/ | |
public static List<AbstractItem> list(AbstractItem... items) { | |
ArrayList<AbstractItem> list = new ArrayList<>(items.length); | |
for (AbstractItem i : items) { | |
if (i == null) continue; | |
list.add(i); | |
} | |
return list; | |
} | |
/** | |
* Utility function to create list of view items in a declarative way. It also filters out nulls from the input | |
* | |
* @param items | |
* @return | |
*/ | |
public static List<AbstractItem> list(List<AbstractItem>... items) { | |
ArrayList<AbstractItem> list = new ArrayList<>(); | |
for (List<AbstractItem> i : items) { | |
if (i == null) continue; | |
list.addAll(i); | |
} | |
return list; | |
} | |
/** | |
* Functional interface to set the view contents that will be called on | |
* {@link android.support.v7.widget.RecyclerView.Adapter#onBindViewHolder(RecyclerView.ViewHolder, int)} | |
* | |
* @param binder | |
* @return | |
*/ | |
public ViewItem<V> withBinder(ViewBinder<V> binder) { | |
this.binder = binder; | |
return this; | |
} | |
/** | |
* Functional interface to unset the view contents that will be called on | |
* {@link android.support.v7.widget.RecyclerView.Adapter#onBindViewHolder(RecyclerView.ViewHolder, int)} | |
* | |
* @param binder | |
* @return | |
*/ | |
public ViewItem<V> withUnbinder(ViewBinder<V> unbinder) { | |
this.unbinder = unbinder; | |
return this; | |
} | |
@Override | |
public ViewItem<V> withOnItemClickListener(FastAdapter.OnClickListener<ViewItem<V>> onItemClickListener) { | |
this.onItemClickListener = onItemClickListener; | |
return this; | |
} | |
/** | |
* In case you want a rotating icon (e.g. arrow) when this item is expanded | |
*/ | |
public ViewItem<V> withViewToRotate(@IdRes int id) { | |
this.idViewToRotate = id; | |
return this; | |
} | |
public ViewItem<V> withRotation(int rotation) { | |
this.rotation = rotation; | |
return this; | |
} | |
@Override | |
public FastAdapter.OnClickListener<ViewItem<V>> getOnItemClickListener() { | |
return defaultOnItemClickListener; | |
} | |
/** | |
* Do not use. | |
* @return | |
*/ | |
@Deprecated | |
@Override | |
public int getLayoutRes() { | |
return 0; //this is ignored, we're overriding generateView instead | |
} | |
/** | |
* The type of view holder. | |
* @return | |
*/ | |
@Override | |
public int getType() { | |
return type; | |
} | |
/** | |
* The logic to bind our data to the view | |
*/ | |
@Override | |
public void bindView(ViewWrapper<V> holder, List<Object> payloads) { | |
super.bindView(holder, payloads); | |
if (binder != null) { | |
binder.bindView(holder.view, this); | |
} | |
View viewToRotate = getViewToRotate(holder.view); | |
if (viewToRotate != null && rotation != 0 && isExpanded()) { | |
ViewCompat.setRotation(viewToRotate, rotation); | |
} else if (viewToRotate != null) { | |
ViewCompat.setRotation(viewToRotate, 0); | |
} | |
} | |
/** | |
* This optional function unbinds the view to the default state | |
* | |
* @param holder | |
*/ | |
@Override | |
public void unbindView(ViewWrapper<V> holder) { | |
super.unbindView(holder); | |
if (unbinder != null) { | |
unbinder.bindView(holder.view, this); | |
} | |
View viewToRotate = getViewToRotate(holder.view); | |
if (viewToRotate != null) { | |
viewToRotate.clearAnimation(); | |
} | |
} | |
/** | |
* Generates the view when needed | |
* @param ctx | |
* @param parent | |
* @return | |
*/ | |
@Override | |
public View generateView(Context ctx, ViewGroup parent) { | |
return generator.generateView(ctx, parent); | |
} | |
/** | |
* Do not use. | |
* | |
* @param parent | |
* @return | |
*/ | |
@Deprecated | |
@Override | |
public ViewWrapper<V> getViewHolder(ViewGroup parent) { | |
return getViewHolder(generateView(parent.getContext(), parent)); | |
} | |
/** | |
* Do not use. | |
* | |
* @param v | |
* @return | |
*/ | |
@Deprecated | |
@Override | |
public ViewWrapper<V> getViewHolder(View v) { | |
return new ViewWrapper<>(v); | |
} | |
private View getViewToRotate(View parent) { | |
return parent.findViewById(idViewToRotate); | |
} | |
/** | |
* @return true if the view item is currently expanded | |
*/ | |
@Override | |
public boolean isExpanded() { | |
return mExpanded; | |
} | |
/** | |
* Set the view item as expanded or not. | |
* | |
* @param expanded | |
* @return | |
*/ | |
@Override | |
public ViewItem<V> withIsExpanded(boolean expanded) { | |
mExpanded = expanded; | |
return this; | |
} | |
/** | |
* Set the subitems. Subitems will be shown when view item is expanded | |
* | |
* @param subItems | |
* @return | |
*/ | |
@Override | |
public ViewItem<V> withSubItems(List<ViewItem> subItems) { | |
this.mSubItems = subItems; | |
for (ViewItem subItem : subItems) { | |
subItem.withParent(this); | |
} | |
return this; | |
} | |
/** | |
* Set the subitems. Subitems will be shown when view item is expanded | |
* | |
* @param subItems | |
* @return | |
*/ | |
public ViewItem<V> withSubItemsOf(ViewItem... items) { | |
return withSubItems(Arrays.asList(items)); | |
} | |
@Override | |
public List<ViewItem> getSubItems() { | |
return this.mSubItems; | |
} | |
@Override | |
public boolean isAutoExpanding() { | |
return true; | |
} | |
/** | |
* Get the parent view item if it exists. | |
* | |
* @return | |
*/ | |
@Override | |
public ViewItem<V> getParent() { | |
return mParent; | |
} | |
/** | |
* Do not use this. use the parent's withSubItems instead. | |
* | |
* @param parent | |
* @return | |
*/ | |
@Deprecated | |
@Override | |
public ViewItem withParent(ViewItem parent) { | |
mParent = parent; | |
return this; | |
} | |
/** | |
* Add tag of arbitrary type. This object can contain multiple tags as long as each key (class) | |
* is different. Tags set with this method will not collide with ones that are set with | |
* {@link #withTag(Object)}. | |
* | |
* @return this object, for chaining | |
*/ | |
public <T> ViewItem<V> withTag(Class<T> key, T value) { | |
if (typedTags == null) { // lazy creation | |
synchronized (this) { // thread-safe | |
if (typedTags == null) { // there's a small chance it's been set | |
typedTags = new HashMap<>(2); | |
} | |
} | |
} | |
typedTags.put(key, value); | |
return this; | |
} | |
/** | |
* Get the tag set by {@link #withTag(Class, Object)} or null if doesn't exist. | |
*/ | |
public <T> T getTag(Class<T> key) { | |
if (typedTags == null) { | |
return null; | |
} | |
//noinspection unchecked | |
return (T) typedTags.get(key); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ViewWrapper<V extends View> extends RecyclerView.ViewHolder { | |
public final V view; | |
public ViewWrapper(View itemView) { | |
super(itemView); | |
view = (V) itemView; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment