Android Material Design學習之RecyclerView代替 ListView

weixiong 8年前發布 | 35K 次閱讀 Android開發 移動開發

 

前言

Android Material Design越來越流行,以前很常用的 ListView 現在也用RecyclerView代替了,實現原理還是相似的。筆者實現一下 RecyclerView,代碼比較簡單,適合初學者,如有錯誤,歡迎指出。

本文鏈接 http://blog.csdn.net/never_cxb/article/details/50495505,轉載請注明出處。

復習 ListView

可以查看這篇博客 Android ListView 基礎入門 簡介以及深入優化 ,了解關于 ListView 的基礎知識。

實現過程中需要復寫BaseAdapter,主要是這4個方法

  • public int getCount() :適配器中數據集中 數據的個數,即ListView需要顯示的數據個數
  • public Object getItem(int position) : 獲取數據集中與指定索引對應的數據項
  • public long getItemId(int position) : 獲取指定行對應的ID
  • public View getView(int
    position, View convertView, ViewGroup parent) :獲取每一個Item的顯示內容

一般 ListView 每一項都是相同的布局,若想各個項實現不同的布局,可復寫 getItemViewType和getViewTypeCount實現

RecyclerView 實現

xml 布局

下面是RecyclerView中每一項的布局 layout下面的item_article_type_1.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="

<LinearLayout  android:layout_width="match_parent" android:layout_height="wrap_content">

    <com.非死book.drawee.view.SimpleDraweeView  android:id="@+id/rcv_article_photo" android:layout_width="100dp" android:layout_height="100dp" android:layout_centerVertical="true" fresco:actualImageScaleType="centerInside" fresco:roundAsCircle="true" fresco:roundingBorderColor="@color/lightslategray" fresco:roundingBorderWidth="1dp" />

    <LinearLayout  android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical">

        <TextView  android:id="@+id/rcv_article_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="2dp" android:gravity="center" android:text="關于舉辦《經典音樂作品欣賞與人文審美》講座的通知" android:textColor="@color/primary_text" />
        <!-- 新聞 發布時間 來源 閱讀次數-->
        <LinearLayout  android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:gravity="center" android:orientation="horizontal">

            <TextView  android:id="@+id/rcv_article_date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="2dp" android:text="2015-01-09" />

            <TextView  android:id="@+id/rcv_article_source" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="2dp" android:layout_marginRight="2dp" android:text="科學研究院" />

            <TextView  android:id="@+id/rcv_article_readtimes" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="2dp" android:layout_marginRight="2dp" android:text="1129次" />

        </LinearLayout>


        <TextView  android:id="@+id/rcv_article_preview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="5dp" android:ellipsize="end" android:maxLines="2" android:text="講座主要內容:以中、西方音樂歷史中經典音樂作品為基礎,通過作曲家及作品創作背景、相關音樂文化史知識及音樂欣賞常識..." />

    </LinearLayout>
</LinearLayout>

</android.support.v7.widget.CardView> </pre>

布局思路就是 CardView里面嵌入了一個LinearLayout。圖片部分用固定寬度100dp,文字部分利用android:layout_weight=”1”占據了其他部分。

TextView利用android:gravity=”center”使得標題的文字居中。

LinearLayout里面利用android:gravity=”center”使得“2015-01-09 科學研究院 1129次”居中,

新聞詳情內容的TextView利用

android:maxLines="2"
android:ellipsize="end"

將文章內容限定為2行,超出部分用省略號顯示。

使用fresco這兒有個坑需要注意,請移步這篇文章

Android 之 Fresco 顯示圓形圖片 之坑

預覽效果
這里寫圖片描述

新聞列表的 xml 文件,layout 文件夾下面的fragment_article.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="

<android.support.v7.widget.RecyclerView  android:id="@+id/rcv_article" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" />

</LinearLayout></pre>

Adapter 實現

主要步驟是:

  • 根據上面的 item_article_type_1.xml實現一個 class ImageItemArticleViewHolder extends RecyclerView.ViewHolder
  • 繼承RecyclerView.Adapter ,class ItemArticleListAdapter extends RecyclerView.Adapter <...>
    重寫三個方法
    • public int getItemCount()
    • public TestAdapter.ImageItemArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    • public void onBindViewHolder(ImageItemArticleViewHolder holder, int position)

/*  Created by tomchen on 1/11/16. */
public class ItemArticleAdapter extends RecyclerView.Adapter<ItemArticleAdapter.ImageItemArticleViewHolder> {

//新聞列表
private List<ItemArticle> articleList;

//context
private Context context;

private LayoutInflater mLayoutInflater;


public ItemArticleAdapter(Context context,List<ItemArticle> articleList) {
    this.context = context;
    this.articleList = articleList;
    mLayoutInflater = LayoutInflater.from(context);
}

@Override
public ItemArticleAdapter.ImageItemArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = mLayoutInflater.inflate(
            R.layout.item_article_type_1, parent, false);
    return new ImageItemArticleViewHolder(view);
}

@Override
public void onBindViewHolder(ImageItemArticleViewHolder holder, int position) {
    ItemArticle article = articleList.get(position);
    holder.rcvArticlePhoto.setImageURI(Uri.parse(article.getImageUrl()));
    holder.rcvArticleTitle.setText(article.getTitle());
    holder.rcvArticleDate.setText(article.getPublishDate());
    holder.rcvArticleSource.setText(article.getSource());
    //注意這個閱讀次數是 int 類型,需要轉化為 String 類型
    holder.rcvArticleReadtimes.setText(article.getReadTimes()+"次");
    holder.rcvArticlePreview.setText(article.getPreview());
}


@Override
public int getItemCount() {
    return articleList.size();
}

class ImageItemArticleViewHolder extends RecyclerView.ViewHolder {

    @InjectView(R.id.rcv_article_photo)
    SimpleDraweeView rcvArticlePhoto;
    @InjectView(R.id.rcv_article_title)
    TextView rcvArticleTitle;
    @InjectView(R.id.rcv_article_date)
    TextView rcvArticleDate;
    @InjectView(R.id.rcv_article_source)
    TextView rcvArticleSource;
    @InjectView(R.id.rcv_article_readtimes)
    TextView rcvArticleReadtimes;
    @InjectView(R.id.rcv_article_preview)
    TextView rcvArticlePreview;

    public ImageItemArticleViewHolder(View itemView) {
        super(itemView);
        ButterKnife.inject(this, itemView);
    }
}

}</pre>

新聞實體類 javabean

有新聞的 index,圖片 url,標題,發布時間,來源,閱讀次數,新聞內容預覽

/*  Created by tomchen on 1/10/16.  新聞類,這是在 RecycleView 使用的新聞 javabean  還有一個新聞詳情javabean */
public class ItemArticle {
    private int index;
    private String imageUrl;
    private String title;
    private String publishDate;
    private String source;
    private int readTimes;
    private String preview;

public ItemArticle(int index, String imageUrl, String title, String publishDate, String source, int readTimes, String preview) {
    this.index = index;
    this.imageUrl = imageUrl;
    this.title = title;
    this.publishDate = publishDate;
    this.source = source;
    this.readTimes = readTimes;
    this.preview = preview;
}

public int getIndex() {
    return index;
}

public void setIndex(int index) {
    this.index = index;
}

public String getImageUrl() {
    return imageUrl;
}

public void setImageUrl(String imageUrl) {
    this.imageUrl = imageUrl;
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public String getPublishDate() {
    return publishDate;
}

public void setPublishDate(String publishDate) {
    this.publishDate = publishDate;
}

public String getSource() {
    return source;
}

public void setSource(String source) {
    this.source = source;
}

public int getReadTimes() {
    return readTimes;
}

public void setReadTimes(int readTimes) {
    this.readTimes = readTimes;
}

public String getPreview() {
    return preview;
}

public void setPreview(String preview) {
    this.preview = preview;
}

}</pre>

fragment 里面使用 RecyclerView

思路就是開啟一個異步線程,讀取多條新聞,加入List itemArticleList,由這個itemArticleList構造ItemArticleAdapter,最后利用setAdapter()方法給RecyclerView加上適配器。

/*  Created by tomchen on 2015/8/28. */
public class ArticleFragment extends Fragment {
    private static final String STORE_PARAM = "param";
    @InjectView(R.id.rcv_article)
    RecyclerView rcvArticle;

private String mParam;
//新聞列表數據
private List<ItemArticle> itemArticleList = new ArrayList<ItemArticle>();

//獲取 fragment 依賴的 Activity,方便使用 Context
private Activity mAct;


public static Fragment newInstance(String param) {
    ArticleFragment fragment = new ArticleFragment();
    Bundle args = new Bundle();
    args.putString(STORE_PARAM, param);
    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam = getArguments().getString(STORE_PARAM);
    }
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_article, null);
    Log.i(STORE_PARAM, "in StoreFragment");
    mAct = getActivity();
    ButterKnife.inject(this, view);
    return view;
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    rcvArticle.setLayoutManager(new LinearLayoutManager(mAct));//這里用線性顯示 類似于listview

// rcvArticle.setLayoutManager(new GridLayoutManager(mAct, 2));//這里用線性宮格顯示 類似于grid view // rcvArticle.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));//這里用線性宮格顯示 類似于瀑布流

    new LatestArticleTask().execute();

}

@Override
public void onDestroyView() {
    super.onDestroyView();
    ButterKnife.reset(this);
}

class LatestArticleTask extends AsyncTask<String, Void, List<ItemArticle>> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected List<ItemArticle> doInBackground(String... params) {
        ItemArticle storeInfo1 =
                new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "關于舉辦《經典音樂作品欣賞與人文審美》講座的通知", "2015-01-09", "科學研究院", 1129,
                        "講座主要內容:以中、西方音樂歷史中經典音樂作品為基礎,通過作曲家及作品創作背景、相關音樂文化史知識及音樂欣賞常識...");
        ItemArticle storeInfo2 =
                new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "關于舉辦《經典音樂作品欣賞與人文審美》講座的通知", "2015-01-09", "科學研究院", 1129,
                        "講座主要內容:以中、西方音樂歷史中經典音樂作品為基礎,通過作曲家及作品創作背景、相關音樂文化史知識及音樂欣賞常識...");
        ItemArticle storeInfo3 =
                new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "關于舉辦《經典音樂作品欣賞與人文審美》講座的通知", "2015-01-09", "科學研究院", 1129,
                        "講座主要內容:以中、西方音樂歷史中經典音樂作品為基礎,通過作曲家及作品創作背景、相關音樂文化史知識及音樂欣賞常識...");
        ItemArticle storeInfo4 =
                new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "關于舉辦《經典音樂作品欣賞與人文審美》講座的通知", "2015-01-09", "科學研究院", 1129,
                        "講座主要內容:以中、西方音樂歷史中經典音樂作品為基礎,通過作曲家及作品創作背景、相關音樂文化史知識及音樂欣賞常識...");
        ItemArticle storeInfo5 =
                new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "關于舉辦《經典音樂作品欣賞與人文審美》講座的通知", "2015-01-09", "科學研究院", 1129,
                        "講座主要內容:以中、西方音樂歷史中經典音樂作品為基礎,通過作曲家及作品創作背景、相關音樂文化史知識及音樂欣賞常識...");
        ItemArticle storeInfo6 =
                new ItemArticle(20123, "http://i2.sinaimg.cn/ent/j/2012-05-20/U5912P28T3D3634984F328DT20120520152700.JPG", "關于舉辦《經典音樂作品欣賞與人文審美》講座的通知", "2015-01-09", "科學研究院", 1129,
                        "講座主要內容:以中、西方音樂歷史中經典音樂作品為基礎,通過作曲家及作品創作背景、相關音樂文化史知識及音樂欣賞常識...");
        itemArticleList.add(storeInfo1);
        itemArticleList.add(storeInfo2);
        itemArticleList.add(storeInfo3);
        itemArticleList.add(storeInfo4);
        itemArticleList.add(storeInfo5);
        itemArticleList.add(storeInfo6);
        return itemArticleList;
    }

    @Override
    protected void onPostExecute(List<ItemArticle> data) {
        super.onPostExecute(data);
        ItemArticleAdapter adapter = new ItemArticleAdapter(mAct, data);
        rcvArticle.setAdapter(adapter);
    }
}

}</pre>

效果圖

利用修改布局,線性顯示或者宮格顯示。(以前宮格顯示很麻煩,現在一條命令就好了,google 搞得這么簡單,我們 Android 工程師要失業的好伐?!!)

rcvArticle.setLayoutManager(new LinearLayoutManager(mAct));//這里用線性顯示 類似于listview
// rcvArticle.setLayoutManager(new GridLayoutManager(mAct, 2));//這里用線性宮格顯示 類似于grid view
// rcvArticle.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));//這里用線性宮格顯示 類似于瀑布流

統計結果1

統計結果1

知識點

TextView需要有setText(int resid) 方法,但是這兒 int 表示 resourceId,如果我想把閱讀次數(int 1123)賦給這個 TextView,不能使用這個方法。
需要把 int 轉化為 String

int 轉 String 有三種方法
int i =8;
String s =Integer.toString(i);
String g =String.valueOf(i);
String h =i+"";
holder.rcvArticleReadtimes.setText(String.valueOf(article.getReadTimes()));    

總結 Todo List

  • Picasso 圖片緩存庫的學習
  • 實現 RecyclerView 每個項各自的布局

遇到的坑

rcvArticle.setLayoutManager()需要在onActivityCreated()方法里調用,如果在onCreateView()調用會拋出空指針異常。

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_one_latest, container, false);
    mAct = getActivity();
    //錯誤,需要在onActivityCreated里面調用
    rcvArticle.setLayoutManager(new LinearLayoutManager(mAct));//這里用線性顯示 類似于listview
    ButterKnife.inject(this, view);
    return view;
}</pre> 

java.lang.NullPointerException
at com.example.administrator.seenews.ui.fragment.common.ArticleFragment.onCreateView(ArticleFragment.java:111)

參考文章

Android RecyclerView Example | Java Techig

</div>

 本文由用戶 weixiong 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!