RecyclerView使用完全指南(一)

概述

RecyclerView(一)使用完全指南
RecyclerView(二)之萬能分割線
RecyclerView之瀑布流(三)

官方介紹,RecyclerView用于在有限的窗口展現(xiàn)大量的數(shù)據(jù)查吊,其實(shí)早已經(jīng)有了類似的控件誊酌,如ListView纠亚、GridView龟劲,那么相比它們,RecyclerView有什么樣優(yōu)勢(shì)呢粪般?
RecyclerView標(biāo)準(zhǔn)化了ViewHolder有决,而且異常的靈活闸拿,可以輕松實(shí)現(xiàn)ListView實(shí)現(xiàn)不了的樣式和功能,通過布局管理器LayoutManager可控制Item的布局方式书幕,通過設(shè)置Item操作動(dòng)畫自定義Item添加和刪除的動(dòng)畫新荤,通過設(shè)置Item之間的間隔樣式,自定義間隔台汇。

  • 設(shè)置布局管理器以控制Item的布局方式苛骨,橫向、豎向以及瀑布流方式励七。
  • 可設(shè)置Item操作的動(dòng)畫(刪除或者添加等)
  • 可設(shè)置Item的間隔樣式(可繪制)
  • 但是關(guān)于Item的點(diǎn)擊和長(zhǎng)按事件智袭,需要用戶自己去實(shí)現(xiàn)。

在使用RecyclerView時(shí)候掠抬,必須指定一個(gè)適配器Adapter和一個(gè)布局管理器LayoutManager吼野。適配器繼承RecyclerView.Adapter類,具體實(shí)現(xiàn)類似ListView的適配器两波,取決于數(shù)據(jù)信息以及展示的UI瞳步。布局管理器用于確定RecyclerView中Item的展示方式以及決定何時(shí)復(fù)用已經(jīng)不可見的Item闷哆,避免重復(fù)創(chuàng)建以及執(zhí)行高成本的findViewById()方法。

來看一下用法单起。


mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// 設(shè)置布局管理器
mRecyclerView.setLayoutManager(mLayoutManager);
// 設(shè)置adapter
mRecyclerView.setAdapter(mAdapter);
// 設(shè)置Item添加和移除的動(dòng)畫
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
// 設(shè)置Item之間間隔樣式(分割線)

mRecyclerView.addItemDecoration(new DividerItemDecoration(
                getActivity(), DividerItemDecoration.HORIZONTAL_LIST));

可以看見RecyclerView相比ListView會(huì)多出許多操作抱怔,這也是RecyclerView靈活的地方,它將許多動(dòng)能暴露出來嘀倒,用戶可以選擇性的自定義屬性以滿足需求屈留。

RecyclerView提供了三種布局管理器:

  • LinerLayoutManager 以垂直或者水平列表方式展示Item
  • GridLayoutManager 以網(wǎng)格方式展示Item
  • StaggeredGridLayoutManager 以瀑布流方式展示Item

基本使用

Activity代碼

  public class HomeActivity extends ActionBarActivity
{

    private RecyclerView mRecyclerView;
    private List<String> mDatas;
    private HomeAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_single_recyclerview);

        initData();
        mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(mAdapter = new HomeAdapter());

    }

    protected void initData()
    {
        mDatas = new ArrayList<String>();
        for (int i = 'A'; i < 'z'; i++)
        {
            mDatas.add("" + (char) i);
        }
    }

    class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
    {

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
        {
            MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
                    HomeActivity.this).inflate(R.layout.item_home, parent,
                    false));
            return holder;
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, int position)
        {
            holder.tv.setText(mDatas.get(position));
        }

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

        class MyViewHolder extends ViewHolder
        {

            TextView tv;

            public MyViewHolder(View view)
            {
                super(view);
                tv = (TextView) view.findViewById(R.id.id_num);
            }
        }
    }

}

Activity布局文件activity_rv.xml

<?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">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

Item的布局文件item_home.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="@dimen/md_common_view_height">
    <TextView
        android:id="@+id/item_tv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        tools:text="item"/>
</LinearLayout>
  • 運(yùn)行結(jié)果如下:

RecyclerView-無間隔.jpg

可以看見展示效果和ListView基本上無差別,但是Item之間并沒有分割線测蘑,在xml去找divider屬性的時(shí)候灌危,發(fā)現(xiàn)RecyclerView沒有divider屬性,當(dāng)然也可以在Item布局中加上分割線碳胳,但是這樣做并不是很優(yōu)雅勇蝙。前文說過,RecyclerView可是支持自定義間隔樣式的挨约。通過mRecyclerView.addItemDecoration()來設(shè)置我們定義好的間隔樣式味混。

默認(rèn)分割線

水平分割線

mRecyclerView.addItemDecoration(new DividerItemDecoration(
                getActivity(), LinerLayoutManager.HORIZONTAL));

垂直分割線

        mRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL, false));

mRecyclerView.addItemDecoration(new DividerItemDecoration(
                getActivity(), LinerLayoutManager.HORIZONTAL));

這里的HORIZONTAL 是設(shè)置垂直分割線 而DividerItemDecoration.VERTICAL是設(shè)置水平分割線

注:如果布局管理器中的LinearLayoutManager.HORIZONTAL和分割線樣式LinearLayoutManager.VERTICAL則不會(huì)顯示

動(dòng)畫

前面說過,RecyclerView可以設(shè)置列表中Item刪除和添加的動(dòng)畫诫惭,在v7包中給我們提供了一種默認(rèn)的Item刪除和添加的動(dòng)畫翁锡,如果沒有特殊的需求,默認(rèn)使用這個(gè)動(dòng)畫即可夕土。

// 設(shè)置Item添加和移除的動(dòng)畫
mRecyclerView.setItemAnimator(new DefaultItemAnimator());

下面就添加一下刪除和添加Item的動(dòng)作盗誊。在Adapter里面添加方法。

public void addNewItem() {
    if(mData == null) {
        mData = new ArrayList<>();
    }
    mData.add(0, "new Item");
    notifyItemInserted(0);
}

public void deleteItem() {
    if(mData == null || mData.isEmpty()) {
        return;
    }
    mData.remove(0);
    notifyItemRemoved(0);
}

添加事件的處理隘弊。

public void onClick(View v) {
    int id = v.getId();
    if(id == R.id.rv_add_item_btn) {
        mAdapter.addNewItem();
        // 由于Adapter內(nèi)部是直接在首個(gè)Item位置做增加操作,增加完畢后列表移動(dòng)到首個(gè)Item位置
        mLayoutManager.scrollToPosition(0);
    } else if(id == R.id.rv_del_item_btn){
        mAdapter.deleteItem();
        // 由于Adapter內(nèi)部是直接在首個(gè)Item位置做刪除操作荒适,刪除完畢后列表移動(dòng)到首個(gè)Item位置
        mLayoutManager.scrollToPosition(0);
    }
}

準(zhǔn)備工作完畢后梨熙,來看一下運(yùn)行的效果。

RecyclerView-動(dòng)畫.gif

點(diǎn)擊事件

RecyclerView并沒有像ListView一樣暴露出Item點(diǎn)擊事件或者長(zhǎng)按事件處理的api刀诬,也就是說使用RecyclerView時(shí)候咽扇,需要我們自己來實(shí)現(xiàn)Item的點(diǎn)擊和長(zhǎng)按等事件的處理。實(shí)現(xiàn)方法有很多陕壹,可以監(jiān)聽RecyclerView的Touch事件然后判斷手勢(shì)做相應(yīng)的處理质欲,也可以通過在綁定ViewHolder的時(shí)候設(shè)置監(jiān)聽,然后通過Apater回調(diào)出去糠馆,我們選擇第二種方法嘶伟,更加直觀和簡(jiǎn)單。

先看一下效果

GIF.gif

原理

為RecyclerView的每個(gè)子item設(shè)置setOnClickListener又碌,然后在onClick中再調(diào)用一次對(duì)外封裝的接口九昧,將這個(gè)事件傳遞給外面的調(diào)用者绊袋。而“為RecyclerView的每個(gè)子item設(shè)置setOnClickListener”在Adapter中設(shè)置。其實(shí)直接在onClick中也能完全處理item的點(diǎn)擊事件铸鹰,但是這樣會(huì)破壞代碼的邏輯癌别。

步驟

1、在MyAdapter中定義接口
public interface OnItemClickListener{
     void onItemClick(int position);
}
2蹋笼、聲明這個(gè)接口變量
private OnItemClickListener mItemClickListener;
3展姐、在onCreateViewHolder()中為每個(gè)item添加點(diǎn)擊事件
@Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = View.inflate(mContext, R.layout.item_linear, null);
        RecyclerView.ViewHolder holder = new LinearViewholder(view);
      //這兩句也可以這樣寫,效果都是一樣的
      //View view =LayoutInflater.from(parent.getContext()).inflate(R.layout.item_home, parent, false);
    //RecyclerView.ViewHolder holder =new ViewHolder
        view.setOnClickListener(this);
        return holder;
    }
@Override
   public void onClick(View v) {
     if (mItemClickListener!=null){
         mItemClickListener.onItemClick((Integer) v.getTag());
        }
    }
4、注意上面調(diào)用接口的onItemClick()中的v.getTag()方法剖毯,這需要在onBindViewHolder()方法中設(shè)置和item相關(guān)的數(shù)據(jù)
 @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        LinearViewholder viewholder = (LinearViewholder) holder;
        viewholder.mTextView.setText(mList.get(position));
        viewholder.itemView.setTag(position);
    }
5圾笨、提供set方法
public void setItemClickListener(OnItemClickListener itemClickListener) {
        mItemClickListener = itemClickListener;
    }
6、在MainActivity中
MyRecyclerViewAdapter adapter = new MyRecyalerViewAdapter();
    adapter.setItemClickListener(this);
 @Override
    public void onItemClick(int position) {
        Toast.makeText(this, ""+position, Toast.LENGTH_SHORT).show();
    }

上面這是一種算是比較負(fù)責(zé)的一種了吧速兔,下面介紹一種簡(jiǎn)單的墅拭,當(dāng)然上面的也要自己弄明白的

class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{

//...
    public interface OnItemClickLitener
    {
        void onItemClick(View view, int position);
        void onItemLongClick(View view , int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
    {
        this.mOnItemClickLitener = mOnItemClickLitener;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position)
    {
        holder.tv.setText(mDatas.get(position));

        // 如果設(shè)置了回調(diào),則設(shè)置點(diǎn)擊事件
        if (mOnItemClickLitener != null)
        {
            holder.itemView.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemClick(holder.itemView, pos);
                }
            });

            holder.itemView.setOnLongClickListener(new OnLongClickListener()
            {
                @Override
                public boolean onLongClick(View v)
                {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
                    return false;
                }
            });
        }
    }
//...
}

根據(jù)王三的貓阿德加以改編

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涣狗,一起剝皮案震驚了整個(gè)濱河市谍婉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌镀钓,老刑警劉巖穗熬,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異丁溅,居然都是意外死亡唤蔗,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門窟赏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妓柜,“玉大人,你說我怎么就攤上這事涯穷」髌” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵拷况,是天一觀的道長(zhǎng)作煌。 經(jīng)常有香客問我,道長(zhǎng)赚瘦,這世上最難降的妖魔是什么粟誓? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮起意,結(jié)果婚禮上鹰服,老公的妹妹穿的比我還像新娘。我一直安慰自己杜恰,他們只是感情好获诈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布仍源。 她就那樣靜靜地躺著,像睡著了一般舔涎。 火紅的嫁衣襯著肌膚如雪笼踩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天亡嫌,我揣著相機(jī)與錄音嚎于,去河邊找鬼。 笑死挟冠,一個(gè)胖子當(dāng)著我的面吹牛于购,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播知染,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼肋僧,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了控淡?” 一聲冷哼從身側(cè)響起嫌吠,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎掺炭,沒想到半個(gè)月后辫诅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涧狮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年炕矮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片者冤。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肤视,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涉枫,到底是詐尸還是另有隱情钢颂,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布拜银,位于F島的核電站,受9級(jí)特大地震影響遭垛,放射性物質(zhì)發(fā)生泄漏尼桶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一锯仪、第九天 我趴在偏房一處隱蔽的房頂上張望泵督。 院中可真熱鬧,春花似錦庶喜、人聲如沸小腊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)秩冈。三九已至本缠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間入问,已是汗流浹背丹锹。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留芬失,地道東北人楣黍。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像棱烂,于是被迫代替她去往敵國(guó)和親租漂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容