RecyclerView的基本使用,还有SwipeRefreshLayout(原生的下拉刷新)(1)

来源:互联网 发布:知乎hexo简书 编辑:程序博客网 时间:2024/04/28 23:07

基本简介:

RecyclerView是support-v7包中的新组件,是一个强大的滑动组件,

与ListView相比,

同样拥有item回收复用的功能,但是直接把viewholder的实现封装起来,用户只要实现自己的viewholder就可以了,该组件会自动帮你回收复用每一个item。它不但变得更精简,也变得更加容易使用,而且更容易组合设计出自己需要的滑动布局

当然,如果只是动态展示数据,listview也可以做到,用它替代listview的原因有几个:
1.它封装了viewholder的回收复用,解耦了生成viewholder跟设置viewholder
2.RecyclerView使用布局管理器管理子view的位置(目前尚只提供了LinearLayoutManager),也就是只要通过管理器(LinearLayoutManga,StaggeredGridLayoutManager,GridLayoutManager)来切换使用GridView,ListView,还是StaggerView.
3.自带了ItemAnimation,可以设置加载和移除时的动画,方便做出各种动态浏览的效果。(通过setItemAnimator)
4.还可以自定义边线(通过addItemDecoration这个来添加

APi基本简介

1.class RecyclerView.Adapter<VH extends RecyclerView.ViewHolder> 

描述:

Base class for an Adapter
Adapters provide a binding from an app-specific data set to views that are displayed within a RecyclerView. 

也就是提供一个BaseAdapter

final voidbindViewHolder(VH holder, int position)

This method internally calls onBindViewHolder(ViewHolder, int) to update the RecyclerView.ViewHolder contents with the item at the given position and also sets up some private fields to be used by RecyclerView.
final VHcreateViewHolder(ViewGroup parent, int viewType)
This method calls onCreateViewHolder(ViewGroup, int) to create a new RecyclerView.ViewHolder and initializes some private fields to be used by RecyclerView.
abstract intgetItemCount()
Returns the total number of items in the data set hold by the adapter.
longgetItemId(int position)
Return the stable ID for the item at position.
intgetItemViewType(int position)
Return the view type of the item at position for the purposes of view recycling.                          

(1).bindViewHolder就是把ViewHolder中的每个对应位置的内容设置进去

(2).createViewHolder就是创建ViewHolder

(3).getItemcount就相当于ListView中的getCount

(4).getItemViewType就是根据不同位置返回当前位置的条目类型

(这样一个ListView或者GridView里面可以有多种不同的条目,比如拉到最底下有个刷新)

注意:

因为RecyclerView没有像ListView一样设置setOnItemClickerListener或者setOnLongClickerListener,所以就通过ViewHolder来实现(下面有例子)


2.class RecyclerView.ItemAnimator

This class defines the animations that take place on items as changes are made to the adapter. 

定义数据增删时的动画

3.class RecyclerView.ItemDecoration

item views from the adapter's data set. 

An ItemDecoration allows the application to add a special drawing and layout offset to specific 

边线

4.class RecyclerView.LayoutManager 

A LayoutManager is responsible for measuring and positioning item views within a RecyclerView as well as determining the policy for when to recycle item views that are no longer visible to the user.  

测量和摆放所有的view,也就是控制显示样式

案例:

一:(一个Vertical方向的ListView)

效果:



代码:

ListViewVertical.java

public class ListViewVertical extends BaseActivity implements SwipeRefreshLayout.OnRefreshListener, MyAdapter.onRecyclerViewListener, View.OnClickListener {    @Bind(R.id.list)    RecyclerView mRecycleList;    @Bind(R.id.bt_add)    Button btAdd;    @Bind(R.id.swipe_refresh_widget)    SwipeRefreshLayout mSwipeRefreshLayout;    private LinearLayoutManager mLLmanager;    private ArrayList<String> mList = new ArrayList<>();    private ArrayList<String> mListExtraOne = new ArrayList<>();    private ArrayList<String> mListExtraTwo = new ArrayList<>();    private MyAdapter mAdapter;    private int mLastVisibleItem;    private int mFirstVisibleItem;    private int ii;    @Override    protected void instantiation() {        setContentView(R.layout.activity_list_view_horizontal_vertical);        ButterKnife.bind(this);        //下拉刷新控制颜色        mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light);        //设置他的下拉刷新监听器        mSwipeRefreshLayout.setOnRefreshListener(this);        //管理器        mLLmanager = new LinearLayoutManager(ListViewVertical.this, LinearLayoutManager.VERTICAL, false);        //        mRecycleList.setLayoutManager(mLLmanager);    }    @Override    protected void dataBind() {        //数据初始化        for (int i = 0; i < 30; i++) {            mList.add("我是内容" + i);        }        for (int i = 0; i < 3; i++) {            mListExtraOne.add("我是下拉增加的" + i);        }        for (int i = 0; i < 2; i++) {            mListExtraTwo.add("我是上拉增加的" + i);        }        mAdapter = new MyAdapter(mList, ListViewVertical.this);        //使RecyclerView保持固定的大小,这样会提高RecyclerView的性能。????        mRecycleList.setHasFixedSize(true);        mRecycleList.setAdapter(mAdapter);    }    @Override    protected void eventBind() {        mAdapter.setonRecyclerViewListener(this);        btAdd.setOnClickListener(this);        mRecycleList.setOnScrollListener(new RecyclerView.OnScrollListener() {            @Override            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                super.onScrollStateChanged(recyclerView, newState);                //滑动的状态一变化就会调用                //这里我们需要的滑到最后一个条目的时候(可见条目是最后一个,而且状态是idle)有一个自动刷新的条目出来                System.out.println("xcqmLastVisibleItem" + mLastVisibleItem);                System.out.println("xcqmList.size()" + mList.size());                //这里的mLastVisibleItem已经算上了  上拉的那个条目的item,所有等于mList.size()                if (newState == RecyclerView.SCROLL_STATE_IDLE && mLastVisibleItem == mList.size()) {                    handler.sendEmptyMessageDelayed(1, 3000);                }                //解决recyclerview  的item并没有达到第一个也能下拉刷新                if (newState == recyclerView.SCROLL_STATE_IDLE && mFirstVisibleItem == 0) {                    mSwipeRefreshLayout.setEnabled(true);                } else {                    mSwipeRefreshLayout.setEnabled(false);                }            }            @Override            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                super.onScrolled(recyclerView, dx, dy);                //滑动的时候会调用的函数                mLastVisibleItem = mLLmanager.findLastVisibleItemPosition();                mFirstVisibleItem = mLLmanager.findFirstVisibleItemPosition();            }        });    }    private android.os.Handler handler = new android.os.Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case 0:                    Toast.makeText(ListViewVertical.this, "DOWN", Toast.LENGTH_LONG).show();                    mSwipeRefreshLayout.setRefreshing(false);                    // mAdapter.getmList().clear();                    //  mAdapter.setmList(mList);                    mAdapter.notifyDataSetChanged();                    break;                case 1:                    Toast.makeText(ListViewVertical.this, "UP", Toast.LENGTH_LONG).show();                    mList.addAll(mListExtraTwo);                    mAdapter.setmList(mList);                    mAdapter.notifyDataSetChanged();                    break;            }        }    };    //下拉刷新    @Override    public void onRefresh() {        System.out.println("xcq下拉");        handler.sendEmptyMessageDelayed(0, 3000);    }    @Override    protected void onDestroy() {        super.onDestroy();        ButterKnife.unbind(this);    }    @Override    public void onItemClick(int position) {        System.out.println("xcqMA单击");        Toast.makeText(ListViewVertical.this, "我是条目" + mList.get(position) + "我被点了", Toast.LENGTH_SHORT).show();    }    @Override    public boolean onLongClick(int position) {        mAdapter.notifyItemRemoved(position);        mList.remove(position);        mAdapter.notifyItemRangeChanged(position, mAdapter.getItemCount());        //记住如果OnlongClick  return true 相当于处理了,那么onclick就不会在处理的        return true;    }    @Override    public void onClick(View view) {        if (view == btAdd) {            // Toast.makeText(MainActivity.this,"添加数据",Toast.LENGTH_SHORT).show();            ii++;            //插入到第二条            mAdapter.notifyItemInserted(3);            //真正开始插数据            mList.add(2, "刚加的" + ii);            //要把第二条开始一下的数据全部刷新一下            mAdapter.notifyItemRangeChanged(2, mAdapter.getItemCount());            //全部刷新没有动画了            // mAdapter.notifyDataSetChanged();        }    }}

MyAdapter.java

public class MyAdapter extends RecyclerView.Adapter {    private List<String> mList;    private Context mContext;//    private List<Integer> mHeightList;    private final static int TYPE_NORMAL_ITEM =1;    private final static int TYPE_FOOTER_ITEM =2;    private onRecyclerViewListener mRecyclerViewListener;    //写一个借口用来实现onitemclick 和 onlongclick    public interface onRecyclerViewListener{        void onItemClick(int position);        boolean onLongClick(int position);    }    //外部给出listener    public void setonRecyclerViewListener(onRecyclerViewListener listener){        this.mRecyclerViewListener = listener;    }    public MyAdapter(List<String> list, Context context) {        this.mList = list;        this.mContext = context;        //为了让瀑布流更明显,高度搞个随机的//        mHeightList = new ArrayList<Integer>();//        for(int i =0;i<50;i++){//            mHeightList.add((int) (50+Math.random()*300));//        }    }    public List<String> getmList() {        return mList;    }    public void setmList(List<String> mList) {        this.mList = mList;    }    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        //相当于原来的getView        if (viewType == TYPE_NORMAL_ITEM) {            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_text, null);            view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));            return new ItemViewHolder(view);        } else if (viewType == TYPE_FOOTER_ITEM) {            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.footerview, null);            view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));            return new FooterViewHolder(view);        }        return null;    }    @Override    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {        //然后在这里给textview设置具体内容        if(viewHolder instanceof  ItemViewHolder){          <span style="background-color: rgb(255, 0, 0);">  //设置不同高度,为了让瀑布流更加明显</span>//            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) ((ItemViewHolder) viewHolder).tv_item.getLayoutParams();//            params.height = mHeightList.get(i);//            viewHolder.itemView.setLayoutParams(params);            ((ItemViewHolder) viewHolder).tv_item.setText(mList.get(i));        }    }    @Override    public int getItemViewType(int position) {        //添加上拉刷新的条目        //list的最后一个是刷新条目        if(position == (getItemCount() -1)){            return TYPE_FOOTER_ITEM;        }else{            return TYPE_NORMAL_ITEM;        }    }    @Override    public int getItemCount() {        //相当于普通的listview中的getcount        return mList.size()>0 ? mList.size()+1 : 0;    }    //更多条目的那个条目的holder    class FooterViewHolder extends RecyclerView.ViewHolder{        public FooterViewHolder(View itemView) {            super(itemView);        }    }    //继承系统的ViewHolder    //recycle本身没有onitemclick,和onclick//我们这里就自己给他实现一个    class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener ,View.OnLongClickListener{        TextView tv_item;        private LinearLayout ll_item;        public ItemViewHolder(View itemView) {            super(itemView);            //然后得到了listView             tv_item = (TextView) itemView.findViewById(R.id.tv_item);             ll_item = (LinearLayout) itemView.findViewById(R.id.ll_item);             ll_item.setOnClickListener(this);             ll_item.setOnLongClickListener(this);        }        @Override        public void onClick(View view) {            System.out.println("xcqMy单击");            if(null != mRecyclerViewListener){                mRecyclerViewListener.onItemClick(this.getPosition());            }        }        @Override        public boolean onLongClick(View view) {            System.out.println("xcqMY长按");            if(null != mRecyclerViewListener){                //这个postition                return mRecyclerViewListener.onLongClick(this.getPosition());            }            return false;        }    }}


总结:

布局文件就不贴了,最后代码里面会有,这个例子实现简单的四个功能

1.上拉下拉刷新

用了Android自带的下拉刷新SwipeRefreshLayout,然后上拉刷新是是在adapter中通过getItemViewType做了一个第二种类型的条目
      //下拉刷新控制颜色        mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light);        //设置他的下拉刷新监听器        mSwipeRefreshLayout.setOnRefreshListener(this);

2.短按打印当前条目

RecyclerView自身是没有单个条目的点击事件(前面已经讲了),所以通过Adapter中的ViewHolder设置单个条目的点击事件,来实现这一功能

3.长按删除

同上,通过Adapter中的ViewHolder设置长按点击事件(如果长按return true短按就不会在执行了)

4.添加条目

这个就是普通的添加条目



二:(一个horizontal的ListView)

效果:



代码:

只是再上一个例子的基础上,改变了一下管理器

mLLmanager = new LinearLayoutManager(ListViewHorizontal.this, LinearLayoutManager.HORIZONTAL, false);

就是这么简单。


三.(一个Vertical方向的GridView)

效果:




代码:

也只是改了下管理器
gdmanager = new GridLayoutManager(this,3,GridLayoutManager.VERTICAL,false);

不过这里貌似出现了一个bug,就是下拉一直刷新停不下来,待解决

四.(瀑布流)

效果:



代码:

Adapter.java


public class StaggeredHomeAdapter extends RecyclerView.Adapter<StaggeredHomeAdapter.MyViewHolder>{private List<String> mDatas;private LayoutInflater mInflater;private List<Integer> mHeights;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;}public StaggeredHomeAdapter(Context context, List<String> datas){mInflater = LayoutInflater.from(context);mDatas = datas;mHeights = new ArrayList<Integer>();for (int i = 0; i < mDatas.size(); i++){mHeights.add( (int) (100 + Math.random() * 300));}}@Overridepublic MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){MyViewHolder holder = new MyViewHolder(mInflater.inflate(R.layout.item_staggered_home, parent, false));return holder;}@Overridepublic void onBindViewHolder(final MyViewHolder holder, final int position){
<span style="white-space:pre"></span>//这里就是设置不同条目的高度,这样才有瀑布流的感觉,在案例一也写了(被注释掉了)LayoutParams lp = holder.tv.getLayoutParams();lp.height = mHeights.get(position);holder.tv.setLayoutParams(lp);holder.tv.setText(mDatas.get(position));// 如果设置了回调,则设置点击事件if (mOnItemClickLitener != null){holder.itemView.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v){int pos = holder.getLayoutPosition();mOnItemClickLitener.onItemClick(holder.itemView, pos);}});holder.itemView.setOnLongClickListener(new OnLongClickListener(){@Overridepublic boolean onLongClick(View v){int pos = holder.getLayoutPosition();mOnItemClickLitener.onItemLongClick(holder.itemView, pos);removeData(pos);return false;}});}}@Overridepublic int getItemCount(){return mDatas.size();}public void addData(int position){mDatas.add(position, "Insert One");mHeights.add( (int) (100 + Math.random() * 300));notifyItemInserted(position);}public void removeData(int position){mDatas.remove(position);notifyItemRemoved(position);}class MyViewHolder extends ViewHolder{TextView tv;public MyViewHolder(View view){super(view);tv = (TextView) view.findViewById(R.id.id_num);}}}

StaggViewHorizontal.java

public class StaggViewHorizontal extends Activity{    private RecyclerView mRecyclerView;    private List<String> mDatas;    private StaggeredHomeAdapter mStaggeredHomeAdapter;    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_single_recyclerview);        initData();        mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);        mStaggeredHomeAdapter = new StaggeredHomeAdapter(this, mDatas);        mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,                StaggeredGridLayoutManager.VERTICAL));        mRecyclerView.setAdapter(mStaggeredHomeAdapter);        // 设置item动画(这个事默认的)        mRecyclerView.setItemAnimator(new DefaultItemAnimator());        initEvent();    }    private void initEvent()    {        mStaggeredHomeAdapter.setOnItemClickLitener(new StaggeredHomeAdapter.OnItemClickLitener()        {            @Override            public void onItemClick(View view, int position)            {                Toast.makeText(StaggViewHorizontal.this,                        position + " click", Toast.LENGTH_SHORT).show();            }            @Override            public void onItemLongClick(View view, int position)            {                Toast.makeText(StaggViewHorizontal.this,                        position + " long click", Toast.LENGTH_SHORT).show();            }        });    }    protected void initData()    {        mDatas = new ArrayList<String>();        for (int i = 'A'; i < 'z'; i++)        {            mDatas.add("" + (char) i);        }    }    @Override    public boolean onCreateOptionsMenu(Menu menu)    {        getMenuInflater().inflate(R.menu.main_staggered, menu);        return super.onCreateOptionsMenu(menu);    }    @Override    public boolean onOptionsItemSelected(MenuItem item)    {        switch (item.getItemId())        {            case R.id.id_action_add:                mStaggeredHomeAdapter.addData(1);                break;            case R.id.id_action_delete:                mStaggeredHomeAdapter.removeData(1);                break;        }        return true;    }}

总结:

其实也只是改了下管理器,主要是随机生成了单个条目的高度   


源码待上传,整理中


下一篇写一下自定义的animator和边线





1 0
原创粉丝点击