• 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; 
    本文出自:【张鸿洋的博客】

  • 相关阅读:
    POJ3320 Jessica's Reading Problem
    POJ3320 Jessica's Reading Problem
    CodeForces 813B The Golden Age
    CodeForces 813B The Golden Age
    An impassioned circulation of affection CodeForces
    An impassioned circulation of affection CodeForces
    Codeforces Round #444 (Div. 2) B. Cubes for Masha
    2013=7=21 进制转换
    2013=7=15
    2013=7=14
  • 原文地址:https://www.cnblogs.com/fangg/p/5914005.html
Copyright © 2020-2023  润新知