美文网首页Android 入门进阶Android 技术开发Android开发
Android RecyclerView的使用解析(完结篇)

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

作者: mkdir_mushroom | 来源:发表于2016-10-29 18:45 被阅读1832次

    前言

    在前面两篇文章(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的使用解析系列就完结啦。虽然这个系列讲解得非常基础,但由于个人水平有限,仍然可能会出现一些错误,欢迎大家指正。

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

    相关文章

      网友评论

        本文标题: Android RecyclerView的使用解析(完结篇)

        本文链接:https://www.haomeiwen.com/subject/jpeyuttx.html