1.ViewHolder
public class BaseDelegateViewHolder extends RecyclerView.ViewHolder {
/**
* Views indexed with their IDs
*/
private final SparseArray<View> views;
public Set<Integer> getNestViews() {
return nestViews;
}
private final HashSet<Integer> nestViews;
private final LinkedHashSet<Integer> childClickViewIds;
private final LinkedHashSet<Integer> itemChildLongClickViewIds;
private BaseDelegateAdapter adapter;
/**
* use itemView instead
*/
@Deprecated
public View convertView;
/**
* Package private field to retain the associated user object and detect a change
*/
Object associatedObject;
public BaseDelegateViewHolder(final View view) {
super(view);
this.views = new SparseArray<>();
this.childClickViewIds = new LinkedHashSet<>();
this.itemChildLongClickViewIds = new LinkedHashSet<>();
this.nestViews = new HashSet<>();
convertView = view;
}
private int getClickPosition() {
return getLayoutPosition();
}
public HashSet<Integer> getItemChildLongClickViewIds() {
return itemChildLongClickViewIds;
}
public HashSet<Integer> getChildClickViewIds() {
return childClickViewIds;
}
/**
* use itemView instead
*
* @return the ViewHolder root view
*/
@Deprecated
public View getConvertView() {
return convertView;
}
/**
* Will set the text of a TextView.
*
* @param viewId The view id.
* @param value The text to put in the text view.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setText(@IdRes int viewId, CharSequence value) {
TextView view = getView(viewId);
view.setText(value);
return this;
}
public BaseDelegateViewHolder setText(@IdRes int viewId, @StringRes int strId) {
TextView view = getView(viewId);
view.setText(strId);
return this;
}
/**
* Will set the image of an ImageView from a resource id.
*
* @param viewId The view id.
* @param imageResId The image resource id.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setImageResource(@IdRes int viewId, @DrawableRes int imageResId) {
ImageView view = getView(viewId);
view.setImageResource(imageResId);
return this;
}
/**
* Will set background color of a view.
*
* @param viewId The view id.
* @param color A color, not a resource id.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setBackgroundColor(@IdRes int viewId, @ColorInt int color) {
View view = getView(viewId);
view.setBackgroundColor(color);
return this;
}
/**
* Will set background of a view.
*
* @param viewId The view id.
* @param backgroundRes A resource to use as a background.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setBackgroundRes(@IdRes int viewId, @DrawableRes int backgroundRes) {
View view = getView(viewId);
view.setBackgroundResource(backgroundRes);
return this;
}
/**
* Will set text color of a TextView.
*
* @param viewId The view id.
* @param textColor The text color (not a resource id).
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setTextColor(@IdRes int viewId, @ColorInt int textColor) {
TextView view = getView(viewId);
view.setTextColor(textColor);
return this;
}
/**
* Will set the image of an ImageView from a drawable.
*
* @param viewId The view id.
* @param drawable The image drawable.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setImageDrawable(@IdRes int viewId, Drawable drawable) {
ImageView view = getView(viewId);
view.setImageDrawable(drawable);
return this;
}
/**
* Add an action to set the image of an image view. Can be called multiple times.
*/
public BaseDelegateViewHolder setImageBitmap(@IdRes int viewId, Bitmap bitmap) {
ImageView view = getView(viewId);
view.setImageBitmap(bitmap);
return this;
}
/**
* Add an action to set the alpha of a view. Can be called multiple times.
* Alpha between 0-1.
*/
public BaseDelegateViewHolder setAlpha(@IdRes int viewId, float value) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
getView(viewId).setAlpha(value);
} else {
// Pre-honeycomb hack to set Alpha value
AlphaAnimation alpha = new AlphaAnimation(value, value);
alpha.setDuration(0);
alpha.setFillAfter(true);
getView(viewId).startAnimation(alpha);
}
return this;
}
/**
* Set a view visibility to VISIBLE (true) or GONE (false).
*
* @param viewId The view id.
* @param visible True for VISIBLE, false for GONE.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setGone(@IdRes int viewId, boolean visible) {
View view = getView(viewId);
view.setVisibility(visible ? View.VISIBLE : View.GONE);
return this;
}
/**
* Set a view visibility to VISIBLE (true) or INVISIBLE (false).
*
* @param viewId The view id.
* @param visible True for VISIBLE, false for INVISIBLE.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setVisible(@IdRes int viewId, boolean visible) {
View view = getView(viewId);
view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
return this;
}
/**
* Add links into a TextView.
*
* @param viewId The id of the TextView to linkify.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder linkify(@IdRes int viewId) {
TextView view = getView(viewId);
Linkify.addLinks(view, Linkify.ALL);
return this;
}
/**
* Apply the typeface to the given viewId, and enable subpixel rendering.
*/
public BaseDelegateViewHolder setTypeface(@IdRes int viewId, Typeface typeface) {
TextView view = getView(viewId);
view.setTypeface(typeface);
view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
return this;
}
/**
* Apply the typeface to all the given viewIds, and enable subpixel rendering.
*/
public BaseDelegateViewHolder setTypeface(Typeface typeface, int... viewIds) {
for (int viewId : viewIds) {
TextView view = getView(viewId);
view.setTypeface(typeface);
view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
}
return this;
}
/**
* Sets the progress of a ProgressBar.
*
* @param viewId The view id.
* @param progress The progress.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setProgress(@IdRes int viewId, int progress) {
ProgressBar view = getView(viewId);
view.setProgress(progress);
return this;
}
/**
* Sets the progress and max of a ProgressBar.
*
* @param viewId The view id.
* @param progress The progress.
* @param max The max value of a ProgressBar.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setProgress(@IdRes int viewId, int progress, int max) {
ProgressBar view = getView(viewId);
view.setMax(max);
view.setProgress(progress);
return this;
}
/**
* Sets the range of a ProgressBar to 0...max.
*
* @param viewId The view id.
* @param max The max value of a ProgressBar.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setMax(@IdRes int viewId, int max) {
ProgressBar view = getView(viewId);
view.setMax(max);
return this;
}
/**
* Sets the rating (the number of stars filled) of a RatingBar.
*
* @param viewId The view id.
* @param rating The rating.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setRating(@IdRes int viewId, float rating) {
RatingBar view = getView(viewId);
view.setRating(rating);
return this;
}
/**
* Sets the rating (the number of stars filled) and max of a RatingBar.
*
* @param viewId The view id.
* @param rating The rating.
* @param max The range of the RatingBar to 0...max.
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setRating(@IdRes int viewId, float rating, int max) {
RatingBar view = getView(viewId);
view.setMax(max);
view.setRating(rating);
return this;
}
/**
* Sets the tag of the view.
*
* @param viewId The view id.
* @param tag The tag;
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setTag(@IdRes int viewId, Object tag) {
View view = getView(viewId);
view.setTag(tag);
return this;
}
/**
* Sets the tag of the view.
*
* @param viewId The view id.
* @param key The key of tag;
* @param tag The tag;
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setTag(@IdRes int viewId, int key, Object tag) {
View view = getView(viewId);
view.setTag(key, tag);
return this;
}
/**
* Sets the checked status of a checkable.
*
* @param viewId The view id.
* @param checked The checked status;
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setChecked(@IdRes int viewId, boolean checked) {
View view = getView(viewId);
// View unable cast to Checkable
if (view instanceof Checkable) {
((Checkable) view).setChecked(checked);
}
return this;
}
/**
* Set the enabled state of this view.
*
* @param viewId The view id.
* @param enable The checked status;
* @return The BaseViewHolder for chaining.
*/
public BaseDelegateViewHolder setEnabled(@IdRes int viewId,boolean enable) {
View view = getView(viewId);
view.setEnabled(enable);
return this;
}
@SuppressWarnings("unchecked")
public <T extends View> T getView(@IdRes int viewId) {
View view = views.get(viewId);
if (view == null) {
view = itemView.findViewById(viewId);
views.put(viewId, view);
}
return (T) view;
}
/**
* Retrieves the last converted object on this view.
*/
public Object getAssociatedObject() {
return associatedObject;
}
/**
* Should be called during convert
*/
public void setAssociatedObject(Object associatedObject) {
this.associatedObject = associatedObject;
}
}
2.Adapter(包含item的点击事件和长按事件)
public abstract class BaseDelegateAdapter<T, VH extends RecyclerView.ViewHolder> extends DelegateAdapter.Adapter<VH>{
private static final String TAG = BaseDelegateAdapter.class.getSimpleName();
public Context mContext;
private LayoutInflater mLayoutInflater;
private int mLayoutResId;
private List<T> mData;
private LayoutHelper mLayoutHelper;
public BaseDelegateAdapter(@LayoutRes int layoutResId, @Nullable List<T> data, LayoutHelper layoutHelper) {
this.mData = data == null ? new ArrayList<>() : data;
if (layoutResId != 0) {
this.mLayoutResId = layoutResId;
}
this.mLayoutHelper = layoutHelper;
}
/**
* 删除一条数据
*/
public void removeItem(int position) {
mData.remove(position);
// 暴力刷新
// notifyDataSetChanged();
// 差量刷新
notifyItemRemoved(position);
}
@Override
public LayoutHelper onCreateLayoutHelper() {
return mLayoutHelper;
}
@NonNull
@Override
public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
VH baseViewHolder = null;
this.mContext = parent.getContext();
this.mLayoutInflater = LayoutInflater.from(mContext);
baseViewHolder = onCreateDefViewHolder(parent, viewType);
return baseViewHolder;
}
@Override
public void onBindViewHolder(@NonNull VH holder, int position) {
VH viewHolder = holder;
bindViewClickListener(viewHolder,position);
convert(holder, getItem(position));
}
@NonNull
public List<T> getData() {
return mData;
}
@Nullable
public T getItem(@IntRange(from = 0) int position) {
if (position >= 0 && position < mData.size())
return mData.get(position);
else
return null;
}
@Override
public int getItemCount() {
return mData.size();
}
private void bindViewClickListener( VH baseViewHolder,int position) {
if (baseViewHolder == null) {
return;
}
final View view = baseViewHolder.itemView;
if (view == null) {
return;
}
if (listener != null) {
view.setOnClickListener(v -> listener.onItemClick(this,v,position));
}
if (longClickListener != null) {
view.setOnLongClickListener(v -> longClickListener.onItemLongClick(BaseDelegateAdapter.this,v,position));
}
}
protected VH onCreateDefViewHolder(ViewGroup parent, int viewType) {
int layoutId = mLayoutResId;
return createBaseViewHolder(parent, layoutId);
}
protected VH createBaseViewHolder(ViewGroup parent, int layoutResId) {
return createViewHolder(getItemView(layoutResId, parent));
}
protected VH createViewHolder(View view) {
Class temp = getClass();
Class z = null;
while (z == null && null != temp) {
z = getInstancedGenericKClass(temp);
temp = temp.getSuperclass();
}
VH k;
// 泛型擦除会导致z为null
if (z == null) {
k = (VH) new BaseDelegateViewHolder(view);
} else {
k = createGenericKInstance(z, view);
}
return k != null ? k : (VH) new BaseDelegateViewHolder(view);
}
/**
* get generic parameter K
*
* @param z
* @return
*/
private Class getInstancedGenericKClass(Class z) {
Type type = z.getGenericSuperclass();
if (type instanceof ParameterizedType) {
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
for (Type temp : types) {
if (temp instanceof Class) {
Class tempClass = (Class) temp;
if (BaseDelegateViewHolder.class.isAssignableFrom(tempClass)) {
return tempClass;
}
} else if (temp instanceof ParameterizedType) {
Type rawType = ((ParameterizedType) temp).getRawType();
if (rawType instanceof Class && BaseDelegateViewHolder.class.isAssignableFrom((Class<?>) rawType)) {
return (Class<?>) rawType;
}
}
}
}
return null;
}
/**
* try to create Generic K instance
*
* @param z
* @param view
* @return
*/
@SuppressWarnings("unchecked")
private VH createGenericKInstance(Class z, View view) {
try {
Constructor constructor;
// inner and unstatic class
if (z.isMemberClass() && !Modifier.isStatic(z.getModifiers())) {
constructor = z.getDeclaredConstructor(getClass(), View.class);
constructor.setAccessible(true);
return (VH) constructor.newInstance(this, view);
} else {
constructor = z.getDeclaredConstructor(View.class);
constructor.setAccessible(true);
return (VH) constructor.newInstance(view);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
protected View getItemView(@LayoutRes int layoutResId, ViewGroup parent) {
return mLayoutInflater.inflate(layoutResId, parent, false);
}
//item点击事件
private OnItemClickListener listener;
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
public interface OnItemClickListener {
void onItemClick(BaseDelegateAdapter adapter,View view,int position);
}
//item长按事件
private OnItemLongClickListener longClickListener;
public void setOnItemLongClickListener(OnItemLongClickListener listener) {
this.longClickListener = listener;
}
public interface OnItemLongClickListener {
boolean onItemLongClick(BaseDelegateAdapter adapter,View view,int position);
}
public abstract void convert(VH holder, T item);
}
感谢https://github.com/CymChad/BaseRecyclerViewAdapterHelper