Android RecyclerView.Adapter onCreateViewHolder() 工作
Android RecyclerView.Adapter onCreateViewHolder() working
我正在使用 RecyclerView.Adapter,但我对其方法 onCreateViewHolder
的工作方式有些困惑。
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if(viewType==TYPE_ITEM) {
View mView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.inflate_common_item, viewGroup, false);
ViewHolder vh = new ViewHolder(mView);
return vh;
} else {
View mView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.inflate_uncommon_item, viewGroup, false);
ViewHolderFooter vh = new ViewHolderFooter(mView);
return vh;
}
}
所以如果我的列表中有 10 个项目,那么对于每个项目都会调用此方法,并且每次都会创建一个新的 ViewHolder
当然每个视图都会调用一次,但现在我的问题当我们使用 ListView
和 BaseAdapter
时,我们将 ViewHolder
存储在标签中并使用它。我们不会为每个项目创建 ViewHolder
。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
MyViewHolder mViewHolder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.layout_list_item, null);
mViewHolder = new MyViewHolder();
convertView.setTag(mViewHolder);
} else {
mViewHolder = (MyViewHolder) convertView.getTag();
}
mViewHolder.tvTitle = detail(convertView, R.id.tvTitle, myList.get(position).getTitle());
mViewHolder.tvDesc = detail(convertView, R.id.tvDesc, myList.get(position).getDescription());
mViewHolder.ivIcon = detail(convertView, R.id.ivIcon, myList.get(position).getImgResId());
return convertView;
}
我们不是在创建额外的 viewholders 对象吗?请帮助我了解利弊。
谢谢
onCreateViewHolder
仅在没有 RecyclerView
可以重用的现有视图持有者时创建新的视图持有者。因此,例如,如果您的 RecyclerView
可以一次显示 5 个项目,它将创建 5-6 个 ViewHolders
,然后自动重用它们,每次调用 onBindViewHolder
。
它类似于 ListView
中的代码(检查 convertView
是否为 null
,如果不是,则从标签中获取现有的 ViewHolder
) , 除了 RecyclerView
, 这都是自动完成的。
我想这是使用 RecyclerView
的优点之一 - 您不必像使用 ListView
那样担心重用 ViewHolders
。缺点是,RecyclerView
非常可定制,但内置功能很少 - 不像 ListView
不是很可定制,但有很多内置功能。
你可以使用这个:
--> 创建一个构造器:
/**
* 由 Deepak Sharma 于 2017 年 10 月 31 日创建。
*/
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);
// Handle item click and set the selection
/*v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Redraw the old selection and the new
notifyItemChanged(selectedItem);
selectedItem = getLayoutPosition();
notifyItemChanged(selectedItem);
}
});*/
}
}
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)
{
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
}
}
--> 在你Activity/Fragment :
ArrayList<StoreModel> mStoreList = new ArrayList<>();
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);
TextView txtStoreAddress = (TextView) cardView.findViewById(R.id.txtStoreAddress);
TextView txtStoreCity = (TextView) cardView.findViewById(R.id.txtStoreCity);
TextView txtPrizes = (TextView) cardView.findViewById(R.id.txtPrizes);
txtStoreName.setText(model.getStoreName());
txtStoreAddress.setText(model.getStoreAddress());
txtStoreCity.setText(model.getStoreCity());
txtPrizes.setText(String.valueOf(model.getPrizesAvailable()));
LinearLayout linearDetails = (LinearLayout) cardView.findViewById(R.id.linearDetails);
LinearLayout linearPrize = (LinearLayout) cardView.findViewById(R.id.linearPrize);
if (clickedMarkerModel != null && clickedMarkerModel == model) {
holder.itemView.setSelected(true);
// holder.itemView.setPressed(true);
// linearDetails.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
// linearPrize.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
// mRecyclerStore.stopScroll();
} else {
holder.itemView.setSelected(false);
// holder.itemView.setPressed(false);
// linearDetails.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.store_selector));
// linearPrize.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.store_selector));
}
// TODO Here scroll recycler view upto selected item
/*mRecyclerStore.smoothScrollToPosition(mStoreListAdapter.getItemCount() - 1);*/
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);
我正在使用 RecyclerView.Adapter,但我对其方法 onCreateViewHolder
的工作方式有些困惑。
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if(viewType==TYPE_ITEM) {
View mView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.inflate_common_item, viewGroup, false);
ViewHolder vh = new ViewHolder(mView);
return vh;
} else {
View mView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.inflate_uncommon_item, viewGroup, false);
ViewHolderFooter vh = new ViewHolderFooter(mView);
return vh;
}
}
所以如果我的列表中有 10 个项目,那么对于每个项目都会调用此方法,并且每次都会创建一个新的 ViewHolder
当然每个视图都会调用一次,但现在我的问题当我们使用 ListView
和 BaseAdapter
时,我们将 ViewHolder
存储在标签中并使用它。我们不会为每个项目创建 ViewHolder
。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
MyViewHolder mViewHolder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.layout_list_item, null);
mViewHolder = new MyViewHolder();
convertView.setTag(mViewHolder);
} else {
mViewHolder = (MyViewHolder) convertView.getTag();
}
mViewHolder.tvTitle = detail(convertView, R.id.tvTitle, myList.get(position).getTitle());
mViewHolder.tvDesc = detail(convertView, R.id.tvDesc, myList.get(position).getDescription());
mViewHolder.ivIcon = detail(convertView, R.id.ivIcon, myList.get(position).getImgResId());
return convertView;
}
我们不是在创建额外的 viewholders 对象吗?请帮助我了解利弊。
谢谢
onCreateViewHolder
仅在没有 RecyclerView
可以重用的现有视图持有者时创建新的视图持有者。因此,例如,如果您的 RecyclerView
可以一次显示 5 个项目,它将创建 5-6 个 ViewHolders
,然后自动重用它们,每次调用 onBindViewHolder
。
它类似于 ListView
中的代码(检查 convertView
是否为 null
,如果不是,则从标签中获取现有的 ViewHolder
) , 除了 RecyclerView
, 这都是自动完成的。
我想这是使用 RecyclerView
的优点之一 - 您不必像使用 ListView
那样担心重用 ViewHolders
。缺点是,RecyclerView
非常可定制,但内置功能很少 - 不像 ListView
不是很可定制,但有很多内置功能。
你可以使用这个:
--> 创建一个构造器:
/** * 由 Deepak Sharma 于 2017 年 10 月 31 日创建。 */
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);
// Handle item click and set the selection
/*v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Redraw the old selection and the new
notifyItemChanged(selectedItem);
selectedItem = getLayoutPosition();
notifyItemChanged(selectedItem);
}
});*/
}
}
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)
{
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
}
}
--> 在你Activity/Fragment :
ArrayList<StoreModel> mStoreList = new ArrayList<>();
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);
TextView txtStoreAddress = (TextView) cardView.findViewById(R.id.txtStoreAddress);
TextView txtStoreCity = (TextView) cardView.findViewById(R.id.txtStoreCity);
TextView txtPrizes = (TextView) cardView.findViewById(R.id.txtPrizes);
txtStoreName.setText(model.getStoreName());
txtStoreAddress.setText(model.getStoreAddress());
txtStoreCity.setText(model.getStoreCity());
txtPrizes.setText(String.valueOf(model.getPrizesAvailable()));
LinearLayout linearDetails = (LinearLayout) cardView.findViewById(R.id.linearDetails);
LinearLayout linearPrize = (LinearLayout) cardView.findViewById(R.id.linearPrize);
if (clickedMarkerModel != null && clickedMarkerModel == model) {
holder.itemView.setSelected(true);
// holder.itemView.setPressed(true);
// linearDetails.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
// linearPrize.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
// mRecyclerStore.stopScroll();
} else {
holder.itemView.setSelected(false);
// holder.itemView.setPressed(false);
// linearDetails.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.store_selector));
// linearPrize.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.store_selector));
}
// TODO Here scroll recycler view upto selected item
/*mRecyclerStore.smoothScrollToPosition(mStoreListAdapter.getItemCount() - 1);*/
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);