尝试为RecyclerView创建通用适配器
已经探索过其他解决方案:
RecyclerView generic adapter with DataBinding
Add click listener to Generic RecyclerView Adapter
https://github.com/ravirupareliya/Recyclerview-Generic-Adapter/blob/master/app/src/main/java/com/rrr/genericrecyclerview/adapter/RecyclerAdapter.java
但是想以一种不同的方式实现它 以下是我的适配器的样子:
public abstract class GenericAdapter<T> extends RecyclerView.Adapter<BaseHolder<T>> {
private OnRecyclerItemClickListener mListener;
private List<T> mItems;
private final LayoutInflater mLayoutInflater;
public GenericAdapter(Context context) {
mLayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mItems = Collections.emptyList();
}
@Override
public BaseHolder<T> onCreateViewHolder(ViewGroup parent, int viewType) {
// assume that viewType is a resource id returned by getItemViewType
// also other solutions are welcome
View view = mLayoutInflater.inflate(viewType, parent, false);
// TODO: how to create the view holder ??
}
@Override
public void onBindViewHolder(BaseHolder<T> holder, int position) {
T item = mItems.get(position);
holder.onBind(item, mListener);
}
@Override
public int getItemCount() {
return mItems != null ? mItems.size() : 0;
}
public void setItems(List<T> items) {
mItems = items;
notifyDataSetChanged();
}
public void setItemClickListener(OnRecyclerItemClickListener listener) {
mListener = listener;
}
}
这是一个基本视图持有者,我希望从中扩展所有其他持有者:
public abstract class BaseHolder<T> extends RecyclerView.ViewHolder {
public BaseHolder(View itemView) {
super(itemView);
}
public abstract void onBind(T item, OnRecyclerItemClickListener listener);
}
问题在于onCreateViewHolder方法
如何创建视图持有者?
我应该以某种方式实现抽象BaseHolder或者我应该以某种方式更改适配器类声明扩展,即在此处使用BaseHolder RecyclerView.Adapter&gt;应该是BaseHolder的一些通用实现?我试过&gt;但它不起作用
提前感谢任何建议
答案 0 :(得分:0)
这就是我在“通用适配器”中所做的:
您传递的持有人类别与您当前的视图相对应,如下所示:
public class FooHolder extends BaseHolder<Foo> {
... // your code with the constructor matching super goes here
}
然后在适配器构造函数中添加一个参数,如下所示:
public GenericAdapter(Context context, Class<? extends BaseHolder> holderClass) {
...
this.holderClass = holderClass;
}
然后在onCreateViewHolder方法中,您可以像这样创建该类的实例:
@Override
public BaseHolder<T> onCreateViewHolder(ViewGroup parent, int viewType) {
...
viewHolder = (BaseHolder) holderClass.getConstructor(View.class).newInstance(view);
}
答案 1 :(得分:0)
如果您想使用单个通用适配器,它们具有不同的2个布局项目和不同的模型用于不同的屏幕,您需要尝试这个:
创建一个java类适配器“ StoreListAdapter.java”
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collection;
/**
* Created by Deepak Sharma on 31/10/17.
*/
public class StoreListAdapter<T> extends RecyclerView.Adapter<StoreListAdapter.ViewHolder> implements Filterable {
private Collection<T> mItems;
private Context context;
private int mLayout;
IClickable iClickable;
private boolean isAnimationAllowed;
private StoreSearchFilter<T> mSearchFilter;
public StoreListAdapter(Context context)
{
this.context = context;
}
public void setData(Collection<T> items, boolean isAnimationAllowed)
{
mItems = items;
this.isAnimationAllowed = isAnimationAllowed;
}
public void setCallback(int layout, IClickable iClickable)
{
this.mLayout = layout;
this.iClickable = iClickable;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(mLayout, viewGroup, false);
iClickable.init(view);
StoreListAdapter.ViewHolder viewHolder = new StoreListAdapter.ViewHolder(view);
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
// viewHolder.itemView.getLayoutParams().width = width;
viewHolder.itemView.getLayoutParams().height = height+24;
return viewHolder;
}
@Override
public void onBindViewHolder(StoreListAdapter.ViewHolder viewHolder, int i) {
iClickable.execute(viewHolder, mItems.toArray()[i],viewHolder.getAdapterPosition());
if (isAnimationAllowed)
setAnimation(viewHolder.itemView, i);
}
@Override
public int getItemCount() {
return mItems.size()>0?mItems.size():0;
}
@Override
public Filter getFilter() {
if (mSearchFilter == null)
mSearchFilter = new StoreSearchFilter<T>((ArrayList<StoreModel>) mItems, new IFilteredList<T>() {
@Override
public void onListFiltered(ArrayList<T> list) {
setData(list, false);
notifyDataSetChanged();
}
});
return mSearchFilter;
}
public class ViewHolder extends RecyclerView.ViewHolder {
private final TextView mTextView;
//private CheckBox mCheckBox;
ViewHolder(View v) {
super(v);
mTextView = (TextView)v.findViewById(R.id.list_item);
}
}
public interface IClickable<T> {
public void init(View view);
public void execute(StoreListAdapter.ViewHolder holder, T object, int position);
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it's animated
/*if (position > lastPosition)
{*/
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
//lastPosition = position;
/*}*/
}
}
创建商店模型“StoreModel.java”:
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Deepak Sharma on 31/10/17.
*/
public class StoreModel implements Parcelable {
private String storeName;
private int storeId;
private String storeAddress;
private String storePhone = "(310)816-2365";
private String storeCity;
private int prizesAvailable;
private double storeLatitude;
private double storeLongitude;
private List<Games> gamesList;
public StoreModel(int id,String sName, String add, String city, int prizes, double lat, double lon, ArrayList<Games> list)
{
this.storeId = id;
this.storeName = sName;
this.storeAddress = add;
this.storeCity = city;
this.prizesAvailable = prizes;
this.storeLatitude = lat;
this.storeLongitude = lon;
this.gamesList = list;
}
public String getStoreName() {
return storeName;
}
public void setStoreName(String storeName) {
this.storeName = storeName;
}
public String getStoreAddress() {
return storeAddress;
}
public void setStoreAddress(String storeAddress) {
this.storeAddress = storeAddress;
}
public String getStoreCity() {
return storeCity;
}
public void setStoreCity(String storeCity) {
this.storeCity = storeCity;
}
public int getPrizesAvailable() {
return prizesAvailable;
}
public void setPrizesAvailable(int prizesAvailable) {
this.prizesAvailable = prizesAvailable;
}
public double getStoreLatitude() {
return storeLatitude;
}
public void setStoreLatitude(double storeLatitude) {
this.storeLatitude = storeLatitude;
}
public double getStoreLongitude() {
return storeLongitude;
}
public void setStoreLongitude(double storeLongitude) {
this.storeLongitude = storeLongitude;
}
public List<Games> getGamesList() {
return gamesList;
}
public void setGamesList(List<Games> gamesList) {
this.gamesList = gamesList;
}
public String getStorePhone() {
return storePhone;
}
public void setStorePhone(String storePhone) {
this.storePhone = storePhone;
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true; //If objects equal, is OK
if (obj == null)
return false;
if (!(obj instanceof StoreModel))
return false;
if (obj instanceof StoreModel) {
StoreModel store = (StoreModel)obj;
return ((storeId == store.storeId) && (storeName.equalsIgnoreCase(store.storeName)));
// return (storeId == store.storeId) && y == store.y);
}
return false;
}
@Override
public int hashCode() {
return storeId;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.storeName);
dest.writeString(this.storeAddress);
dest.writeString(this.storePhone);
dest.writeString(this.storeCity);
dest.writeInt(this.prizesAvailable);
dest.writeDouble(this.storeLatitude);
dest.writeDouble(this.storeLongitude);
dest.writeList(this.gamesList);
}
protected StoreModel(Parcel in) {
this.storeName = in.readString();
this.storeAddress = in.readString();
this.storePhone = in.readString();
this.storeCity = in.readString();
this.prizesAvailable = in.readInt();
this.storeLatitude = in.readDouble();
this.storeLongitude = in.readDouble();
this.gamesList = new ArrayList<Games>();
in.readList(this.gamesList, Games.class.getClassLoader());
}
public static final Parcelable.Creator<StoreModel> CREATOR = new Parcelable.Creator<StoreModel>() {
@Override
public StoreModel createFromParcel(Parcel source) {
return new StoreModel(source);
}
@Override
public StoreModel[] newArray(int size) {
return new StoreModel[size];
}
};
}
创建“store_item.xml”:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/coordinator_game_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/store_item_cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="@android:color/transparent"
card_view:cardElevation="0dp"
android:layout_marginTop="@dimen/dp_five">
<TextView
android:id="@+id/txtStoreName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Store Name"
android:textSize="18sp" />
</android.support.v7.widget.CardView>
</android.support.design.widget.CoordinatorLayout>
现在在Activity或Fragment类中,调用此方法来设置Adapter:
private void setBottomViewAdapter() {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerStore.setHasFixedSize(true);
// use a linear layout manager
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerStore.setLayoutManager(mLayoutManager);
// specify an adapter (see also next example)
mStoreList = new ArrayList<>();
mStoreList.add(new StoreModel(1001, "Von's", "9860 National Blvd., Los Angeles", "Culver City", 12, 28.624035, 77.365541, getGamesList(8)));
mStoreList.add(new StoreModel(1002, "Jack", "1311 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.622665, 77.364082, getGamesList(6)));
mStoreList.add(new StoreModel(1003, "Ian", "1430 S Fairfax Ave., Los Angeles", "Culver City", 8, 28.620899, 77.365258, getGamesList(2)));
mStoreList.add(new StoreModel(1004, "Jessica Alberto", "1372 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.623890, 77.374136, getGamesList(10)));
mStoreList.add(new StoreModel(1005, "Robert", "2545 National Blvd, Los Angeles", "Culver City", 6, 28.631175, 77.375661, getGamesList(4)));
mStoreList.add(new StoreModel(1006, "Clark", "1372 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.627153, 77.381809, getGamesList(11)));
mStoreList.add(new StoreModel(1007, "Jason", "9860 National Blvd., Los Angeles", "Culver City", 12, 28.626569, 77.371963, getGamesList(3)));
mStoreList.add(new StoreModel(1008, "Papon", "1372 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.623155, 77.371677, getGamesList(2)));
mStoreList.add(new StoreModel(1009, "Von's", "2545 National Blvd, Los Angeles", "Culver City", 11, 28.611569, 77.38545, getGamesList(13)));
mStoreList.add(new StoreModel(1010, "Robert Downey Jr.", "1430 S Fairfax Ave., Los Angeles", "Culver City", 8, 28.623127, 77.369113, getGamesList(4)));
mStoreList.add(new StoreModel(1011, "Ben Affleck", "1335 Wilshire Blvd., Santa Monica", "Mid City", 4, 28.62373, 77.39452, getGamesList(12)));
mStoreListAdapter = new StoreListAdapter(getActivity());
boolean isAnimate = false;
mStoreListAdapter.setData(mStoreList, isAnimate);
mStoreListAdapter.setCallback(R.layout.store_item, new StoreListAdapter.IClickable() {
@Override
public void init(View view) {
// Toast.makeText(getActivity(), "Initialized", Toast.LENGTH_SHORT).show();
}
@Override
public void execute(StoreListAdapter.ViewHolder viewHolder, Object object, int position) {
final StoreModel model = (StoreModel) object;
View view = viewHolder.itemView;
StoreListAdapter.ViewHolder holder = viewHolder;
final CoordinatorLayout fabGameview = (CoordinatorLayout) view;
final CardView cardView = (CardView) fabGameview.findViewById(R.id.store_item_cardview);
TextView txtStoreName = (TextView) cardView.findViewById(R.id.txtStoreName);
cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean isAddedToBackStack = true;
StoreDetailsAndProductListFragment storeDetailsAndProductListFragment = new StoreDetailsAndProductListFragment();
Bundle bundle = new Bundle();
bundle.putParcelable(ExtrasUtil.STORE, model);
storeDetailsAndProductListFragment.setArguments(bundle);
showOtherFragment(storeDetailsAndProductListFragment, getActivity().getFragmentManager(), isAddedToBackStack);
}
});
}
});
mRecyclerStore.setAdapter(mStoreListAdapter);
}
创建一个界面:
import java.util.ArrayList;
/**
* Created by Deepak Sharma on 3/8/2017.
*/
public interface IFilteredList<T> {
public void onListFiltered(ArrayList<T> list);
}
创建自定义可过滤类 StoreSearchFilter.java :
import android.widget.Filter;
import java.util.ArrayList;
import java.util.List;
public final class StoreSearchFilter<T> {
// private final Pattern pattern;
private ArrayList<StoreModel> mList;
private IFilteredList<T> callback;
public StoreSearchFilter(final String regex)
{
// pattern = Pattern.compile(regex);
}
public StoreSearchFilter(ArrayList<StoreModel> list, IFilteredList<T> listener)
{
this.mList = list;
this.callback = listener;
}
@Override
protected Filter.FilterResults performFiltering(CharSequence constraint) {
Filter.FilterResults results = new Filter.FilterResults();
if (constraint == null || constraint.length() == 0) {
results.values = mList;
results.count = mList.size();
}
else {
// Some search copnstraint has been passed
// so let's filter accordingly
ArrayList<StoreModel> filteredContacts = new ArrayList<StoreModel>();
if (mList!=null && mList.size()>0)
{
// We'll go through all the contacts and see
// if they contain the supplied string
for (StoreModel model : mList) {
// TODO Here search for the store name match
if (model.getStoreName().toUpperCase().contains(constraint.toString().toUpperCase())) {
// if `contains` == true then add it
// to our filtered list
filteredContacts.add(model);
}
// TODO Here search for the product name match
else {
List<Games> gameList = model.getGamesList();
if (gameList!=null && gameList.size()>0)
{
for (Games game : gameList) {
if (game.getProductName().toUpperCase().contains(constraint.toString().toUpperCase())) {
filteredContacts.add(model);
break;
}
}
}
}
}
}
// Finally set the filtered values and size/count
results.values = filteredContacts;
results.count = filteredContacts.size();
}
// Return our FilterResults object
return results;
}
@Override
protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
callback.onListFiltered((ArrayList<T>) results.values);
}
}
答案 2 :(得分:0)
P.S。已经好久了,但是如果有人感兴趣,
当时我解决了它,并发布在Generic RecyclerView Adapter library中。
最终,创建适配器非常容易。
我仍在几个生产项目中使用它。
编辑: 因此,适配器最终看起来像:
const fetchPromise = fetch(<your params>);
fetchPromise.then(response => {
if (response.ok()){
//Your request was successful
const jsonPromise = response.json();
jsonPromise.then(data => {
console.log("Successful request, parsed json body", data);
}).catch(error => {
//error handling for json parsing errors (empty body etc.)
console.log("Successful request, Could not parse body as json", error);
})
} else {
//Your request was not successful
/*
You can check the body of the response here anyways. Maybe your api does return a json error?
*/
}
}).catch(error => {
//error handling for fetch errors
}))
因此,将ViewHolder的创建委托给适配器实现,即:
public abstract class GenericRecyclerViewAdapter<T, L extends BaseRecyclerListener, VH extends BaseViewHolder<T, L>> extends RecyclerView.Adapter<VH> {
@Override
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
// ...
}
ViewHolder是:
public class SimpleAdapter extends GenericRecyclerViewAdapter<User, OnRecyclerItemClickListener, UserViewHolder> {
// ...
@Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// or return here any specific ViewHolder according to the viewType
return new UserViewHolder(inflate(R.layout.item_user, parent), getListener());
}
}