Android学习之RecyclerView学习
来源:互联网 发布:服务器与数据库的区别 编辑:程序博客网 时间:2024/05/17 08:33
内容概括:
- 给recyclerView添加分割线
- 给recyclerView添加HeaderView和FootView
- 给recyclerView添加刷新功能,这里使用的是Android系统的SwipeRefreshLayout
- recyclerView子项的点击事件【三种实现方式】
RecyclerView出来很长时间,但一直没有用在项目中,这个项目打算全部使用RecyclerView代替ListView,所以学习了一波,把看到的整理出来
RecyclerView比ListView更灵活,可以动态设置布局方向,也可以动态切换成ListView gridview以及瀑布流形式
- -
基础的使用
添加依赖
compile 'com.android.support:recyclerview-v7:24.0.0-beta1'
xml布局中像使用正常控件一样添加
<android.support.v7.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent" />
初始化视图
mRecyclerView = (RecyclerView) findViewById(R.id.recycler); linear = new LinearLayoutManager(this); //设置布局管理器,这里设置为线性布局 mRecyclerView.setLayoutManager(linear); //设置布局方向 linear.setOrientation(LinearLayoutManager.VERTICAL); //设置适配器 adpt = new MyAdapter(this, mList); //设置适配器 mRecyclerView.setAdapter(adpt);
初始化数据
private void initDatas() { mList = new ArrayList<>(); for (int i = 0; i < 20; i++) { mList.add("item" + i); } }
RecyclerView与ListView的适配器不同,需要继承自RecyclerView的Adapter
代码
package com.cd.recyclerviewdemo;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;/** * Author Chendan * Create Date 2016/9/9. * Description: */public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyVeiwHold> { Context mContext; List<String> mList; //构造方法,初始化数据 public MyAdapter(Context context, List<String> mlist) { mContext = context; mList = mlist; } //初始化控件 @Override public MyVeiwHold onCreateViewHolder(ViewGroup parent, int viewType) { View layout = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler, parent, false); return new MyVeiwHold(layout); } //绑定控件 @Override public void onBindViewHolder(MyVeiwHold holder, final int position) { ((MyVeiwHold)holder).mTextView.setText(mList.get(position )); /** * @return */ @Override public int getItemCount() { return mList.size(); } // class MyVeiwHold extends RecyclerView.ViewHolder { TextView mTextView; public MyVeiwHold(View itemView) { super(itemView);mTextView = (TextView) itemView.findViewById(R.id.item_tv); } }}
通过以上代码的编写,就能实现普通ListView展示的功能了
但是会发现子项之间没有分割线,于是需要特别为它写一个类去绘制分割线
- -
添加分割线
代码
package com.cd.recyclerviewdemo;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.view.View;import android.widget.LinearLayout;import org.w3c.dom.Attr;/** * Author Chendan * Create Date 2016/9/9. * Description: */public class Decretion extends RecyclerView.ItemDecoration { /** * 成员变量 */ //上下文 Context mContext; //线 private Drawable mdevider; //方向 private int moritation; //水平 public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; //垂直 public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; //获取系统属性 public static final int[] Attr = new int[]{android.R.attr.listDivider}; public Decretion(Context context, int oritation) { mContext = context; //通过上下文对象获取属性数组 TypedArray ta = context.obtainStyledAttributes(Attr); //通过属性数组。获取对应属性获取线 this.mdevider = ta.getDrawable(0); //回收属性 ta.recycle(); //初始化方向 setOritation(oritation); } private void setOritation(int oritation) { //如果方向不为水平也不为垂直,则跑出非法异常 if (oritation != HORIZONTAL_LIST && oritation != VERTICAL_LIST) { new IllegalArgumentException("invalid orientation"); } else { moritation = oritation; } } // @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, state); if (moritation == HORIZONTAL_LIST) { drawVerticalLine(c, parent, state); } else { drawHorizontalLine(c, parent, state); } } //绘制水平线 private void drawHorizontalLine(Canvas c, RecyclerView parent, RecyclerView.State state) { //左边 int left = parent.getPaddingLeft(); //右边 int right = parent.getWidth() - parent.getPaddingRight(); //子视图数量 int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { View child = parent.getChildAt(i); RecyclerView.LayoutParams param = (RecyclerView.LayoutParams) child.getLayoutParams(); final int top = child.getBottom() + param.bottomMargin; final int bottom = top + mdevider.getIntrinsicHeight(); mdevider.setBounds(left, top, right, bottom); mdevider.draw(c); } } //绘制垂直线 private void drawVerticalLine(Canvas c, RecyclerView parent, RecyclerView.State state) { int top = parent.getPaddingTop(); int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); //获得child的布局信息 final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); final int left = child.getRight() + params.rightMargin; final int right = left + mdevider.getIntrinsicWidth(); mdevider.setBounds(left, top, right, bottom); mdevider.draw(c); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); if (moritation == HORIZONTAL_LIST) { //画横线,就是往下偏移一个分割线的高度 outRect.set(0, 0, 0, mdevider.getIntrinsicHeight()); } else { //画竖线,就是往右偏移一个分割线的宽度 outRect.set(0, 0, mdevider.getIntrinsicWidth(), 0); } }}
获取到系统属性然后通过方向判断绘制横向的还是垂直的
在视图初始化中添加这样一行代码
//添加下划线 mRecyclerView.addItemDecoration(new Decretion(this, Decretion.VERTICAL_LIST));
Decretion类中使用到的attr和drawable代码如下
在AppTheme中添加
<item name="android:listDivider">@drawable/divider</item>
在drawable文件夹下定义divider
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#7b7a7a"/> <size android:height="1dp"/></shape>
添加完以上代码运行就会有下划线的效果了,这样比较灵活可以自定义线的颜色和粗细
- -
RecyclerView添加头部视图和足部视图
分别定义好头部和足部布局
header
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="100dp"> <TextView android:id="@+id/header" android:layout_width="match_parent" android:layout_height="match_parent" android:text="我是Header" android:textSize="30sp" android:textColor="#fde70b0b" android:background="#f9777979" android:gravity="center"/></LinearLayout>
footer与header同样,只是显示的文本不同
然后在activity中添加两个方法把布局添加进来
//设置HeardView private void setHeaderView(RecyclerView view) { View header = LayoutInflater.from(this).inflate(R.layout.header, view, false); adpt.setHeaderView(header); } //设置FooterView private void setFooterView(RecyclerView view) { View footer = LayoutInflater.from(this).inflate(R.layout.footer, view, false); adpt.setFooterView(footer); }
这个adpt就是我的适配器,适配器中定义了setFooterView和setHeaderView方法
代码:
//获取HeaderView public View getHeaderView() { return mHeaderView; } //设置HeaderView public void setHeaderView(View headerView) { mHeaderView = headerView; //更新第一条 notifyItemInserted(0); } //获取FootView public View getFooterView() { return mFooterView; } //设置FooterView public void setFooterView(View footerView) { mFooterView = footerView; //更新最后一条 notifyItemInserted(getItemCount() - 1); }
其他方法代码也要相应改变,适配器所有代码
package com.cd.recyclerviewdemo;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;/** * Author Chendan * Create Date 2016/9/9. * Description: */public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyVeiwHold> { Context mContext; List<String> mList; public static final int TYPE_HEADER = 0; //带有Header的类型 public static final int TYPE_FOOTER = 1; //是带有Footer的类型 public static final int TYPE_NORMAL = 2; //不带有header和footer的类型,正常类型 private View mHeaderView;//头部视图 private View mFooterView;//足部视图 public onRecyclerViewItemOnClick mItemOnClick; /** * 定义recyclerView的点击事件接口 */ public interface onRecyclerViewItemOnClick { //点击事件 void onItemClick(View view, int position); //长按事件 void onItemLongClick(View view, int position); } /** * 设置set方法 */ public void setItemClick(onRecyclerViewItemOnClick itemOnClick) { mItemOnClick = itemOnClick; } //构造方法,初始化数据 public MyAdapter(Context context, List<String> mlist) { mContext = context; mList = mlist; } //获取HeaderView public View getHeaderView() { return mHeaderView; } //设置HeaderView public void setHeaderView(View headerView) { mHeaderView = headerView; //更新第一条 notifyItemInserted(0); } //获取FootView public View getFooterView() { return mFooterView; } //设置FooterView public void setFooterView(View footerView) { mFooterView = footerView; //更新最后一条 notifyItemInserted(getItemCount() - 1); } //初始化控件 @Override public MyVeiwHold onCreateViewHolder(ViewGroup parent, int viewType) { //如果有头部视图 if (mHeaderView != null && viewType == TYPE_HEADER) { //返回头部视图的Hold return new MyVeiwHold(mHeaderView); } //如果有足部视图 if (mFooterView != null && viewType == TYPE_FOOTER) { //返回足部视图的Hold return new MyVeiwHold(mFooterView); } View layout = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler, parent, false); return new MyVeiwHold(layout); } //绑定控件 @Override public void onBindViewHolder(MyVeiwHold holder, final int position) { /** * 对子项视图的类型进行判断,1,正常无头部和足部视图的情况下2,有头部视图的情况下3,有足部视图的情况下以及头足部都有的情况下 */ if (getItemViewType(position) == TYPE_NORMAL) { if (holder instanceof MyVeiwHold) { //这里加载数据的时候要注意,是从position-1开始,因为position==0已经被header占用了 ((MyVeiwHold) holder).mTextView.setText(mList.get(position - 1)); if (mItemOnClick!=null){ holder.mTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mItemOnClick.onItemClick(v,position); } }); holder.mTextView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { mItemOnClick.onItemLongClick(v,position); return false; } }); } return; } return; } else if (getItemViewType(position) == TYPE_HEADER) { return; } else { return; } } /** * @return */ @Override public int getItemCount() { if (mHeaderView == null && mFooterView == null) { return mList.size(); } else if (mHeaderView == null && mFooterView != null) { return mList.size() + 1; } else if (mHeaderView != null && mFooterView == null) { return mList.size() + 1; } else { return mList.size() + 2; } } // class MyVeiwHold extends RecyclerView.ViewHolder { TextView mTextView; public MyVeiwHold(View itemView) { super(itemView); //如果是headerview或者是footerview,直接返回 if (itemView == mHeaderView) { return; } if (itemView == mFooterView) { return; } mTextView = (TextView) itemView.findViewById(R.id.item_tv); } } /** * 重写这个方法,很重要,是加入Header和Footer的关键,我们通过判断item的类型,从而绑定不同的view * */ @Override public int getItemViewType(int position) { if (mHeaderView == null && mFooterView == null) { return TYPE_NORMAL; } if (position == 0) { //第一个item应该加载Header return TYPE_HEADER; } if (position == getItemCount() - 1) { //最后一个,应该加载Footer return TYPE_FOOTER; } return TYPE_NORMAL; }}
在activity中调用
//为RecyclerView添加HeaderView和FooterView setHeaderView(mRecyclerView); setFooterView(mRecyclerView);
这样就实现了添加头部视图和足部视图
-
RecyclerView刷新
在布局的最外层包裹一个控件SwipeRefreshLayout
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/swip" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.cd.recyclerviewdemo.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent" /></android.support.v4.widget.SwipeRefreshLayout>
在初始化中添加
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swip); //设置卷内的颜色 mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright, android.R.color.holo_green_light, android.R.color.holo_orange_light, android.R.color.holo_red_light);
刷新
//刷新 mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { //往集合中添加数据 mList.add(0, "嘿,我是下拉刷新的数据"); //更新适配器中的数据 adpt.notifyDataSetChanged(); //关闭刷新 mSwipeRefreshLayout.setRefreshing(false); } });
加载
//加载 mRecyclerView.addOnScrollListener(new EndLessOnScrollListener(linear) { @Override public void onLoadMore(int currentPage) { //加载更多,这里是测试数据,所以直接加载更多, // 如果是真是开发中,需要传入currentPage这个参数来实现分页效果, // 否则一次性加载太多影响性能 loadMoreData(); } });
private void loadMoreData() { for (int i = 0; i < 10; i++) { mList.add("哈哈,拉出第" + i + "条数据"); adpt.notifyDataSetChanged(); } }
这里的EndLessOnScrollListener是定义的一个接口,继承自RecyclerView.OnScrollListener
package com.cd.recyclerviewdemo;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.util.Log;/** * Author Chendan * Create Date 2016/9/9. * Description: */public abstract class EndLessOnScrollListener extends RecyclerView.OnScrollListener { //声明一个LinearLayoutManager private LinearLayoutManager mLinearLayoutManager; // 当前页,从0开始 private int currentPage = 0; //已经加载出来的Item的数量 private int totalItemCount; //主要用来存储上一个totalItemCount private int previousTotal = 0; //在屏幕上可见的item数量 private int visibleItemCount; //在屏幕可见的Item中的第一个 private int firstVisibleItem; //是否正在上拉数据 private boolean loading = true; public EndLessOnScrollListener(LinearLayoutManager linearLayoutManager) { this.mLinearLayoutManager = linearLayoutManager; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); //显示在屏幕中的数量 visibleItemCount = recyclerView.getChildCount(); //总数量 totalItemCount = mLinearLayoutManager.getItemCount(); //第一项可见数量 firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition(); //如果正在上拉数据,并且数据当前总条数大于上一次总条数 if (loading) { if (totalItemCount > previousTotal) { //说明数据已经加载结束 loading = false; //保存这次的总条数 previousTotal = totalItemCount; } } //这里需要好好理解 if (!loading && totalItemCount - visibleItemCount <= firstVisibleItem) { currentPage++; onLoadMore(currentPage); loading = true; } } /** * 提供一个抽闲方法,在Activity中监听到这个EndLessOnScrollListener * 并且实现这个方法 */ public abstract void onLoadMore(int currentPage);}
RecyclerView的点击事件
有三种实现方式,但是我只选择一种我最熟悉也最适合我们项目的记下来,要具体了解可以看看这篇文章
http://www.tuicool.com/articles/au6ZvmB
1,通过 RecyclerView 已有的方法 addOnItemTouchListener() 实现
2,在绑定 ItemView 时添加点击监听
3,当 ItemView attach RecyclerView 时实现
我使用的是第二种
在适配器中定义设置监听的接口
/** * 定义recyclerView的点击事件接口 */ public interface onRecyclerViewItemOnClick { //点击事件 void onItemClick(View view, int position); //长按事件 void onItemLongClick(View view, int position); }
给接口设置set方法,方便调用
/** * 设置set方法 */ public onRecyclerViewItemOnClick mItemOnClick; public void setItemClick(onRecyclerViewItemOnClick itemOnClick) { mItemOnClick = itemOnClick; }
在绑定视图的时候给item每一个控件设置点击事件,这是一种item点击事件的假象,但是可以实现功能
//绑定控件 @Override public void onBindViewHolder(MyVeiwHold holder, final int position) { /** * 对子项视图的类型进行判断,1,正常无头部和足部视图的情况下2,有头部视图的情况下3,有足部视图的情况下以及头足部都有的情况下 */ if (getItemViewType(position) == TYPE_NORMAL) { if (holder instanceof MyVeiwHold) { //这里加载数据的时候要注意,是从position-1开始,因为position==0已经被header占用了 ((MyVeiwHold) holder).mTextView.setText(mList.get(position - 1)); if (mItemOnClick!=null){ holder.mTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mItemOnClick.onItemClick(v,position); } }); holder.mTextView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { mItemOnClick.onItemLongClick(v,position); return false; } }); } return; } return; } else if (getItemViewType(position) == TYPE_HEADER) { return; } else { return; } }
在activity中调用
adpt.setItemClick(new MyAdapter.onRecyclerViewItemOnClick() { @Override public void onItemClick(View view, int position) { Toast.makeText(MainActivity.this, "点击view.getId()+position:" + (view.getId() + position), Toast.LENGTH_SHORT).show(); } @Override public void onItemLongClick(View view, int position) { Toast.makeText(MainActivity.this, "长按view.getId()+position:" + (view.getId() + position), Toast.LENGTH_SHORT).show(); } });
参考文章
http://www.jianshu.com/p/3bf125b4917d
http://www.jianshu.com/p/4eff036360da
http://www.jianshu.com/p/991062d964cf
- Android学习之RecyclerView
- Android学习之RecyclerView
- Android学习之RecyclerView
- Android学习之RecyclerView
- Android学习之RecyclerView
- Android学习之RecyclerView
- Android学习之RecyclerView学习
- Android学习笔记之RecyclerView
- Android——RecyclerView入门学习之RecyclerView.Adapter
- Android学习之RecyclerView(三)-ItemDecoration
- Android学习笔记之RecyclerView详解
- android学习之RecyclerView的简单使用
- Android学习之SwipeRefreshLayout+RecyclerView+CardView
- #Android学习#RecyclerView基础
- Android学习RecyclerView小结
- android RecyclerView学习笔记
- Android--RecyclerView学习
- Android RecyclerView源码学习
- 替换空格
- 什么是P问题、NP问题和NPC问题
- 第3章 管道符、重定向与环境变量
- hdoj3714【三分】
- [Java]阿里内部面试总结
- Android学习之RecyclerView学习
- Javascript函数封装
- LIBSVM使用方法及参数设置
- Android开源库之使用ZXing开源库二维码-实现竖屏且高识别率
- CCF 消除类游戏
- Android自定义控件下拉刷新和加载更多
- 【一步步学OpenGL 2】-《你好顶点》
- 北大暑期学习之并查集
- Xcode命令Archive导出4个ipa包的含义