簡體   English   中英

RecyclerView中視圖的動態位置

[英]Dynamic position of views in RecyclerView

我的問題基於之前關於我的代碼的問題 - 這是一個具有不同視圖的新聞源,可以垂直或水平滾動或顯示各種內容(基本上是廣告)

  • 垂直視圖
  • 水平視圖
  • AD VIEW

現在,我在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,Horizo​​ntal和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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM