【问题标题】:RecyclerView with multiple view types and data source具有多种视图类型和数据源的 RecyclerView
【发布时间】:2018-09-15 17:02:42
【问题描述】:

我正在使用 recyclerView,我成功地扩充了两个视图,但每个视图内容来自不同的 json 数据类型。我尝试在适配器中传递这两种数据类型,但它们没有正确绑定

  • 源代码

    公共类 SimpleStringRecyclerViewAdapter : RecyclerView.Adapter {

    private Article[] mValues;
    private List<YouTubeItem> mValues2;
    
    Context context;
    
    public SimpleStringRecyclerViewAdapter(Context context, Article[] items, List<YouTubeItem> item )
    {
        this.context = context;
        mValues = items;
        mValues2 = item;
    }
    
    public override int ItemCount
    {
    
        get
        {
           return mValues.Count() + mValues2.Count();
        }
    }
    
    public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
    {
        if (holder is SimpleViewHolder)
        try
        {
            Article item = mValues[position];
            var simpleHolder = holder as SimpleViewHolder;
    
            simpleHolder.mTxtView.Text = Android.Text.Html.FromHtml(item.Title).ToString();
            simpleHolder.mTxtView2.Text = item.Description;
    
    
            using (var imageView = simpleHolder.mImageView)
            {
                string url = Android.Text.Html.FromHtml(item.UrlToImage).ToString();
    
                //Download and display image
                UrlImageViewHelper.SetUrlDrawable(imageView,
                    url, Resource.Drawable.cheese_1
                    );
    
    
    
            }
            //    simpleHolder.mprogressbar.Visibility = ViewStates.Gone;
        }
        catch (Exception e)
        {
            //Toast.MakeText(this.context, e.ToString(), ToastLength.Long).Show();
        }
        else
        {
            try
            {
                YouTubeItem item = mValues2[position];
                var simpleHolder = holder as SimpleViewHolder2;
    
                simpleHolder.mTxtView.Text = Android.Text.Html.FromHtml(item.Title).ToString();
                // simpleHolder.mTxtView2.Text = item.DescriptionShort;
    
    
                using (var imageView = simpleHolder.mImageView)
                {
                    string url = Android.Text.Html.FromHtml(item.MaxResThumbnailUrl).ToString();
    
                    //Download and display image
                    UrlImageViewHelper.SetUrlDrawable(imageView,
                        url, Resource.Drawable.cheese_1
                        );
    
    
    
                }
            }
            catch (Exception e)
            {
                //Toast.MakeText(this.context, e.ToString(), ToastLength.Long).Show();
            }
    
        }
    }
    
    public override int GetItemViewType(int position)
    {
        if ((position % 2) == 0)
        {
            //Even number
            return Resource.Layout.List_Item;
        }
    
        else
        {
            //Odd number
            return Resource.Layout.VideoList;
        }
    }
    
    
    
    public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
    {
        if (viewType == Resource.Layout.List_Item)
        {
            View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.List_Item, parent, false);
            view.SetBackgroundColor(Color.White);
    
    
            SimpleViewHolder holder = new SimpleViewHolder(view);
            // holder.mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
            // holder.mprogressbar.Visibility = ViewStates.Visible;
    
    
            //Showing loading progressbar
    
            return holder;
        }
        else
        {
            View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.VideoList, parent, false);
            view.SetBackgroundColor(Color.White);
            SimpleViewHolder2 holder = new SimpleViewHolder2(view);
    
            return holder;
        }
    
    }
    

    }

    公共类 SimpleViewHolder : RecyclerView.ViewHolder { 公共字符串 mBoundString; 公共只读视图 mView; 公共只读 ImageView mImageView; 公共只读TextView mTxtView; 公共只读TextView mTxtView2; // public ProgressBar mprogressbar;

    public SimpleViewHolder(View view) : base(view)
    {
        mView = view;
        mImageView = view.FindViewById<ImageView>(Resource.Id.avatar);
        mTxtView = view.FindViewById<TextView>(Resource.Id.Text1);
        mTxtView2 = view.FindViewById<TextView>(Resource.Id.Text2);
        //   mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
    
    
    }
    
    
    
    
    public override string ToString()
    {
        return base.ToString() + " '" + mTxtView.Text;
    
    }
    

    } 公共类 SimpleViewHolder2 : RecyclerView.ViewHolder { 公共字符串 mBoundString; 公共只读视图 mView; 公共只读 ImageView mImageView; 公共只读TextView mTxtView; public readonly TextView mTxtView2;

    public SimpleViewHolder2(View view) : base(view)
    {
        mView = view;
        mImageView = view.FindViewById<ImageView>(Resource.Id.videoavatar);
        mTxtView = view.FindViewById<TextView>(Resource.Id.videoText1);
        //   mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
    
    
    }
    

【问题讨论】:

  • 您必须将两个列表合并为一个。

标签: android android-recyclerview xamarin.android


【解决方案1】:

您应该只将数据合并到一个数据源。你可以这样试试:

  1. 创建数据源类

    public class Data {
       int type; // 1 is article and 2 is youtubeitem
       public Article article;
       public YouTubeItem youTubeItem;
    }
    
  2. 现在将两个数据源合并为一个

    public List<Data> merge(Articel[] articles, List<YouTubeItem> items) {
        List<Data> datas = new ArrayList<>();
        for(Article article : articles) {
           Data data = new Data();
           data.article = article;
           data.youTubeItem = null;
           data.type = 1;
           datas.add(data);
        }
    
        for(YouTubeItem item : items) {
           Data data = new Data();
           data.article = null;
           data.youTubeItem = item;
           data.type = 2;
           datas.add(data);
        }
    
       return datas;
    }
    
  3. 修改适配器的构造函数

    private List<Data> datas;
    
    public SimpleStringRecyclerViewAdapter(Context context, List<Data> datas )
    {
      this.datas = datas;
    }
    
  4. 更改获取项目数

    public override int ItemCount
    {
    
        get
        {
            return datas.Count();
        }
    }
    
  5. 改变getViewType

    public override int GetItemViewType(int position)
    {
       if (datas.get(position).type == 1)
       {
            return Resource.Layout.List_Item;
       }
    
       else
       {
           return Resource.Layout.VideoList;
       }
    }
    

已编辑:用于合并随机方法

 public List<Data> mergeRandom(Articel[] articles, List<YouTubeItem> items) {
     List<Data> datas = new ArrayList<>();

     List<Integer> random = new ArrayList<>();
     int maxLength = articles.length + items.size(); 
     for(int i = 0; i< maxLength; i++) { 
        random.add(i);
     }

     while (random.size() > 0) {
        // get random item
        int index = new Random().nextInt(random.size());
        int position = random.get(index);

        if(position <= article.length - 1) {
            Data data = new Data();
            data.article = articles[position];
            data.youTubeItem = null;
            data.type = 1;
            datas.add(data);
        } else {
            Data data = new Data();
            data.article = null;
            data.youTubeItem = items.get(position - article.length);
            data.type = 2;
            datas.add(data);
        }

        random.remove(index);
    }

    return datas;
 }

用于合并奇偶法

List<Data> mergeOddEven(Articel[] articles, List<YouTubeItem> items) {
    List<Data> datas = new ArrayList<>();

    int articleIndex = 0;
    int youtubeIndex = 0;
    int length = articles.length + items.size();

    for(int i = 0; i< length; i++) {
        if(articleIndex >= articles.length || youtubeIndex >= items.size()) {
            if(articleIndex < articles.length) {
                for(int j = articleIndex; j < articles.length ; j++) {
                   Data data = new Data();
                   data.article = articles[j];
                   data.youTubeItem = null;
                   data.type = 1;
                   datas.add(data);

                }
            } else {
                for(int j = youtubeIndex; j < items.size() ; j++) {
                   Data data = new Data();
                   data.article = null;
                   data.youTubeItem = items.get(j);
                   data.type = 2;
                   datas.add(data);

                }
            }

            break;
        }


        if(i % 2 == 0) {
            Data data = new Data();
            data.article = articles[articleIndex];
            data.youTubeItem = null;
            data.type = 1;
            datas.add(data);

            articleIndex++;
        } else {
            Data data = new Data();
            data.article = null;
            data.youTubeItem = tems.get(youtubeIndex);
            data.type = 2;
            datas.add(data);

            youtubeIndex++;
        }
    }

    return datas;
}

希望对你有帮助

【讨论】:

  • 谢谢,它有帮助,但它首先显示所有文章,然后是 youtube 项目,我真的很乐意让它们随机播放
  • 它依赖于 merge(Article[] 文章, List items) 方法中的逻辑。告诉我你想要哪种洗牌?偶数位置 -> 文章,奇数位置 -> youtubeitem ?或者你想要随机位置的随机项目?
  • 感谢回复,我会喜欢随机位置的随机项目
  • 检查我编辑的答案,我添加了 mergeRandom() 方法
  • 非常感谢,但我内存不足异常,我认为使用奇偶位置会更现实,如果您能提供帮助,我会很高兴
【解决方案2】:

使用此函数合并数据并在您的适配器中使用它:

public List<Data> merge(Articel[] articles, List<YouTubeItem> items) {


        int counter = 0,counter1=0,size=0;


        size = articles.length + items.size();

        List<Data> datas = new ArrayList<>();
        for (int i = 0; i < size;i++) {

            if (i % 2 == 0) {

                if(counter1<articles.length){

                Article article = articles[counter1];
                Data data = new Data();
                data.article = article;
                data.youTubeItem = null;
                data.type = 1;
                datas.add(data);
                counter1++;

                }else if(counter<items.size()){

                 YouTubeItem item = items.get(counter);
                Data data = new Data();
                data.article = null;
                data.youTubeItem = item;
                data.type = 2;
                datas.add(data);
                counter++;
                }

            } else {

                if(counter<items.size()){

                   YouTubeItem item = items.get(counter);
                Data data = new Data();
                data.article = null;
                data.youTubeItem = item;
                data.type = 2;
                datas.add(data);
                counter++;
                }else if(counter1<articles.length){

                Article article = articles[counter1];
                Data data = new Data();
                data.article = article;
                data.youTubeItem = null;
                data.type = 1;
                datas.add(data);
                counter1++;
                }

            }

        }


        return datas;
    }

【讨论】:

  • 谢谢,但我得到 ArgumentOutOfRangeException:索引超出范围。必须为非负数且小于集合的大小。
  • 不,我在合并函数中得到它
  • 谢谢,但在我自己的情况下减去列表仅返回五个项目,因为articles.length = 20 和 items.size() = 15
  • 如果我一次加载数据但如果我需要实现延迟加载功能,例如在用户从回收视图滚动 10 个项目后调用 api,您的答案是好的。所以任何人都可以解释这种情况“?你能检查我的问题吗:stackoverflow.com/questions/53730109/…
【解决方案3】:

创建一个interface 来实现您的数据pojo 类,如下所示..

public interface Parent{
}

然后像pojo类

public class User implements Parent{
    private String name,addres;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddres() {
        return addres;
    }

    public void setAddres(String addres) {
        this.addres = addres;
    }
}

然后将所有数据添加到父列表并绑定到适配器.. 适配器根据 pojo 类绑定数据,如下所示..

public class SearchListAdapter extends ArrayAdapter<Parent> {
    Context context;
    Parent parent[] = null;
        public SearchListAdapter(Context context, int layoutResourceId, Parent[] parent) {
        super(context, layoutResourceId, parent);
        this.context = context;
        this.parent = parent;
    }
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        final View outerContainer = inflater.inflate(R.layout.food_list_item, parent, false);
        if (this.parent != null) {
            Parent temp = this.parent[position];
            if (temp instanceof FoodItem) {
                final FoodItem item = (FoodItem) temp;
            }
        }   
    }
}

【讨论】:

  • 如果我一次加载数据但如果我需要实现延迟加载功能,例如在用户从回收视图滚动 10 个项目后调用 api,您的答案是好的。所以任何人都可以解释这种情况“?你能检查我的问题吗:stackoverflow.com/questions/53730109/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-02
  • 1970-01-01
  • 2020-04-20
相关资源
最近更新 更多