【问题标题】:Multiple row layouts using RecyclerView使用 RecyclerView 的多行布局
【发布时间】:2017-04-08 05:01:32
【问题描述】:

根据this tutorial,我可以一屏在RecyclerView上发布json内容(结果数组)

现在,我将 json 文件更改为:

 "page": 1, 
    "results": [ { ... } ],
    "menus": [ { ... } ]
}, "total_results": 5450, "total_pages": 273 }

现在我想将 menus array 导入到同一屏幕上的 RecyclerView。(在第一行)。 然后导入结果数组

菜单数组没有分页。

我为菜单创建了模型类 (LastMedicMenu.java)。

我是菜鸟。所以现在,我想我必须更换适配器。

原来的适配器是:

原始适配器:

public class MedicPaginationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private static final int ITEM = 0;
    private static final int LOADING = 1;
    private static final String BASE_URL_IMG = "http://www.example.com/api/service/img";

    private List<LastMedicResult> medicResults;
    private Context context;

    private boolean isLoadingAdded = false;

    public MedicPaginationAdapter(Context context) {
        this.context = context;
        medicResults = new ArrayList<>();
    }

    public List<LastMedicResult> getMedics() {
        return medicResults;
    }


    public void setMedics(List<LastMedicResult> medicResults) {
        this.medicResults = medicResults;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder viewHolder = null;
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        switch (viewType) {
            case ITEM:
                viewHolder = getViewHolder(parent, inflater);
                break;
            case LOADING:
                View v2 = inflater.inflate(R.layout.item_progress, parent, false);
                viewHolder = new LoadingVH(v2);
                break;
        }
        return viewHolder;
    }

    @NonNull
    private RecyclerView.ViewHolder getViewHolder(ViewGroup parent, LayoutInflater inflater) {
        RecyclerView.ViewHolder viewHolder;
        View v1 = inflater.inflate(R.layout.service_list, parent, false);
        viewHolder = new MedicVH(v1);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        LastMedicResult result = medicResults.get(position); // Movie

        switch (getItemViewType(position)) {
            case ITEM:
                final MedicVH MedicVH = (MedicVH) holder;

                MedicVH.mMovieTitle.setText(result.getTitle());



                MedicVH.sLocation.setText(result.getServiceLocation());
                MedicVH.sType.setText(result.getServiceType());
                MedicVH.mMovieDesc.setText(result.getOverview());


                Glide
                        .with(context)
                        .load(BASE_URL_IMG + result.getPosterPath())
                        .listener(new RequestListener<String, GlideDrawable>() {
                            @Override
                            public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
                                // TODO: 08/11/16 handle failure
                                MedicVH.mProgress.setVisibility(View.GONE);
                                return false;
                            }

                            @Override
                            public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                                // image ready, hide progress now
                                MedicVH.mProgress.setVisibility(View.GONE);
                                return false;   // return false if you want Glide to handle everything else.
                            }
                        })
                        .diskCacheStrategy(DiskCacheStrategy.ALL)   // cache both original & resized image
                        .centerCrop()
                        .crossFade()
                        .into(MedicVH.mPosterImg);



                break;

            case LOADING:
//                Do nothing
                break;
        }

    }

    @Override
    public int getItemCount() {
        return medicResults == null ? 0 : medicResults.size();
    }

    @Override
    public int getItemViewType(int position) {
        return (position == medicResults.size() - 1 && isLoadingAdded) ? LOADING : ITEM;
    }


    /*
   Helpers
    */

    public void add(LastMedicResult r) {
        medicResults.add(r);
        notifyItemInserted(medicResults.size() - 1);
    }

    public void addAll(List<LastMedicResult> moveResults) {
        for (LastMedicResult result : moveResults) {
            add(result);
        }
    }

    public void remove(LastMedicResult r) {
        int position = medicResults.indexOf(r);
        if (position > -1) {
            medicResults.remove(position);
            notifyItemRemoved(position);
        }
    }

    public void clear() {
        isLoadingAdded = false;
        while (getItemCount() > 0) {
            remove(getItem(0));
        }
    }

    public boolean isEmpty() {
        return getItemCount() == 0;
    }


    public void addLoadingFooter() {
        isLoadingAdded = true;
        add(new LastMedicResult());
    }

    public void removeLoadingFooter() {
        isLoadingAdded = false;

        int position = medicResults.size() - 1;
        LastMedicResult result = getItem(position);

        if (result != null) {
            medicResults.remove(position);
            notifyItemRemoved(position);
        }
    }

    public LastMedicResult getItem(int position) {
        return medicResults.get(position);
    }


    protected class MedicVH extends RecyclerView.ViewHolder {
        private TextView mMovieTitle;
        private TextView mMovieDesc;
        private TextView sLocation;
        private TextView sType;
        private ImageView mPosterImg;
        private ProgressBar mProgress;

        public MedicVH(View itemView) {
            super(itemView);

            mMovieTitle = (TextView) itemView.findViewById(R.id.movie_title);


            mMovieDesc = (TextView) itemView.findViewById(R.id.movie_desc);



            sLocation = (TextView) itemView.findViewById(R.id.service_location);


            sType = (TextView) itemView.findViewById(R.id.service_type);


            mPosterImg = (ImageView) itemView.findViewById(R.id.movie_poster);
            mProgress = (ProgressBar) itemView.findViewById(R.id.movie_progress);

        }
    }


    protected class LoadingVH extends RecyclerView.ViewHolder {

        public LoadingVH(View itemView) {
            super(itemView);
        }
    }


}

请查看我的更改步骤:

1- 原代码:

private static final int ITEM = 0; // for search
private static final int LOADING = 1;// for progress bar

更改代码:

private static final int ITEM = 0; // for search
private static final int MENU = 1; // for search1
private static final int LOADING = 2;// for progress bar

2-

public MedicPaginationAdapter(Context context) {
        this.context = context;
        medicResults = new ArrayList<>();
    }

public MedicPaginationAdapter(Context context) {
    this.context = context;
    medicResults = new ArrayList<>();
    medicMenus = new ArrayList<>();
}

第 3 步:

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder viewHolder = null;
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        switch (viewType) {
            case ITEM:
                viewHolder = getViewHolder(parent, inflater);
                break;
            case LOADING:
                View v2 = inflater.inflate(R.layout.item_progress, parent, false);
                viewHolder = new LoadingVH(v2);
                break;
        }
        return viewHolder;
    }

@Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder viewHolder = null;
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        switch (viewType) {
            case ITEM:
                viewHolder = getViewHolder(parent, inflater,viewType);
                break;
            case MENU:
            viewHolder = getViewHolder(parent, inflater,viewType);
                break;
            case LOADING:
                View v2 = inflater.inflate(R.layout.item_progress, parent, false);
                viewHolder = new LoadingVH(v2);
                break;
        }
        return viewHolder;
    }

第四步:

private RecyclerView.ViewHolder getViewHolder(ViewGroup parent, LayoutInflater inflater) {
        RecyclerView.ViewHolder viewHolder;
        View v1 = inflater.inflate(R.layout.service_list, parent, false);
        viewHolder = new MedicVH(v1);
        return viewHolder;
    }

private RecyclerView.ViewHolder getViewHolder(ViewGroup parent, LayoutInflater inflater, int viewType) {
        RecyclerView.ViewHolder viewHolder;
        View v1;
        if(ITEM == viewType)
        {
            v1 = inflater.inflate(R.layout.service_list, parent, false);
            viewHolder = new MedicVH(v1);
        }
        else
        {
            v1 = inflater.inflate(R.layout.service_munu_list, parent, false);
            viewHolder = new MedicMenuVH(v1);
        }
        return viewHolder;
    }

第 5 步:

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        LastMedicResult result = medicResults.get(position); 


        switch (getItemViewType(position)) {
            case ITEM:
                final MedicVH MedicVH = (MedicVH) holder;

                MedicVH.mMovieTitle.setText(result.getTitle());
                ...


                break;

            case LOADING:
                   //Do nothing
                break;
        }

    }

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    LastMedicResult result = medicResults.get(position); 
    LastMedicResult menu = medicMenus.get(position); 
    switch (getItemViewType(position)) {
        case ITEM:
            final MedicVH MedicVH = (MedicVH) holder;

            MedicVH.mMovieTitle.setText(result.getTitle());
            ...


            break;
        case MENU:
            final MedicMenuVH MedicMenuVH = (MedicMenuVH) holder;

            MedicMenuVH .mMenuTitle.setText(menu.getTitle());
            ...


            break;


        case LOADING:
               //Do nothing
            break;
    }

}

第六步:

@Override
    public int getItemViewType(int position) {
        return (position == medicResults.size() - 1 && isLoadingAdded) ? LOADING : ITEM;
    }

public int getItemViewType(int position) {
        //return (position == medicResults.size() - 1 && isLoadingAdded) ? ITEM : ITEM;
        if(medicResults.get(position) instanceof LastMedicResult)
        {
            return (position == medicResults.size() - 1 && isLoadingAdded) ? LOADING : ITEM;
        }
        else if(medicMenus.get(position) instanceof LastMedicMenu)
        {
            return (position == medicMenus.size() - 1 && isLoadingAdded) ? LOADING : MENU;
        }
        else
        {
            return LOADING;
        }
    }

第 7 步: 并且最后添加这个类:

protected class MedicMenuVH extends RecyclerView.ViewHolder {
        private TextView mMenuTitle;


        public MedicMenuVH(View itemView) {
            super(itemView);

            mMenuTitle = (TextView) itemView.findViewById(R.id.menu_title);

        }
    }

全部更改后,只能在RecyclerView中显示结果数组

我的代码有什么问题?可以请告诉我我该怎么做吗?

编辑

根据答案,我将步骤 5 更改为:

@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        LastMedicResult result = medicResults.get(position); // result
        LastMedicMenu menu = medicMenus.get(position);

        switch (getItemViewType(position)) {
            case ITEM:
                final MedicVH MedicVH = (MedicVH) holder;

                MedicVH.mMovieTitle.setText(result.getTitle());

                break;
            case MENU:
            {
                final MedicMenuVH MedicMenuVH = (MedicMenuVH) holder;

                MedicMenuVH.mMenuTitle.setText(menu.getTitle());
                break;
            }
            case LOADING:
                //  Do nothing
                break;
        }

    }

但我在此行的错误日志中收到错误(应用程序将崩溃):

LastMedicMenu menu = medicMenus.get(position);

我之前为菜单创建了模型类。

为什么会出现这个错误?

04-08 14:34:55.954 15584-15584/com.example.teb E/AndroidRuntime: 致命 例外:主要 java.lang.IndexOutOfBoundsException:索引 0 无效,大小为 0 在 java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251) 在 java.util.ArrayList.get(ArrayList.java:304) 在 com.example.teb.MedicPaginationAdapter.onBindViewHolder(MedicPaginationAdapter.java:105)

【问题讨论】:

    标签: android android-recyclerview android-adapter android-json


    【解决方案1】:

    如果您已经有菜单的模型类,在 onBindViewHolder() 中只需将视图设置为绑定 菜单,然后再生成您拥有的布局。

     LastMedicResult result = medicResults.get(position); 
     LastMedicMenus menus = medicMenus.get(position); //Custom Name 
    
        switch (getItemViewType(position)) {
            case ITEM:
                final MedicVH MedicVH = (MedicVH) holder;
    
                MedicVH.mMovieTitle.setText(result.getTitle());
                MedicVH.mMovieName.setText(menus.getFoo()); //This way
                ...
    
                break;
           ...
        }
    }
    

    【讨论】:

      【解决方案2】:

      您在 onBindViewHolder 中使用了 medicResults 而不是 medicMenus

      LastMedicResult 结果 = medicResults.get(position);

      问题是result.getTitle()

      case MENU:
         final MedicMenuVH MedicMenuVH = (MedicMenuVH) holder;
         MedicMenuVH .mMenuTitle.setText(result.getTitle());
         ...
      break;
      

      你的 onBindViewHolder 应该是这样的

      public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
      
      switch (getItemViewType(position)) {
          case ITEM:
              LastMedicResult result = medicResults.get(position); 
              final MedicVH MedicVH = (MedicVH) holder;
      
              MedicVH.mMovieTitle.setText(result.getTitle());
              ...
      
      
              break;
          case MENU:
              LastMedicMenus menus = medicMenus.get(position);
              final MedicMenuVH MedicMenuVH = (MedicMenuVH) holder;
      
              MedicMenuVH .mMenuTitle.setText(menus.getTitle());
              ...
      
      
              break;
      
      
          case LOADING:
                 //Do nothing
              break;
      }
      
      }
      

      【讨论】:

      • 不幸的是。你能检查我的更新吗? (问题结束)
      • 查看更新的答案!。我已将获取项目代码放在 case 中,第二件事你的菜单列表是空的,这就是你得到 indexoutofbound 的原因
      猜你喜欢
      • 1970-01-01
      • 2015-09-03
      • 1970-01-01
      • 2021-07-09
      • 1970-01-01
      • 1970-01-01
      • 2016-04-21
      • 2022-01-16
      • 1970-01-01
      相关资源
      最近更新 更多