[英]Dynamic position of views in RecyclerView
我的問題基於之前關於我的代碼的問題 - 這是一個具有不同視圖的新聞源,可以垂直或水平滾動或顯示各種內容(基本上是廣告)
現在,我在Ben P的幫助下,在我之前的帖子中使用以下代碼組織我的觀點:
this.items = new ArrayList<>();
if (listVertical.size() > 0) {
items.add(listVertical.remove(0));
}
if (listHorizontal.size() > 0) {
items.add(listHorizontal.remove(0));
}
while (listVertical.size() > 0 || listAd.size() > 0) {
if (listAd.size() > 0) {
items.add(listAd.remove(0));
}
int count = 5;
while (count > 0 && listVertical.size() > 0) {
items.add(listVertical.remove(0));
}
}
對於感覺活躍的新聞源,這是靜態的方式。 所以我嘗試用我的JSON中的position元素組織我的視圖,如下所示:
{
"horizontal": [{...,position:"1",},{...,position:"3",...},{...,position:"4",...}] ,
"vertical": [{...,position:"2",},{...,position:"5",},{...,position:"6",}]
"ad": [{...,position:"0",},{...,position:"7",},{...,position:"8",}]
}
使用此代碼,應該可以獲得Feed位置:
int length_tot= vertical.size() + horizontal.size() + ad.size();
this.items = new ArrayList<>();
for(int i = 0; i < lenth_tot; i++) {
if(vertical.getallthepositions_somehow == i) {
items.add(vertical.remove(0));
}
if(horizontal.getallthepositions_somehow == i) {
items.add(horizontal.remove(0));
}
if(ad.getallthepositions_somehow == i) {
items.add(ad.remove(0));
}
}
正如你所看到的,我一直在循環遍歷所有列表,找到要在我的項目列表中添加的下一個位置。
所以我的問題是:
找到下一個要添加的位置的最快方法是什么? 我的解決方案感覺它太沉重了,是否有更經濟的解決方案(從處理器的角度來看)?
這是我的onBindViewHolder
:
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == VIEW_TYPE_VERTICAL)
verticalView((VerticalViewHolder) holder, position);
if (holder.getItemViewType() == VIEW_TYPE_HORIZONTAL)
horizontalView((HorizontalViewHolder) holder, position);
}
來自適配器的getItemViewType
:
@Override
public int getItemViewType(int position) {
if (items.get(position) instanceof Vertical)
return VIEW_TYPE_VERTICAL;
if (items.get(position) instanceof Horizontal)
return VIEW_TYPE_HORIZONTAL;
}
編輯:
那么我正試圖從服務器中獲取我的JSON:
{
"horizontal": [{...,position:"1",},{...,position:"3",...},{...,position:"4",...}] ,
"vertical": [{...,position:"2",},{...,position:"5",},{...,position:"6",}]
"ad": [{...,position:"0",},{...,position:"7",},{...,position:"8",}]
}
是具有以下視圖順序的新聞源:
- [AD] (position=0)
- [HORIZONTAL] (position =1)
- [VERTICAL] (position=2)
- [HORIZONTAL]
- [HORIZONTAL]
等等...
因此,由於每個json-array中的psoition項,服務器基本上決定了我的適配器中的視圖順序
Ben P - 我的清單中正確順序的代碼:
Object[] itemsObject = new Object[listVertical.size() + listHorizontal.size() + adList.size()];
for (Vertical item : listVertical) {
itemsObject[Integer.parseInt(item.getPosition())] = item;
}
for (Horizontal item : listHorizontal) {
itemsObject[Integer.parseInt(item.getPosition())] = item;
}
for (Adfeed item : adList) {
it
ArrayList<Object> itemsPos = new ArrayList<>();
itemsPos.addAll(listVertical);
itemsPos.addAll(listHorizontal);
itemsPos.addAll(adList);
Collections.sort(items, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return Integer.compare(o1.getPosition(),o2.getPosition())
}
});
Vertical,Horizontal和Adfeed包含.getPosition()。 那么如何在我的Comparator中訪問它們?
實際上,無論如何,您需要構建一個項目列表,以便在適配器中傳遞以顯示在RecyclerView
。 因此,循環遍歷每個列表中的所有元素(即水平,垂直和廣告)並不是一個非常糟糕的主意。 您實際上正在對您的項目進行一些預處理,以便在RecyclerView
顯示,以便它可以相應地執行。
在預處理數據時,我可以建議一個小的改進。 在您的代碼中,您必須在每次迭代中再次為每個列表再次遍歷所有元素。 哪個可以實際優化。 考慮到這種預處理是在適配器之外,你可能會做這樣的事情。
int total = vertical.size() + horizontal.size() + ad.size();
int[] types = new int[total];
// Considering the positions are not overlapping.
for(int i = 0; i < vertical.size(); i++) {
types[vertical[i].position] = VIEW_TYPE_VERTICAL;
}
for(int i = 0; i < horizontal.size(); i++) {
types[horizontal[i].position] = VIEW_TYPE_HORIZONTAL;
}
for(int i = 0; i < add.size(); i++) {
types[add[i].position] = VIEW_TYPE_ADD;
}
// The type array has the view types for all elements now.
// Now add the views accordingly in your items list and then pass it to your adapter.
ArrayList<Item> items = new ArrayList<Item>();
for(int i = 0; i < type.length; i++) {
items.add(getItemBasedOnType(type[i]));
}
// Populate your adapter or pass new elements
adapter.addListItems(items);
getItemBasedOnType
可以是這樣的。
private Item getItemBasedOnType(int type) {
if(type == VIEW_TYPE_VERTICAL) return vertical.remove(0);
else if(type == VIEW_TYPE_HORIZONTAL) return horizontal.remove(0);
else return add.remove(0);
}
希望有所幫助。
在實現RecyclerView.Adapter
,您應該努力首先創建一個代表您的數據集的有序列表(或數組)。 如果您可以成功構建此列表,那么其他所有內容將變得非常容易。
為了從您發布的JSON示例構建列表,我會考慮兩種不同的策略。 第一種是使用數組,以便您可以分配特定的索引:
Object[] items = new Object[vertical.size() + horizontal.size() + ad.size()];
for (VerticalItem item : vertical) {
items[item.position] = item;
}
for (HorizontalItem item : horizontal) {
items[item.position] = item;
}
for (AdItem item : ad) {
items[item.position] = item;
}
第二個選項是使用List
,然后使用比較位置的Comparator
對列表進行排序。 這將要求您的三個項類型中的每一個都具有與position
字段共同的超類或實現暴露getPosition()
等的接口。
List<PositionalItem> items = new ArrayList<>();
items.addAll(vertical);
items.addAll(horizontal);
items.addAll(ad);
Collections.sort(items, new Comparator<PositionalItem>() {
@Override
public int compare(PositionalItem lhs, PositionalItem rhs) {
return Integer.compare(lhs.getPosition(), rhs.getPosition());
}
});
這些中的任何一個都會生成一個單獨的排序列表,其中的項目與您希望顯示它們的順序相同。 我們現在可以使用它來實現Adapter
的其余部分。
(這個例子假設您使用Object[]
作為項目列表。如果使用List<PositionalItem>
或類似的東西,顯然語法會略有不同。)
private class MyAdapter extends RecyclerView.Adapter {
private final Object[] items;
public MyAdapter(Object[] items) {
this.items = items;
}
@Override
public int getItemCount() {
return items.length;
}
@Override
public int getItemViewType(int position) {
Object item = items[position];
if (item instanceof VerticalItem) {
return R.layout.newsfeed_vertical;
} else if (item instanceof HorizontalItem) {
return R.layout.newsfeed_horizontal;
} else if (item instanceof AdItem) {
return R.layout.newsfeed_ad;
} else {
throw new IllegalStateException("unexpected item type: " + item);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(viewType, parent, false);
switch (viewType) {
case R.layout.newsfeed_vertical: return new VerticalViewHolder(itemView);
case R.layout.newsfeed_horizontal: return new HorizontalViewHolder(itemView);
case R.layout.newsfeed_ad: return new AdViewHolder(itemView);
default: throw new IllegalStateException("unexpected viewType: " + viewType);
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case R.layout.newsfeed_vertical: verticalView((VerticalViewHolder) holder, position);
case R.layout.newsfeed_horizontal: horizontalView((HorizontalViewHolder) holder, position);
case R.layout.newsfeed_ad: adView((AdViewHolder) holder, position);
default: throw new IllegalStateException("unexpected viewType: " + viewType);
}
}
// ...
}
您會注意到我使用了一種技巧來處理視圖類型:使用布局資源ID而不是int
常量。 沒有必要定義自己的常量; 資源框架已經為您創建了這些常量!
無論如何,我很樂意回答你的任何其他問題。 但這里的主要教訓是擔心先構建你的產品清單,然后用在所有的適配器方法列表 。
而不是使用ArrayList<Object>
,最好為所有三種項類型創建一個接口來實現,並使用它:
public interface NewsfeedItem {
int getPosition();
}
現在,您可以將implements NewsfeedItem
添加到每個類的聲明中:
public class Vertical implements NewsfeedItem {
// ...
}
public class Horizontal implements NewsfeedItem {
// ...
}
public class Adfeed implements NewsfeedItem {
// ...
}
只要每個類都有一個int getPosition()
方法,這將“正常工作”。 看起來好像getPosition()
現在可以返回一個String,所以要么你可以改變接口定義來返回String
要么你可以改變類來返回int
。 無論哪種方式都很好,只要四者相互匹配。
然后,一旦設置了此界面,您就可以更改排序代碼以使用它:
ArrayList<NewsfeedItem> itemsPos = new ArrayList<>();
itemsPos.addAll(listVertical);
itemsPos.addAll(listHorizontal);
itemsPos.addAll(adList);
Collections.sort(items, new Comparator<NewsfeedItem>() {
@Override
public int compare(NewsfeedItem o1, NewsfeedItem o2) {
return Integer.compare(o1.getPosition(),o2.getPosition());
}
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.