Android RecyclerView實(shí)現(xiàn)多種item布局的方法
在項(xiàng)目中列表是基本都會(huì)用到的,然而在顯示列表時(shí),我們需要的數(shù)據(jù)可能需要不止一種item顯示,對(duì)于復(fù)雜的數(shù)據(jù)就需要多種item,以不同的樣式顯示出來(lái),這樣效果是很棒的,我們先看一下效果
我們可以看到,這個(gè)RecyclerView中有多種item顯示出來(lái),那么具體怎么實(shí)現(xiàn)呢,其實(shí)在RecyclerView中,我們可以重寫方法getItemViewType(),這個(gè)方法會(huì)傳進(jìn)一個(gè)參數(shù)position表示當(dāng)前是第幾個(gè)Item,然后我們可以通過position拿到當(dāng)前的Item對(duì)象,然后判斷這個(gè)item對(duì)象需要那種視圖,返回一個(gè)int類型的視圖標(biāo)志,然后在onCreatViewHolder方法中給引入布局,這樣就能夠?qū)崿F(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這個(gè)方法,在這個(gè)方法中根據(jù)position對(duì)item對(duì)象做了一些判斷,如果存儲(chǔ)item對(duì)象的集合大小為空,返回空view標(biāo)識(shí)(這里為1),如果item對(duì)象為null,返回進(jìn)度條標(biāo)識(shí),這個(gè)主要是用于實(shí)現(xiàn)下拉加載更多,如果item對(duì)象類型屬于圖片類型,就返回圖片類型對(duì)應(yīng)的Item,這個(gè)就是效果圖中的第一個(gè)Item類型,否則就是其它類型,也就是效果圖中的另一種item布局,然后我們?cè)趏nCreatViewHolder中具體的為每一種類型引入其布局
@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引入其對(duì)應(yīng)的布局,這樣就基本實(shí)現(xiàn)了多種item布局,但是僅僅是這些還不夠,因?yàn)槲覀冞€要對(duì)每種item設(shè)置數(shù)據(jù),所以還要對(duì)每種item寫一個(gè)VIewHolder來(lái)為item顯示數(shù)據(jù)
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對(duì)應(yīng)的幾個(gè)ViewHolder,判斷viewHolder屬于那種對(duì)象,然后在onBindViewHolder中根據(jù)對(duì)應(yīng)的ViewHolder對(duì)其控件設(shè)置數(shù)據(jù)并顯示
@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); } }
整個(gè)過程基本就是這樣,這種方式在項(xiàng)目中經(jīng)常會(huì)用到,我們就可以這樣去處理,下拉加載更多就可以這樣實(shí)現(xiàn),在加載完數(shù)據(jù)后再往對(duì)象集合中傳入null,然后判斷如果出現(xiàn)null就加載progressBar布局,再加上Google官方的SwipeRefreshLayout,下拉刷新,上拉加載就搞定了,其實(shí)很容易,而且也有點(diǎn)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); } } }
項(xiàng)目地址:https://github.com/xiyouZmt/E-Read
最后說一下為什么為什么用RecyclerView取代ListView。
用過ListView的都知道,在ListView中若要復(fù)用視圖緩存,就要在getView()方法中手動(dòng)判斷convertView是否為空,若不為空則復(fù)用視圖緩存,若為空則重新加載視圖,而RecyclerView相當(dāng)于對(duì)ListView的Adapter進(jìn)行了再次封裝,把ListView手動(dòng)判斷是否有緩存的代碼封裝到RecyclerView內(nèi)部,使這部分邏輯不可見,我們只需要通過getItemCount()方法告訴RecyclerView有多少項(xiàng)數(shù)據(jù),然后在onCreateViewHolder()中加載item布局實(shí)例化ViewHolder,然后在onBindViewHolder()中完成數(shù)據(jù)的綁定即可。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android RecyclerView滑動(dòng)刪除和拖動(dòng)排序
- Android RecyclerView item選中放大被遮擋問題詳解
- Android使用CardView作為RecyclerView的Item并實(shí)現(xiàn)拖拽和左滑刪除
- Android中RecyclerView實(shí)現(xiàn)Item添加和刪除的代碼示例
- Android中RecyclerView的item寬高問題詳解
- Android RecyclerView顯示Item布局不一致解決辦法
- Android RecyclerView的Item點(diǎn)擊事件實(shí)現(xiàn)整理
- Android 中RecyclerView多種item布局的寫法(頭布局+腳布局)
- Android RecyclerView自由拖動(dòng)item的實(shí)現(xiàn)代碼
相關(guān)文章
自定義ListView實(shí)現(xiàn)拖拽ListItem項(xiàng)交換位置(附源碼)
本文要實(shí)現(xiàn)的是拖拽ListView的Item項(xiàng),在布局方面還是用基于布局泵LayoutInflater來(lái)從不同的Layout模板拿到不同的布局然后將view返回,感興趣的朋友可以了解下哈2013-06-06Android端使用Modbus協(xié)議的簡(jiǎn)單方法
Modbus協(xié)議是全球第一個(gè)用于工業(yè)現(xiàn)場(chǎng)的總線協(xié)議,與外設(shè)交互可以采用串口通信,tcp等方式,這篇文章主要給大家介紹了關(guān)于Android端使用Modbus協(xié)議的簡(jiǎn)單方法,需要的朋友可以參考下2021-11-11Android+Flutter實(shí)現(xiàn)彩虹圖案的繪制
彩虹,是氣象中的一種光學(xué)現(xiàn)象,當(dāng)太陽(yáng)光照射到半空中的水滴,光線被折射及反射,在天空上形成拱形的七彩光譜。接下來(lái),我們就自己手動(dòng)繪制一下彩虹圖案吧2022-11-11Android開發(fā)案例手冊(cè)Application跳出dialog
這篇文章主要為大家介紹了Android開發(fā)案例手冊(cè)Application跳出dialog,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Kotlin基本類型自動(dòng)裝箱一點(diǎn)問題剖析
這篇文章主要剖析了Kotlin基本類型自動(dòng)裝箱的一點(diǎn)問題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Android Compose自定義TextField實(shí)現(xiàn)自定義的輸入框
眾所周知Compose中默認(rèn)的TextField和OutlineTextField樣式并不能滿足所有的使用場(chǎng)景,所以自定義TextField就成了必備技能。本文將自定義TextField實(shí)現(xiàn)自定義的輸入框,感興趣的可以了解一下2022-03-03Android App實(shí)現(xiàn)監(jiān)聽軟鍵盤按鍵的三種方式
本篇文章主要介紹Android App實(shí)現(xiàn)監(jiān)聽軟鍵盤按鍵的三種方式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03詳解Android中使用Notification實(shí)現(xiàn)進(jìn)度通知欄(示例三)
這篇文章主要介紹了詳解Android中使用Notification實(shí)現(xiàn)進(jìn)度通知欄(示例三),具有一定的參考價(jià)值,有興趣的可以了解一下。2016-12-12Flutter實(shí)現(xiàn)彈窗攔截器的示例代碼
彈窗的排隊(duì)執(zhí)行在App中是一個(gè)很常見的應(yīng)用場(chǎng)景,這篇文章為大家介紹了兩個(gè)Flutter實(shí)現(xiàn)彈窗攔截器的示例代碼,感興趣的小伙伴可以學(xué)習(xí)一下2023-09-09