zoukankan      html  css  js  c++  java
  • RecyclerView的使用

      原文来自:http://www.cnblogs.com/liuling/p/2015-11-04-01.html

    什么是RecyclerView
            RecyclerView是Android 5.0 materials design中的组件之一,相应的还有CardView、Palette等。看名字我们就能看出一点端倪,没错,它主要的特点就是复用。我们知道,Listview中的Adapter中可以实现ViewHolder的复用。RecyclerView提供了一个耦合度更低的方式来复用ViewHolder,RecyclerView只管回收与复用View,其他的你可以自己去设置,其高度解耦可以轻松的实现ListView、GridView以及瀑布流的效果
     
    RecyclerView的用法        首先我们要gradle的依赖库中添加  
    compile 'com.android.support:recyclerview-v7:23.3.0'
    。如果是eclipse直接导入android-support-v7-recyclerview.jar就可以了。

    找到v7下的包,编译的时候出错,可以更改为

     

    • 控制其显示的方式,通过布局管理器LayoutManager
    • 控制Item间的间隔(可绘制),通过ItemDecoration
    • 控制Item增删的动画,通过ItemAnimator
    • 控制点击、长按事件,自己写
     
    实例:
    运用recyclerView实现listview的效果,并实现自定义监听,进行item的点击,长按事件
    layout_recyclerview_item.xml:
    注意:设置listview垂直滚动时,父布局的高度不能为mathch_parent ,不然会出现一个页面显示一条数据的现象,横向滚动同理.
    <?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="wrap_content">
        <TextView
            android:id="@+id/tv_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
     
    适配器的代码如下:
    /**
     * Created by Administrator on 2016/9/27.
     */
    public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ItemViewHolder> {
        private Context context;
        private List<String>dataList;
        private MyOnItemClickListener myOnItemClickListener;
    
        /**
         * 重写构造方法
         * @param context 当前activity对象
         * @param dataList 数据源
         */
        public MyRecyclerViewAdapter(Context context, List<String> dataList) {
            this.context = context;
            this.dataList = dataList;
    
        }
    
    
    
        /**
         * 创建viewHolder
         * @param parent
         * @param viewType
         * @return
         */
        @Override
        public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            //加载布局
            View view = LayoutInflater.from(context).inflate(R.layout.layout_recyclerview_item,parent,false);
            //创建viewholder对象,将布局传入
            ItemViewHolder viewHolder = new ItemViewHolder(view);
            return viewHolder;
        }
    
        /**
         * 绑定viewHolder
         * @param holder  recycleView.ViewHolder的子类
         * @param position 当前索引
         */
        @Override
        public void onBindViewHolder(final ItemViewHolder holder,final int position) {
            holder.tv_text.setText(dataList.get(position));
            //给每个item设置点击事件
            //判断是否存在监听
    /**
     这里加了判断,itemViewHolder.itemView.hasOnClickListeners()
     目的是减少对象的创建,如果已经为view设置了click监听事件,就不用重复设置了,不然每次调用onBindViewHolder方法,都会创建两个监听事件对象,增加了内存的开销
    */
            if(myOnItemClickListener != null&&!holder.tv_text.hasOnClickListeners()){
                holder.tv_text.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //注意:当点击该position的时候,recycleView中默认点击的是在父控件中的位置,当删除数据时,也是删除父布局中的对应索引的位置
                        //比如:删除点击item4会删除Item4,再点击item6,会删除item7,因为item7在父布局中位置为6,因此推荐使用父类的position
                        myOnItemClickListener.myOnItemClick(v,holder.getLayoutPosition());
                    }
                });
                holder.tv_text.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View v) {
                        myOnItemClickListener.myOItemLongClick(v,holder.getLayoutPosition());
                        return true;
                    }
                });
    
            }
        }
        @Override
        public int getItemCount() {
            return dataList.size();
        }
        /**
         * 设置自定义对外暴露的监听
         * @param myOnItemClickListener
         */
        public void setMyOnItemClickListener(MyOnItemClickListener myOnItemClickListener){
            this.myOnItemClickListener = myOnItemClickListener;
    
        }
    
        /**
         * 删除数据
         * @param position
         */
        public void deleteData(int position){
            dataList.remove(position);
            //更新当前删除条目的数据
            notifyItemRemoved(position);
        }
        public void addData(int positon,String data){
            dataList.add(positon,data);
            //只更新当前插入的条目的数据
            notifyItemInserted(positon);
        }
        /**
         * 添加数据
         * @param list
         */
        public void updateData(List<String> list){
            dataList.addAll(list);
            notifyDataSetChanged();
        }
    
        class ItemViewHolder extends RecyclerView.ViewHolder{
            private TextView tv_text;
            public ItemViewHolder(View itemView) {
                super(itemView);
                tv_text = (TextView) itemView.findViewById(R.id.tv_text);
            }
        }
        public interface  MyOnItemClickListener{
            void myOnItemClick(View view,int Postion);
            void myOItemLongClick(View view,int position);
        }
    
    }

    可以看到数据适配器与BaseAdapter比较发生了相当大的变化,主要有3个方法:

    getItemCount 这个不用说,获取总的条目数

    onCreateViewHolder 创建ViewHolder

    onBindViewHolder 将数据绑定至ViewHolder

    可见,RecyclerView对ViewHolder也进行了一定的封装,但是如果你仔细观察,你会发出一个疑问,ListView里面有个getView返回View为Item的布局,那么这个Item的样子在哪控制?

    其实是这样的,我们创建的ViewHolder必须继承RecyclerView.ViewHolder,这个RecyclerView.ViewHolder的构造时必须传入一个View,这个View相当于我们ListView getView中的convertView (即:我们需要inflate的item布局需要传入)。

    还有一点,ListView中convertView是复用的,在RecyclerView中,是把ViewHolder作为缓存的单位了,然后convertView作为ViewHolder的成员变量保持在ViewHolder中,也就是说,假设没有屏幕显示10个条目,则会创建10个ViewHolder缓存起来,每次复用的是ViewHolder,所以他把getView这个方法变为了onCreateViewHolder。有兴趣的自己打印下Log,测试下

    main方法:

    public class MainActivity extends AppCompatActivity {
    
        private RecyclerView recyclerView;
        private List<String> dataList = new ArrayList<String>();
        private MyRecyclerViewAdapter recyclerViewAdapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //初始化控件
            recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
            /**
                设置布局管理器,listview风格则设置为LinearLayoutManager
                gridview风格则设置为GridLayoutManager
                pu瀑布流风格的设置为StaggeredGridLayoutManager
                    */
            //默认竖直滚动
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
            linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
            recyclerView.setLayoutManager(linearLayoutManager);
            //初始化数据
            initData();
            //创建适配器
            recyclerViewAdapter = new MyRecyclerViewAdapter(this,dataList);
            //设置适配器
            recyclerView.setAdapter(recyclerViewAdapter);
            //设置自定义点击监听
            recyclerViewAdapter.setMyOnItemClickListener(new MyRecyclerViewAdapter.MyOnItemClickListener() {
                //点击item的时候调用
                @Override
                public void myOnItemClick(View view, int Postion) {
                    Toast.makeText(MainActivity.this, dataList.get(Postion), Toast.LENGTH_SHORT).show();
                    recyclerViewAdapter.deleteData(Postion);
                }
                //长按item的时候调用
                @Override
                public void myOItemLongClick(View view, int position) {
                    Toast.makeText(MainActivity.this,"长按--"+dataList.get(position), Toast.LENGTH_SHORT).show();
                    recyclerViewAdapter.addData(position,"我是新来的");
                }
            });
        }
    
        private void initData() {
            for (int i = 0; i < 30; i++) {
                dataList.add((i+1)+"条数据");
            }
        }
    }

    效果如下:

    点击时:

    点击后:

     长按后:

     

    ItemDecoration

    我们可以通过该方法添加分割线: 
    mRecyclerView.addItemDecoration() 

    RecyclerView.ItemDecoration的实现类

    package fanggao.qf.recycleviewlistview;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Rect;
    import android.graphics.drawable.Drawable;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.util.Log;
    import android.view.View;
    
    /**
     * Created by Administrator on 2016/9/27.
     */
    public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    
        private static final int[] ATTRS = new int[]{
                android.R.attr.listDivider
        };
    
        public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
    
        public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
    
        private Drawable mDivider;
    
        private int mOrientation;
    
        public DividerItemDecoration(Context context, int orientation) {
            final TypedArray a = context.obtainStyledAttributes(ATTRS);
            mDivider = a.getDrawable(0);
            a.recycle();
            setOrientation(orientation);
        }
    
        public void setOrientation(int orientation) {
            if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
                throw new IllegalArgumentException("invalid orientation");
            }
            mOrientation = orientation;
        }
    
        @Override
        public void onDraw(Canvas c, RecyclerView parent) {
            Log.v("recyclerview - itemdecoration", "onDraw()");
    
            if (mOrientation == VERTICAL_LIST) {
                drawVertical(c, parent);
            } else {
                drawHorizontal(c, parent);
            }
    
        }
    
    
        public void drawVertical(Canvas c, RecyclerView parent) {
            final int left = parent.getPaddingLeft();
            final int right = parent.getWidth() - parent.getPaddingRight();
    
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {
                final View child = parent.getChildAt(i);
                android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                        .getLayoutParams();
                final int top = child.getBottom() + params.bottomMargin;
                final int bottom = top + mDivider.getIntrinsicHeight();
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
            }
        }
    
        public void drawHorizontal(Canvas c, RecyclerView parent) {
            final int top = parent.getPaddingTop();
            final int bottom = parent.getHeight() - parent.getPaddingBottom();
    
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {
                final View child = parent.getChildAt(i);
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                        .getLayoutParams();
                final int left = child.getRight() + params.rightMargin;
                final int right = left + mDivider.getIntrinsicHeight();
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
            }
        }
    
        @Override
        public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
            if (mOrientation == VERTICAL_LIST) {
                outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
            } else {
                outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
            }
        }
    }

    该实现类可以看到通过读取系统主题中的 Android.R.attr.listDivider作为Item间的分割线,并且支持横向和纵向

    在源代码上添加一句

     recyclerView.addItemDecoration(new DividerItemDecoration(this,
                    DividerItemDecoration.VERTICAL_LIST));

    效果:

    该分割线是系统默认的,你可以在theme.xml中找到该属性的使用情况

    续:recycleView的一些常用属性:

    recyclerView.getChildCount()只是获取的是可见的item个数

    recyclerView.getLayoutManager().getItemCount()获取的是所有的item的个数

    recyclerView.getChildAt(int position) 获取某个位置的view

    recyclerView.getChildAdapterPosition(View view) 获取某个view的位置

    可通过上面几个属性,在recycleView的滚动监听中实现自定义的recycleView的上拉加载和下拉刷新

    具体见转载请标明出处: 
    http://blog.csdn.net/lmj623565791/article/details/45059587; 
    本文出自:【张鸿洋的博客】

  • 相关阅读:
    Javascript常见全局函数
    字符串入门练习题1 好长好长的字符串 题解
    字符串入门 讲义
    初等排序 大纲
    初等排序 讲义
    排序入门练习题10 病人排队 题解
    排序入门练习题9 合影效果 题解
    排序入门练习题7 分数线划定 题解
    排序入门练习题8 整数奇偶排序 题解
    排序入门练习题6 奖学金 题解
  • 原文地址:https://www.cnblogs.com/fangg/p/5914005.html
Copyright © 2011-2022 走看看