theo giải pháp của Anton, hãy đưa ra giải pháp này ViewHolder
chứa / xử lý / ủy nhiệm các loại bố cục khác nhau. Nhưng không chắc cách bố trí thay thế mới có hoạt động khi chế độ xem tái chế khôngViewHolder
không phải là loại cuộn dữ liệu.
Nên về cơ bản,
onCreateViewHolder(ViewGroup parent, int viewType)
chỉ được gọi khi cần bố trí chế độ xem mới;
getItemViewType(int position)
sẽ được gọi cho viewType
;
onBindViewHolder(ViewHolder holder, int position)
luôn được gọi khi tái chế chế độ xem (dữ liệu mới được đưa vào và cố gắng hiển thị với chế độ xem đó ViewHolder
).
Vì vậy, khi onBindViewHolder
được gọi, nó cần đặt trong bố cục xem đúng và cập nhậtViewHolder
.
Là cách chính xác để thay thế bố cục khung nhìn cho điều đó ViewHolder
sẽ được đưa vào, hoặc bất kỳ vấn đề? Đánh giá cao bất kỳ bình luận!
public int getItemViewType(int position) {
TypedData data = mDataSource.get(position);
return data.type;
}
public ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
return ViewHolder.makeViewHolder(parent, viewType);
}
public void onBindViewHolder(ViewHolder holder,
int position) {
TypedData data = mDataSource.get(position);
holder.updateData(data);
}
///
public static class ViewHolder extends
RecyclerView.ViewHolder {
ViewGroup mParentViewGroup;
View mCurrentViewThisViewHolderIsFor;
int mDataType;
public TypeOneViewHolder mTypeOneViewHolder;
public TypeTwoViewHolder mTypeTwoViewHolder;
static ViewHolder makeViewHolder(ViewGroup vwGrp,
int dataType) {
View v = getLayoutView(vwGrp, dataType);
return new ViewHolder(vwGrp, v, viewType);
}
static View getLayoutView(ViewGroup vwGrp,
int dataType) {
int layoutId = getLayoutId(dataType);
return LayoutInflater.from(vwGrp.getContext())
.inflate(layoutId, null);
}
static int getLayoutId(int dataType) {
if (dataType == TYPE_ONE) {
return R.layout.type_one_layout;
} else if (dataType == TYPE_TWO) {
return R.layout.type_two_layout;
}
}
public ViewHolder(ViewGroup vwGrp, View v,
int dataType) {
super(v);
mDataType = dataType;
mParentViewGroup = vwGrp;
mCurrentViewThisViewHolderIsFor = v;
if (data.type == TYPE_ONE) {
mTypeOneViewHolder = new TypeOneViewHolder(v);
} else if (data.type == TYPE_TWO) {
mTypeTwoViewHolder = new TypeTwoViewHolder(v);
}
}
public void updateData(TypeData data) {
mDataType = data.type;
if (data.type == TYPE_ONE) {
mTypeTwoViewHolder = null;
if (mTypeOneViewHolder == null) {
View newView = getLayoutView(mParentViewGroup,
data.type);
/**
* how to replace new view with
the view in the parent
view container ???
*/
replaceView(mCurrentViewThisViewHolderIsFor,
newView);
mCurrentViewThisViewHolderIsFor = newView;
mTypeOneViewHolder =
new TypeOneViewHolder(newView);
}
mTypeOneViewHolder.updateDataTypeOne(data);
} else if (data.type == TYPE_TWO){
mTypeOneViewHolder = null;
if (mTypeTwoViewHolder == null) {
View newView = getLayoutView(mParentViewGroup,
data.type);
/**
* how to replace new view with
the view in the parent view
container ???
*/
replaceView(mCurrentViewThisViewHolderIsFor,
newView);
mCurrentViewThisViewHolderIsFor = newView;
mTypeTwoViewHolder =
new TypeTwoViewHolder(newView);
}
mTypeTwoViewHolder.updateDataTypeOne(data);
}
}
}
public static void replaceView(View currentView,
View newView) {
ViewGroup parent = (ViewGroup)currentView.getParent();
if(parent == null) {
return;
}
final int index = parent.indexOfChild(currentView);
parent.removeView(currentView);
parent.addView(newView, index);
}
Biên tập: ViewHolder có thành viên mItemViewType để giữ chế độ xem
Biên tập: trông giống như trong onBindViewHolder (người giữ ViewHolder, vị trí int) mà ViewHolder được truyền vào đã được chọn (hoặc tạo) bằng cách xem getItemViewType (vị trí int) để đảm bảo rằng đó là một trận đấu, vì vậy có thể không cần phải lo lắng về điều đó của ViewHolder loại không khớp với loại dữ liệu [vị trí]. Có ai biết thêm về cách ViewHolder trong onBindViewHolder () được chọn không?
Chỉnh sửa: Có vẻ như Tái chế ViewHolder
được chọn theo loại, vì vậy không có chiến binh nào ở đó.
Chỉnh sửa: http://wiresareobsolete.com/2014/09/building-a-recyclerview-layoutmanager-part-1/ trả lời câu hỏi này.
Nó được tái chế ViewHolder
như:
holder = getRecycledViewPool().getRecycledView(mAdapter.getItemViewType(offsetPosition));
hoặc tạo cái mới nếu không tìm thấy tái chế ViewHolder
đúng loại.
public ViewHolder getRecycledView(int viewType) {
final ArrayList<ViewHolder> scrapHeap = mScrap.get(viewType);
if (scrapHeap != null && !scrapHeap.isEmpty()) {
final int index = scrapHeap.size() - 1;
final ViewHolder scrap = scrapHeap.get(index);
scrapHeap.remove(index);
return scrap;
}
return null;
}
View getViewForPosition(int position, boolean dryRun) {
......
if (holder == null) {
final int offsetPosition = mAdapterHelper.findPositionOffset(position);
if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) {
throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item "
+ "position " + position + "(offset:" + offsetPosition + ")."
+ "state:" + mState.getItemCount());
}
final int type = mAdapter.getItemViewType(offsetPosition);
// 2) Find from scrap via stable ids, if exists
if (mAdapter.hasStableIds()) {
holder = getScrapViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);
if (holder != null) {
// update position
holder.mPosition = offsetPosition;
fromScrap = true;
}
}
if (holder == null && mViewCacheExtension != null) {
// We are NOT sending the offsetPosition because LayoutManager does not
// know it.
final View view = mViewCacheExtension
.getViewForPositionAndType(this, position, type);
if (view != null) {
holder = getChildViewHolder(view);
if (holder == null) {
throw new IllegalArgumentException("getViewForPositionAndType returned"
+ " a view which does not have a ViewHolder");
} else if (holder.shouldIgnore()) {
throw new IllegalArgumentException("getViewForPositionAndType returned"
+ " a view that is ignored. You must call stopIgnoring before"
+ " returning this view.");
}
}
}
if (holder == null) { // fallback to recycler
// try recycler.
// Head to the shared pool.
if (DEBUG) {
Log.d(TAG, "getViewForPosition(" + position + ") fetching from shared "
+ "pool");
}
holder = getRecycledViewPool()
.getRecycledView(mAdapter.getItemViewType(offsetPosition));
if (holder != null) {
holder.resetInternal();
if (FORCE_INVALIDATE_DISPLAY_LIST) {
invalidateDisplayListInt(holder);
}
}
}
if (holder == null) {
holder = mAdapter.createViewHolder(RecyclerView.this,
mAdapter.getItemViewType(offsetPosition));
if (DEBUG) {
Log.d(TAG, "getViewForPosition created new ViewHolder");
}
}
}
boolean bound = false;
if (mState.isPreLayout() && holder.isBound()) {
// do not update unless we absolutely have to.
holder.mPreLayoutPosition = position;
} else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
if (DEBUG && holder.isRemoved()) {
throw new IllegalStateException("Removed holder should be bound and it should"
+ " come here only in pre-layout. Holder: " + holder);
}
final int offsetPosition = mAdapterHelper.findPositionOffset(position);
mAdapter.bindViewHolder(holder, offsetPosition);
attachAccessibilityDelegate(holder.itemView);
bound = true;
if (mState.isPreLayout()) {
holder.mPreLayoutPosition = position;
}
}
final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
final LayoutParams rvLayoutParams;
if (lp == null) {
rvLayoutParams = (LayoutParams) generateDefaultLayoutParams();
holder.itemView.setLayoutParams(rvLayoutParams);
} else if (!checkLayoutParams(lp)) {
rvLayoutParams = (LayoutParams) generateLayoutParams(lp);
holder.itemView.setLayoutParams(rvLayoutParams);
} else {
rvLayoutParams = (LayoutParams) lp;
}
rvLayoutParams.mViewHolder = holder;
rvLayoutParams.mPendingInvalidate = fromScrap && bound;
return holder.itemView;
}