Android RecyclerView實現(xiàn)多種item布局的方法
在項目中列表是基本都會用到的,然而在顯示列表時,我們需要的數(shù)據可能需要不止一種item顯示,對于復雜的數(shù)據就需要多種item,以不同的樣式顯示出來,這樣效果是很棒的,我們先看一下效果


我們可以看到,這個RecyclerView中有多種item顯示出來,那么具體怎么實現(xiàn)呢,其實在RecyclerView中,我們可以重寫方法getItemViewType(),這個方法會傳進一個參數(shù)position表示當前是第幾個Item,然后我們可以通過position拿到當前的Item對象,然后判斷這個item對象需要那種視圖,返回一個int類型的視圖標志,然后在onCreatViewHolder方法中給引入布局,這樣就能夠實現(xiàn)多種item顯示了,講了這么多我們看一下具體的例子
@Override
public int getItemViewType(int position) {
if(list.size() == 0){
return EMPTY_VIEW;
} else if(list.get(position) == null){
return PROGRESS_VIEW;
} else if(list.get(position).getType().equals(News.IMAGE_NEWS)){
return IMAGE_VIEW;
} else {
return super.getItemViewType(position);
}
}
首先我們重寫了getItemViewType這個方法,在這個方法中根據position對item對象做了一些判斷,如果存儲item對象的集合大小為空,返回空view標識(這里為1),如果item對象為null,返回進度條標識,這個主要是用于實現(xiàn)下拉加載更多,如果item對象類型屬于圖片類型,就返回圖片類型對應的Item,這個就是效果圖中的第一個Item類型,否則就是其它類型,也就是效果圖中的另一種item布局,然后我們在onCreatViewHolder中具體的為每一種類型引入其布局
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if(viewType == PROGRESS_VIEW){
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.progressbar_item, parent, false);
return new ProgressViewHolder(view);
} else if(viewType == EMPTY_VIEW){
return null;
} else if(viewType == IMAGE_VIEW){
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.image_news_item, parent, false);
return new ImageViewHolder(view);
} else {
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false);
return new NewsViewHolder(view);
}
}
上面的代碼就是具體為每種viewType引入其對應的布局,這樣就基本實現(xiàn)了多種item布局,但是僅僅是這些還不夠,因為我們還要對每種item設置數(shù)據,所以還要對每種item寫一個VIewHolder來為item顯示數(shù)據
class NewsViewHolder extends RecyclerView.ViewHolder{
@BindView(R.id.news_title)TextView title;
@BindView(R.id.news_digest)TextView digest;
@BindView(R.id.news_time)TextView time;
@BindView(R.id.news_src)ImageView image;
public NewsViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
class ImageViewHolder extends RecyclerView.ViewHolder{
@BindView(R.id.news_title) TextView title;
@BindView(R.id.image_left) ImageView imageLeft;
@BindView(R.id.image_right) ImageView imageRight;
@BindView(R.id.image_middle) ImageView imageMiddle;
@BindView(R.id.news_time) TextView time;
public ImageViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
class ProgressViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.progressBar) ProgressBar progressBar;
@BindView(R.id.textView) TextView textView;
public ProgressViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
上面就是item對應的幾個ViewHolder,判斷viewHolder屬于那種對象,然后在onBindViewHolder中根據對應的ViewHolder對其控件設置數(shù)據并顯示
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clickListener.onItemClick(v, position);
}
});
if(holder instanceof NewsViewHolder){
NewsViewHolder viewHolder = (NewsViewHolder)holder;
viewHolder.title.setText(list.get(position).getTitle());
viewHolder.time.setText(list.get(position).getTime());
/**
* Glide加載圖片
*/
Glide.with(context).load(list.get(position).getImageUrl().get(0))
.override(dpToPx(72), dpToPx(72)).centerCrop().into(viewHolder.image);
if(list.get(position).getType().equals(News.TEXT_NEWS)){
viewHolder.digest.setText(list.get(position).getDigest());
} else {
viewHolder.digest.setText("");
}
} else if(holder instanceof ImageViewHolder){
ImageViewHolder viewHolder = (ImageViewHolder)holder;
viewHolder.title.setText(list.get(position).getTitle());
viewHolder.time.setText(list.get(position).getTime());
setItemImage(viewHolder, list, position);
} else if(holder instanceof ProgressViewHolder){
ProgressViewHolder viewHolder = (ProgressViewHolder)holder;
viewHolder.progressBar.setIndeterminate(true);
}
}
整個過程基本就是這樣,這種方式在項目中經常會用到,我們就可以這樣去處理,下拉加載更多就可以這樣實現(xiàn),在加載完數(shù)據后再往對象集合中傳入null,然后判斷如果出現(xiàn)null就加載progressBar布局,再加上Google官方的SwipeRefreshLayout,下拉刷新,上拉加載就搞定了,其實很容易,而且也有點Material Design 的感覺~~~~~~
看下Adapter的全部代碼
package com.zmt.e_read.Adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.zmt.e_read.Module.News;
import com.zmt.e_read.Module.OnItemClickListener;
import com.zmt.e_read.R;
import com.zmt.e_read.Utils.ProgressViewHolder;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
* Created by Dangelo on 2016/9/27.
*/
public class NewsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int EMPTY_VIEW = 1;
private final int PROGRESS_VIEW = 2;
private final int IMAGE_VIEW = 3;
private Context context;
private List<News> list;
private OnItemClickListener clickListener;
public NewsAdapter(Context context, List<News> list, OnItemClickListener clickListener) {
this.context = context;
this.list = list;
this.clickListener = clickListener;
}
public void addOnItemClickListener(OnItemClickListener clickListener){
this.clickListener = clickListener;
}
@Override
public int getItemViewType(int position) {
if(list.size() == 0){
return EMPTY_VIEW;
} else if(list.get(position) == null){
return PROGRESS_VIEW;
} else if(list.get(position).getType().equals(News.IMAGE_NEWS)){
return IMAGE_VIEW;
} else {
return super.getItemViewType(position);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if(viewType == PROGRESS_VIEW){
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.progressbar_item, parent, false);
return new ProgressViewHolder(view);
} else if(viewType == EMPTY_VIEW){
return null;
} else if(viewType == IMAGE_VIEW){
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.image_news_item, parent, false);
return new ImageViewHolder(view);
} else {
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false);
return new NewsViewHolder(view);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clickListener.onItemClick(v, position);
}
});
if(holder instanceof NewsViewHolder){
NewsViewHolder viewHolder = (NewsViewHolder)holder;
viewHolder.title.setText(list.get(position).getTitle());
viewHolder.time.setText(list.get(position).getTime());
/**
* Glide加載圖片
*/
Glide.with(context).load(list.get(position).getImageUrl().get(0))
.override(dpToPx(72), dpToPx(72)).centerCrop().into(viewHolder.image);
if(list.get(position).getType().equals(News.TEXT_NEWS)){
viewHolder.digest.setText(list.get(position).getDigest());
} else {
viewHolder.digest.setText("");
}
} else if(holder instanceof ImageViewHolder){
ImageViewHolder viewHolder = (ImageViewHolder)holder;
viewHolder.title.setText(list.get(position).getTitle());
viewHolder.time.setText(list.get(position).getTime());
setItemImage(viewHolder, list, position);
} else if(holder instanceof ProgressViewHolder){
ProgressViewHolder viewHolder = (ProgressViewHolder)holder;
viewHolder.progressBar.setIndeterminate(true);
}
}
public void setItemImage(ImageViewHolder viewHolder, List<News> list, int position){
viewHolder.imageMiddle.setVisibility(View.VISIBLE);
viewHolder.imageRight.setVisibility(View.VISIBLE);
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
if(list.get(position).getImageUrl().size() == 1){
Glide.with(context).load(list.get(position).getImageUrl().get(0))
.override(displayMetrics.widthPixels - dpToPx(10), dpToPx(90))
.centerCrop().into(viewHolder.imageLeft);
viewHolder.imageMiddle.setVisibility(View.GONE);
viewHolder.imageRight.setVisibility(View.GONE);
} else if(list.get(position).getImageUrl().size() == 2){
int imageWidth = (displayMetrics.widthPixels - dpToPx(20)) / 2;
Glide.with(context).load(list.get(position).getImageUrl().get(0))
.override(imageWidth, dpToPx(90))
.centerCrop().into(viewHolder.imageLeft);
Glide.with(context).load(list.get(position).getImageUrl().get(1))
.override(imageWidth, dpToPx(90))
.centerCrop().into(viewHolder.imageMiddle);
viewHolder.imageRight.setVisibility(View.GONE);
} else if(list.get(position).getImageUrl().size() >= 3){
int imageWidth = (displayMetrics.widthPixels - dpToPx(30)) / 3;
Glide.with(context).load(list.get(position).getImageUrl().get(0))
.override(imageWidth, dpToPx(90))
.centerCrop().into(viewHolder.imageLeft);
Glide.with(context).load(list.get(position).getImageUrl().get(1))
.override(imageWidth, dpToPx(90))
.centerCrop().into(viewHolder.imageMiddle);
Glide.with(context).load(list.get(position).getImageUrl().get(2))
.override(imageWidth, dpToPx(90))
.centerCrop().into(viewHolder.imageRight);
}
}
@Override
public int getItemCount() {
return list.size();
}
public int dpToPx(float dp){
float px = context.getResources().getDisplayMetrics().density;
return (int)(dp * px + 0.5f);
}
class NewsViewHolder extends RecyclerView.ViewHolder{
@BindView(R.id.news_title)TextView title;
@BindView(R.id.news_digest)TextView digest;
@BindView(R.id.news_time)TextView time;
@BindView(R.id.news_src)ImageView image;
public NewsViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
class ImageViewHolder extends RecyclerView.ViewHolder{
@BindView(R.id.news_title) TextView title;
@BindView(R.id.image_left) ImageView imageLeft;
@BindView(R.id.image_right) ImageView imageRight;
@BindView(R.id.image_middle) ImageView imageMiddle;
@BindView(R.id.news_time) TextView time;
public ImageViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
class ProgressViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.progressBar) ProgressBar progressBar;
@BindView(R.id.textView) TextView textView;
public ProgressViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
項目地址:https://github.com/xiyouZmt/E-Read
最后說一下為什么為什么用RecyclerView取代ListView。
用過ListView的都知道,在ListView中若要復用視圖緩存,就要在getView()方法中手動判斷convertView是否為空,若不為空則復用視圖緩存,若為空則重新加載視圖,而RecyclerView相當于對ListView的Adapter進行了再次封裝,把ListView手動判斷是否有緩存的代碼封裝到RecyclerView內部,使這部分邏輯不可見,我們只需要通過getItemCount()方法告訴RecyclerView有多少項數(shù)據,然后在onCreateViewHolder()中加載item布局實例化ViewHolder,然后在onBindViewHolder()中完成數(shù)據的綁定即可。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- Android RecyclerView滑動刪除和拖動排序
- Android RecyclerView item選中放大被遮擋問題詳解
- Android使用CardView作為RecyclerView的Item并實現(xiàn)拖拽和左滑刪除
- Android中RecyclerView實現(xiàn)Item添加和刪除的代碼示例
- Android中RecyclerView的item寬高問題詳解
- Android RecyclerView顯示Item布局不一致解決辦法
- Android RecyclerView的Item點擊事件實現(xiàn)整理
- Android 中RecyclerView多種item布局的寫法(頭布局+腳布局)
- Android RecyclerView自由拖動item的實現(xiàn)代碼
相關文章
自定義ListView實現(xiàn)拖拽ListItem項交換位置(附源碼)
本文要實現(xiàn)的是拖拽ListView的Item項,在布局方面還是用基于布局泵LayoutInflater來從不同的Layout模板拿到不同的布局然后將view返回,感興趣的朋友可以了解下哈2013-06-06
Android+Flutter實現(xiàn)彩虹圖案的繪制
彩虹,是氣象中的一種光學現(xiàn)象,當太陽光照射到半空中的水滴,光線被折射及反射,在天空上形成拱形的七彩光譜。接下來,我們就自己手動繪制一下彩虹圖案吧2022-11-11
Android開發(fā)案例手冊Application跳出dialog
這篇文章主要為大家介紹了Android開發(fā)案例手冊Application跳出dialog,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06
Android Compose自定義TextField實現(xiàn)自定義的輸入框
眾所周知Compose中默認的TextField和OutlineTextField樣式并不能滿足所有的使用場景,所以自定義TextField就成了必備技能。本文將自定義TextField實現(xiàn)自定義的輸入框,感興趣的可以了解一下2022-03-03
Android App實現(xiàn)監(jiān)聽軟鍵盤按鍵的三種方式
本篇文章主要介紹Android App實現(xiàn)監(jiān)聽軟鍵盤按鍵的三種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-03-03
詳解Android中使用Notification實現(xiàn)進度通知欄(示例三)
這篇文章主要介紹了詳解Android中使用Notification實現(xiàn)進度通知欄(示例三),具有一定的參考價值,有興趣的可以了解一下。2016-12-12

