Android RecyclerView的使用解析(完结篇)

前言

在前面两篇文章(Android RecyclerView的使用解析(一)Android RecyclerView的使用解析(二))中,我们主要对RecyclerView作了简单的介绍并实现了它不同的布局效果,在本文中,我将对RecyclerView的动画机制和点击事件进行讲解。

ItemAnimator

说到RecyclerView的动画机制,那我们就不得不提ItemAnimator这个类了,我们就
是依靠它来实现item的动画效果的。这个类仍然是个抽象类,不过Google给我们提供了一些实现类,我们也可以自定义它的实现类以显示更加炫酷的效果。网上有很多讲解该类的文章,这里我就不多作分析了。

给item设置添加、删除动画

首先我们需要在菜单栏添加两个实现增加和删除item的按钮,打开menu文件夹下的布局文件,添加两个item项:

 <item android:id="@+id/action_add"
          android:title="ADD"
          android:orderInCategory="100"
          app:showAsAction="ifRoom" />
    <item android:id="@+id/action_remove"
          android:title="REMOVE"
          android:orderInCategory="100"
          app:showAsAction="ifRoom" />

接着在TestAdapter中添加两个增加和删除item的方法:

 public void addData(int pos) {
        mDataset.add (pos, "Insert one");
        notifyItemInserted (pos);
    }

    public void removeData(int pos) {
        mDataset.remove (pos);
        notifyItemRemoved (pos);
    }

然后在MainActivity的Oncreate方法中给RecyclerView设置一个默认的动画效果:

mRecyclerView.setItemAnimator (new DefaultItemAnimator ());

最后在onOptionsItemSelected方法中增加两个按钮的id:

case R.id.action_add:
                mAdapter.addData (1);
                break;
            case R.id.action_remove:
                mAdapter.removeData (1);
                break;

由于我们给瀑布流的布局设置了不同的activity,所以还需将以上代码添加到StaggeredGridActivity和StagggeredAdapter。

运行效果如下:


ItemAnimator

额。。。虽然我们实现了添加和删除动画,但是每次都通过点击菜单选项来操作好像很繁琐耶,我们来优化一下呗。

我们可以给我们的demo增加一个ActionBar或ToolBar并把ADD和REMOVE按钮放在其上,为了方便,我这里使用的是ActionBar。修改代码,让MainActivty和StaggeredGridActivity继承自ActionBarActivity,接着修改values/styles.xml,将Theme指定为Theme.AppCompat.Light.DarkActionBar,代码如下:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <!--<item name="android:listDivider">@drawable/my_divider</item>-->
    </style>

</resources>

重新运行程序,试试效果吧:


ChagedItemAnimator

嘿嘿,是不是方便多啦!

添加OnClick监听

熟悉ListView的人应该知道,ListView给我们提供了onItemClickListener之类的监听器,当我们点击item的时候,它会回调相关的方法,以便我们可以方便的处理item的点击事件。然而RecyclerView它丫的竟然没有对item提供任何相关的回调方法,太不负责任了!还能肿么办,只能我们自己去添加咯,谁叫人家是当大爷的命呢。

简单起见,我们可以在Adapter中为其添加,修改TestAdapter,代码如下:

package com.wuminmiao.recycleviewtest;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;

/**
 * Created by wmm on 2016/10/13.
 */

public class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyViewHolder> {

    private Context mContext;
    protected List<String> mDataset;
    private LayoutInflater mInflater;

//    提供接口
    public interface OnItemClickListener {
        void onItemClick(View view, int position);
        void onItemLongClick(View view, int position);
    }

//    声明类型
    private OnItemClickListener mOnItemClickListener;

//    提供它的set方法,供activity设置回调
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.mOnItemClickListener = listener;
    }

    //提供一个合适的构造方法
    public TestAdapter(Context context, List<String> dataset) {
        this.mContext = context;
        this.mDataset = dataset;
        mInflater = LayoutInflater.from (context);
    }

    /**
     *将布局转换为View并传递给自定义的MyViewHolder
     * @param viewGroup
     * @param viewType
     * @return
     */
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        View view = mInflater.inflate (R.layout.item, viewGroup, false);
        MyViewHolder viewHolder = new MyViewHolder (view);
        return viewHolder;
    }

    /**
     * 建立起MyViewHolder中视图与数据的关联
     * @param viewHolder
     * @param position
     */
    @Override
    public void onBindViewHolder(final MyViewHolder viewHolder, final int position) {
        viewHolder.mTextView.setText (mDataset.get (position));
        setUpItemEvent (viewHolder);
    }
    
//    设置item的回调
    protected void setUpItemEvent(final MyViewHolder viewHolder) {
        if (mOnItemClickListener != null) {
            viewHolder.itemView.setOnClickListener (new View.OnClickListener () {
                @Override
                public void onClick(View v) {
                    int layoutPosition = viewHolder.getLayoutPosition ();

                    mOnItemClickListener.onItemClick (viewHolder.itemView, layoutPosition);
                }
            });
            viewHolder.itemView.setOnLongClickListener (new View.OnLongClickListener () {
                @Override
                public boolean onLongClick(View v) {
                    int layoutPosition = viewHolder.getLayoutPosition ();
                    mOnItemClickListener.onItemLongClick (viewHolder.itemView, layoutPosition);
                    return false;
                }
            });
        }
    }

    /**
     * 获取item的数目
     * @return
     */
    @Override
    public int getItemCount() {
     return mDataset.size ();
    }

    public void addData(int position) {
        mDataset.add (position, "Insert one");
        notifyItemInserted (position);
    }

    public void removeData(int position) {
        mDataset.remove (position);
        notifyItemRemoved (position);
    }

    //自定义的ViewHoder,持有item的所有控件
    public static class MyViewHolder extends RecyclerView.ViewHolder {
         TextView mTextView;
        public MyViewHolder(View view) {
            super (view);
            mTextView = (TextView) view.findViewById(R.id.text);
        }
    }

}

可以看到,我们给适配器提供了一个OnItemClickListener的接口,里面封装了两个回调方法分别是onItemClick(点击)和onItemLongClick(长按)。接着提供setOnItemClickListener方法让activity可以去监听它的回调方法。最后在onBindViewHolder中设置这两个回调方法。

这样就可以在activity中去监听这两个回调方法啦,我们在onCreate方法中添加如下代码:

  mAdapter.setOnItemClickListener (new TestAdapter.OnItemClickListener () {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText (MainActivity.this, "你点击了第" + position + "个item" ,
                        Toast.LENGTH_SHORT).show ();
            }

            @Override
            public void onItemLongClick(View view, int position) {
                mAdapter.removeData (position);
            }
        });

代码很简单,当我们点击一个item时,会弹出一个Toast,而当我们长按一个item则会删除该item。

别忘了,我们的瀑布流布局与其他布局是不同的activity和adapter,我们还需要修改它们的代码。
StaggeredGridActivity中和MainActivity需要添加的代码是一样的,而StagggeredAdapter也可以继承我们的TestAdapter,保留其特有的属性和方法就行了,StagggeredAdapter修改后的代码如下:

package com.wuminmiao.recycleviewtest;

import android.content.Context;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by wmm on 2016/10/13.
 */

public class StagggeredAdapter extends TestAdapter{


    private List<Integer> mHeight;

    //提供一个合适的构造方法
    public StagggeredAdapter(Context context, List<String> dataset) {
        super(context, dataset);

        mHeight = new ArrayList<Integer> ();
        for (int i = 0; i < mDataset.size (); i++) {
            mHeight.add ((int) (100 + Math.random ()*300));
        }
    }
    /**
     * 建立起MyViewHolder中视图与数据的关联
     * @param viewHolder
     * @param position
     */
    @Override
    public void onBindViewHolder (MyViewHolder viewHolder, int position) {
        viewHolder.mTextView.setText(mDataset.get (position));
        ViewGroup.LayoutParams lp  = viewHolder.itemView.getLayoutParams ();
        lp.height = mHeight.get (position);
        viewHolder.itemView.setLayoutParams (lp);

        setUpItemEvent (viewHolder);
    }


}

还有一点要注意的是,如果现在运行程序的话,当我们点击item时它的颜色是不会变化的,这样的用户体验肯定很差,我们需要给它优化一下。

首先,在drawable中新建一个xml文件,就叫做bg_item吧:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item  android:drawable="@color/state_item_pressed" android:state_pressed="true"></item>
    <item  android:drawable="@color/state_item_normal"></item>
</selector>

接着在values/colors.xml中指定其颜色:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="state_item_pressed">#728cd4</color>
    <color name="state_item_normal">#add8e6</color>
</resources>

我们给默认的item和点击后的item设置了不同的颜色,这样体验效果应该会好一点。

现在,就可以运行我们的程序啦,效果如下:


OnClickEvent

总结

在本文中,我们首先给RecyclerView实现了item添加和删除的动画效果,除了系统默认的效果,我们也可以自定义一些更加炫酷的动画效果。当然,得益于伟大的开源世界,我们可以直接在前人种的树下乘凉,比如这里,或者这里

接着我们又给RecylerView的item添加了OnClick监听,我们可以根据需求处理各式各样的点击事件。

那么到这里,我们的Android RecyclerView的使用解析系列就完结啦。虽然这个系列讲解得非常基础,但由于个人水平有限,仍然可能会出现一些错误,欢迎大家指正。

该系列文章首发在我的个人博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,082评论 25 707
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,755评论 22 665
  • 听了海连和鲜丽两位的分享,我内心触动很大,心里边也非常痛,特别是海连的分享,她的经历怎么跟我这么相似,不过她比我强...
    辛勒换成果阅读 189评论 0 0
  • 1、实现原理加盐的实现过程通常是在需要散列的字段的特定位置增加特定的字符,打乱原始的字串,使其生成的散列结果产生变...
    半亩房顶阅读 1,175评论 0 0
  • COOKIE 与 SESSION 概念 cookie不属于http协议范围,由于http协议无法保持状态,但实际情...
    lkning阅读 286评论 0 0