Android RecyclerView 簡介與例項

segmentfault發表於2016-03-05

RecyclerView是傳統ListView的一個很好的替代,具有很好的擴充性,初次接觸RecyclerView可能會被其複雜的邏輯搞暈,本文就以一個簡單的例項帶小夥伴們理清其中的關係。

一 新增依賴包

本文所使用的IDE為AndroidStudio。

依次點選File—>Project Structure—>左下角Module的app—>Dependencis—>點選左下方的+號,選擇recycler view即可。

二 準備工作

首先建立一個名為NotesListFragment的fragment,對應的佈局檔名為fragment_notes_list。接著將該fragment加入到主Activity中(關於如何在Activity中操作fragment將另作文章說明,此處省略啦),接下來在NotesListFragment中定義一個私有欄位

private RecyclerView noteRecycler;

我們將要實現的是一個顯示筆記的RecyclerView,這裡將筆記類定義如下:

package com.aristark.note;

import java.util.Date;
import java.util.UUID;
public class Note {

    private UUID uuid;
    private String title;
    private String content;
    private Date date;
    private String tag;

    public Note{
        uuid = UUID.randomUUID();
        date = new Date();
    }

    public UUID getUuid() {
        return uuid;
    }

    public Date getDate() {
        return date;
    }

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

    public String getTitle() {
        return title;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public void setTag(String tag) {
        this.tag = tag;
    }

    public String getTag() {
        return tag;
    }
}

為了操作方便,我們再建立一個NoteLab類:

package com.aristark.note;

import android.content.Context;
import java.util.ArrayList;

public class NoteLab {
    private static NoteLab sNoteLab; //for the global use
    private ArrayList<Note> notes;

    private NoteLab(Context context){
        notes = new ArrayList<Note>();

        //generate 100 Note Objects
        for (int i=0;i<100;i++){
            Note note = new Note();
            note.setTitle("this is title "+i);
            note.setContent("this is content"+i+"balabalabalabalalabalabalabalabalala/nbalabalabalabalalabalabalabala    balala/nbalabalabalabalalabalabalabalabalala/nbalabalabalabalalabalabalab    alabalala/nbalabalabalabalalabalabalabalabalala/n");
            notes.add(note);
        }
    }

    public static NoteLab getNoteLab(Context context){
        if (sNoteLab == null){
            sNoteLab = new NoteLab(context);
        }

        return sNoteLab;
    }

    public ArrayList<Note> getNotes() {
        return notes;
    }
}

注意體會該類所使用的單例模式,sNoteLab以靜態方式存在,既節省了記憶體,又可以讓應用的各個部件方便的訪問。在構造方法NoteLab中,我們生成100個Note物件以作後面的測試。

三 ViewHolder和Adapter

這兩個類是實現列表的關鍵,其實從字面含義很容易猜測這兩個類的作用,ViewHolder操作的是列表每個部分的佈局,而Adapter則是用資料去填充View,雖然解釋的不是很準確,但姑且這麼理解是沒問題的。那麼下面我們就在NotesListFragment裡建立這兩個類:

1 首先建立NoteHolder

private class NoteHolder extends RecyclerView.ViewHolder{

    public NoteHolder(View root) {
        super(root);
    }       
}

這個類很簡單,值得注意的是自動建立的構造方法所傳入的引數名叫itemView,這裡我將其改為root,因為接下來我們通過這個構造方法傳進來的是一個完整的佈局檔案,而不僅僅是一個控制元件。

2 建立Adapter

private class NoteAdapter extends RecyclerView.Adapter<NoteHolder>{
    private List<Note> notes;

    public NoteAdapter(List<Note> notes){
        this.notes = notes;
    }

    public void setNotes(List<Note> notes) {
        this.notes = notes;
    }

    @Override
    public NoteHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public void onBindViewHolder(NoteHolder holder, int position) {

    }

    @Override
    public int getItemCount() {
        return 0;
    }
}

前面說了Adapter是有關於資料的操作了,因此在類的內部定義notes欄位也很容易理解,我們再來看看這裡覆寫的三個方法,onCreateViewHolder返回值是NoteHolder,因此它是用來建立ViewHolder,onBindViewHolder則可以直接操作NoteHolder,position指的是當前View處在整個List的位置(我們的目的是要建立類似於微信訊息列表的一個列表,其每個部件的佈局其實是一樣的,只是填充的資料不一樣而已),以便按照當前的位置填入相應的資料。getItemCount則是返回需要相應佈局的總數。talk is cheap,show me the code。說再多恐怕也難以表達,下面看程式碼,多看幾遍,自然而然就會用了。

private class NoteAdapter extends RecyclerView.Adapter<NoteHolder>{
    private List<Note> notes;

    public NoteAdapter(List<Note> notes){
        this.notes = notes;
    }

    public void setNotes(List<Note> notes) {
        this.notes = notes;
    }

    @Override
    public NoteHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
        View view = layoutInflater.inflate(R.layout.list_item_note,parent,false);
        return new NoteHolder(view);
    }

    @Override
    public void onBindViewHolder(NoteHolder holder, int position) {
        Note note = notes.get(position);
        holder.bindView(note);
    }

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

其中R.layout.list_item_note的佈局檔案如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout     xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/list_item_note_title" />

</LinearLayout>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/list_item_note_content" />

</LinearLayout>

這裡只簡單的使用了Note類中title和content兩個欄位,其實就是這個view就是形成整個列表,只是依次填充類不同的資料而已。

四 RecyclerView的使用

前面已經準備好了ViewHolder和Adapter,接下來要做的就是將這些部件組裝在一起,最後將整個fragment貼出來,大家注意onCreateView裡是 Ruhr操作的!

public class NotesListFragment extends Fragment {
    private RecyclerView noteRecycler;
    private NoteAdapter noteAdapter;

    public NotesListFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
        // Inflate the layout for this fragment
//return inflater.inflate(R.layout.fragment_notes_list, container, false);
        View root = inflater.inflate(R.layout.fragment_notes_list,container,false);

        noteRecycler = (RecyclerView) root.findViewById(R.id.note_recycler_view);
        noteRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
        NoteLab noteLab = NoteLab.getNoteLab(getActivity());
        ArrayList<Note> notes = noteLab.getNotes();
        noteAdapter = new NoteAdapter(notes);
        noteRecycler.setAdapter(noteAdapter);
        return root;
    }

    private class NoteHolder extends RecyclerView.ViewHolder{
        private TextView noteTitle;
        private TextView noteContent;

        public NoteHolder(View root) {
            super(root);
            noteTitle = (TextView) root.findViewById(R.id.list_item_note_title);
            noteContent = (TextView) root.findViewById(R.id.list_item_note_content);
        }

        public void bindView(Note note){
            noteTitle.setText(note.getTitle());
            noteContent.setText(note.getContent());
        }

    }

    private class NoteAdapter extends RecyclerView.Adapter<NoteHolder>{
        private List<Note> notes;

        public NoteAdapter(List<Note> notes){
            this.notes = notes;
        }

        public void setNotes(List<Note> notes) {
            this.notes = notes;
        }

        @Override
        public NoteHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
            View view = layoutInflater.inflate(R.layout.list_item_note,parent,false);
            return new NoteHolder(view);
        }

        @Override
        public void onBindViewHolder(NoteHolder holder, int position) {
            Note note = notes.get(position);
            holder.bindView(note);
        }

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

}

後記

最後給大家貼出最後的效果圖吧!

這是我第一次寫部落格,解釋的不多,程式碼較多,一來是因為我沒有很多表達的經驗,二來我覺得很多時候類名,函式名足以說明它的用途,過多解釋怕會誤導大家。whatever,還是希望得到大家的支援,我會在堅持寫程式碼的同時也堅持把部落格寫下去,是對自己學到的知識的總結,也希望確確實實可以幫到需要幫助的朋友。我的QQ891871898,大家有任何技術交流的問題都可以聯絡我,批評也可以!另外,求工作!

相關文章