本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布
1. RecyclerView常用功能
- 普通的上下滑动和左右滑动
- Grid效果上下滑动和左右滑动
- 瀑布流的上下滑动和左右滑动
- 添加分割线
- 添加item之间的空隙
- 去除最后一个item的分割线
- 添加点击事件
- 增加和删除item
- 添加动画
- 多布局
- 下拉刷新和上拉加载
- 添加头布局和脚布局
- 拖拽排序和侧滑删除
- 分页加载、上拉加载、添加脚布局DEMO
2. RecyclerView相关类
- RecyclerView.Adapter :创建子项item布局和绑定数据
- RecyclerView.ViewHolder :生成子项item的布局
- RecyclerView.LayoutManager :设置子项item的排列方式
- RecyclerView.ItemDecoration : 设置子项item的分割线
- RecyclerView.ItemAnimator : 设置子项item的动画
3. RecyclerView基本实现
- 依赖:
compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
- 布局:
- 设置布局管理器和Adapter
public class MainActivity extends AppCompatActivity {
private RecyclerView mMain_recyclerview;
private List mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
initData();
initAdapter();
}
//初始化控件
private void initView() {
setContentView(R.layout.activity_main);
mMain_recyclerview = (RecyclerView) findViewById(R.id.main_recyclerview);
}
//初始化数据
private void initData() {
mList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
mList.add("纵向和横向滑动");
mList.add("纵向和横向瀑布流");
mList.add("添加头布局和脚布局");
mList.add("下拉刷新和上拉加载");
mList.add("多布局页面");
mList.add("滑动删除");
mList.add("点击事件");
mList.add("添加空布局");
mList.add("添加分割线");
}
}
//初始化Adapter
private void initAdapter() {
//设置布局管理器
mMain_recyclerview.setLayoutManager(new LinearLayoutManager(this));
//初始化和设置Adapter
MainAdapter mainAdapter = new MainAdapter(mList);
mMain_recyclerview.setAdapter(mainAdapter);
}
}
- Adapter:
public class MainAdapter extends RecyclerView.Adapter {
private List mList;
public MainAdapter(List list) {
mList = list;
}
//创建子项item的布局
@Override
public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_item, parent, false);
return new ViewHolder(view);
}
//给控件设置数据
@Override
public void onBindViewHolder(MainAdapter.ViewHolder holder, int position) {
holder.tv_main.setText(mList.get(position));
}
//子项item的数量
@Override
public int getItemCount() {
return mList.size();
}
//初始化子项控件
static class ViewHolder extends RecyclerView.ViewHolder {
TextView tv_main;
public ViewHolder(View itemView) {
super(itemView);
this.tv_main = itemView.findViewById(R.id.tv_main);
}
}
}
4. RecyclerView左右和上下滑动以及瀑布流:
- 只需修改布局管理器参数即可:
//ListView形式上下滑动:
mMain_recyclerview.setLayoutManager(new LinearLayoutManager(this));
//左右滑动:
LinearLayoutManager magager = new LinearLayoutManager(this);
magager.setOrientation(LinearLayoutManager.HORIZONTAL);
//Grid形式上下滑动:
GridLayoutManager layoutManager = new GridLayoutManager(this,4);
//Grid形式左右滑动:
GridLayoutManager layoutManager = new GridLayoutManager(this, 4);
layoutManager.setOrientation(GridLayoutManager.HORIZONTAL);
//瀑布流形式上下滑动:
StaggeredGridLayoutManager layoutManager = new
StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL);
//瀑布流形式左右滑动:
StaggeredGridLayoutManager layoutManager = new
StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.HORIZONTAL);
5. ListView形式上下滑动和左右滑动添加分割线:
- 添加分割线:
mMain_recyclerview.addItemDecoration(new MyDividerItemDecoration(this, MyDividerItemDecoration.VERTICAL_LIST));
- MyDividerItemDecoration
ondraw:绘制 getItemOffsets:绘制的区域
public class MyDividerItemDecoration 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 int mOrientation;
private Drawable mDivider;
private int mDividerHeight = 2; //默认是2px
private Paint mPaint;
//绘制默认分割线
public MyDividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0); //系统属性中获取
a.recycle();
setOrientation(orientation);
}
/**
* 自定义分割线
*
* @param context
* @param orientation 列表方向
* @param drawableId 分割线图片
*/
public MyDividerItemDecoration(Context context, int orientation, int drawableId) {
this(context, orientation);
mDivider = ContextCompat.getDrawable(context, drawableId);
mDividerHeight = mDivider.getIntrinsicHeight();
}
/**
* 自定义分割线
*
* @param context
* @param orientation 列表方向
* @param dividerHeight 分割线高度
* @param dividerColor 分割线颜色
*/
public MyDividerItemDecoration(Context context, int orientation, int dividerHeight, int dividerColor) {
this(context, orientation);
mDividerHeight = dividerHeight;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(dividerColor);
mPaint.setStyle(Paint.Style.FILL);
}
private void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientaion");
}
mOrientation = orientation;
}
@Override //在RecyclerView的onDraw中执行
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
private 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-1; 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);
}
}
private 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-1; i++) {
final View child = parent.getChildAt(i);
RecyclerView v = new 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);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDividerHeight);
} else {
outRect.set(0, 0, mDividerHeight, 0);
}
}
}
6. Grid和瀑布流形式添加分割线
- 添加分割线:
mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));
- DividerGridItemDecoration(Grid和瀑布流形式都可用):
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration
{
private static final int[] ATTRS = new int[] { android.R.attr.listDivider };
private Drawable mDivider;
public DividerGridItemDecoration(Context context)
{
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)
{
drawHorizontal(c, parent);
drawVertical(c, parent);
}
private int getSpanCount(RecyclerView parent)
{
// 列数
int spanCount = -1;
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager)
{
spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
} else if (layoutManager instanceof StaggeredGridLayoutManager)
{
spanCount = ((StaggeredGridLayoutManager) layoutManager)
.getSpanCount();
}
return spanCount;
}
public void drawHorizontal(Canvas c, RecyclerView parent)
{
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.getLeft() - params.leftMargin;
final int right = child.getRight() + params.rightMargin
+ mDivider.getIntrinsicWidth();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawVertical(Canvas c, RecyclerView parent)
{
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 top = child.getTop() - params.topMargin;
final int bottom = child.getBottom() + params.bottomMargin;
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicWidth();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
int childCount)
{
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager)
{
if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
{
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager)
{
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
if (orientation == StaggeredGridLayoutManager.VERTICAL)
{
if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
{
return true;
}
} else
{
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
return true;
}
}
return false;
}
private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
int childCount)
{
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager)
{
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
return true;
} else if (layoutManager instanceof StaggeredGridLayoutManager)
{
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
// StaggeredGridLayoutManager 且纵向滚动
if (orientation == StaggeredGridLayoutManager.VERTICAL)
{
childCount = childCount - childCount % spanCount;
// 如果是最后一行,则不需要绘制底部
if (pos >= childCount)
return true;
} else
// StaggeredGridLayoutManager 且横向滚动
{
// 如果是最后一行,则不需要绘制底部
if ((pos + 1) % spanCount == 0)
{
return true;
}
}
}
return false;
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition,
RecyclerView parent)
{
int spanCount = getSpanCount(parent);
int childCount = parent.getAdapter().getItemCount();
if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部
{
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
} else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
{
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else
{
outRect.set(0, 0, mDivider.getIntrinsicWidth(),
mDivider.getIntrinsicHeight());
}
}
}
7. 添加item之间的空隙
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int leftRight;
private int topBottom;
public SpacesItemDecoration(int leftRight, int topBottom) {
this.leftRight = leftRight;
this.topBottom = topBottom;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
//竖直方向的
if (layoutManager.getOrientation() == LinearLayoutManager.VERTICAL) {
//最后一项需要 bottom
if (parent.getChildAdapterPosition(view) == layoutManager.getItemCount() - 1) {
outRect.bottom = topBottom;
}
outRect.top = topBottom;
outRect.left = leftRight;
outRect.right = leftRight;
} else {
//最后一项需要right
if (parent.getChildAdapterPosition(view) == layoutManager.getItemCount() - 1) {
outRect.right = leftRight;
}
outRect.top = topBottom;
outRect.left = leftRight;
outRect.bottom = topBottom;
}
}
}
int leftRight = DisplayUtil.dp2px(8);
int topBottom = DisplayUtil.dp2px(8);
mRecyclerView.addItemDecoration(new SpacesItemDecoration(leftRight, topBottom));
8. RecyclerView去除最后一个item的分割线
ListView形式:在上面的分割线绘制部分,我们只绘制了childCount-1个,所以上面的分割线,已经不会绘制最后一条item的分割线了。
Grid和瀑布流形式:首先去判断是不是最后一行或者一列,然后在getItemOffsets方法中不绘制底部或者右边,上面的部分已经实现。
9. RecyclerView添加点击事件
- 处理点击事件,只需要在Adapter中处理即可(不推荐)
public class PortraitAdapter extends RecyclerView.Adapter {
private List mFruitList;
private boolean flag = true;
public PortraitAdapter(List fruitList) {
mFruitList = fruitList;
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView fruitImage;
TextView fruitName;
LinearLayout ll_portraitscape;
public ViewHolder(View view) {
super(view);
fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
fruitName = (TextView) view.findViewById(R.id.fruit_name);
ll_portraitscape = (LinearLayout) view.findViewById(R.id.ll_portraitscape);
}
}
@Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_portrait, parent, false);
final ViewHolder holder = new ViewHolder(view);
holder.ll_portraitscape.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
new AlertDialog.Builder(v.getContext())
.setTitle("确认删除吗")
.setNegativeButton("取消",null)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (flag == true){
removeData(holder.getAdapterPosition());
flag=false;
}else{
addData(holder.getAdapterPosition());
flag=true;
}
}
})
.show();
return false;
}
});
holder.fruitImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(parent.getContext(),"我是图片短点击",Toast.LENGTH_SHORT).show();
}
});
return holder;
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
@Override
public int getItemCount() {
return mFruitList.size();
}
public void addData(int position) {
mFruitList.add(position, new Fruit("Apple", R.drawable.apple_pic));
notifyItemInserted(position);
}
public void removeData(int position) {
mFruitList.remove(position);
notifyItemRemoved(position);
}
}
只需要在onCreateViewHolder中处理即可,可以很轻松实现子项中任意控件或布局的点击事件。
- 在Adapter中定义接口并提供回调(推荐)
Adapter:
public interface OnItemClickListener{
void onItemClick(View view,int position);
void onItemLongClick(View view,int position);
}
public void setOnItemClickListener(OnItemClickListener mOnItemClickListener){
this.mOnItemClickListener = mOnItemClickListener;
}
onBindViewHolder:
if (mOnItemClickListener!=null){
holder.tv.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
int pos = holder.getLayoutPosition();
mOnItemClickListener.onItemClick(holder.tv,pos);
}
});
holder.tv.setOnLongClickListener(new View.OnLongClickListener(){
@Override
public boolean onLongClick(View view){
int pos = holder.getLayoutPosition();
mOnItemClickListener.onItemLongClick(holder.tv,pos);
return false;
}
}
}
Activity:
mHomeAdapter.setOnItemClickListener(new HomeAdapter.OnItemClickListener(){
@Override
public void onItemClick(View view,int position){
...
}
@Override
public void onItemLongClick(View view,final int position){
...
}
}
10. RecyclerView增加和删除item
- 在Adapter添加两种方法
public void addData(int position) {
mFruitList.add(position, new Fruit("Apple", R.drawable.apple_pic));
notifyItemInserted(position);
}
public void removeData(int position) {
mFruitList.remove(position);
notifyItemRemoved(position);
}
- 在Adapter中的onCreateViewHolder中的点击事件里面添加动作
holder.ll_portraitscape.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
new AlertDialog.Builder(v.getContext())
.setTitle("确认删除吗")
.setNegativeButton("取消",null)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (flag == true){
removeData(holder.getAdapterPosition());
flag=false;
}else{
addData(holder.getAdapterPosition());
flag=true;
}
}
})
.show();
return false;
}
});
11. RecyclerView添加动画效果
- 默认的动画:
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
- 自定义的动画:
private int mLastPosition;//放在成员变量的位置上
if (viewHolder.getAdapterPosition() > mLastPosition) {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(viewHolder.itemView, "scaleX", 0.5f, 1f);
scaleX.start();
mLastPosition = viewHolder.getLayoutPosition();
}
说明:实现的方式有很多种,这里介绍一种,就是在RecyclerView的onBindViewHolder中利用属性动画就可以实现非常华丽的效果。
12. RecyclerView多布局
- 实现多布局最核心的方法就是在Adapter中重写getItemViewType方法:
@Override
public int getItemViewType(int position) {
if (mNewsBeanList.get(position).getThumbnail_pic_s03() == null) {
return IMAGE_ONLY_ONE;
} else {
return IMAGE_TWOORTHREE;
}
}
说明:判断下布局的不同,返回不同的值,不同的值就代表了不多的布局。
- 在onCreateViewHolder方法中第二个参数对应的就是上面方法返回的值,我们根据值的不同,填充不同的布局。
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if (viewType == IMAGE_TWOORTHREE) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.news_imagethree_item, viewGroup, false);
ImageThreeViewHolder viewHolder = new ImageThreeViewHolder(view);
return viewHolder;
} else {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.news_imageonly_item, viewGroup, false);
ImageOnlyOneViewHolder viewHolder = new ImageOnlyOneViewHolder(view);
return viewHolder;
}
}
- 不同的布局需要不同的ViewHolder
static class ImageThreeViewHolder extends RecyclerView.ViewHolder {
private TextView mTv_title;
private ImageView mIv_image01;
private ImageView mIv_image02;
private ImageView mIv_image03;
private TextView mTv_company;
private TextView mTv_time;
private View mItemView;
public ImageThreeViewHolder(View itemView) {
super(itemView);
mItemView = itemView;
mTv_title = itemView.findViewById(R.id.tv_title);
mIv_image01 = itemView.findViewById(R.id.iv_image01);
mIv_image02 = itemView.findViewById(R.id.iv_image02);
mIv_image03 = itemView.findViewById(R.id.iv_image03);
mTv_company = itemView.findViewById(R.id.tv_company);
mTv_time = itemView.findViewById(R.id.tv_time);
}
}
static class ImageOnlyOneViewHolder extends RecyclerView.ViewHolder {
private View mItemView;
private TextView mTv_title;
private TextView mTv_company;
private TextView mTv_time;
private ImageView mIv_image01;
public ImageOnlyOneViewHolder(View itemView) {
super(itemView);
mItemView = itemView;
mTv_title = itemView.findViewById(R.id.tv_title);
mTv_company = itemView.findViewById(R.id.tv_company);
mTv_time = itemView.findViewById(R.id.tv_time);
mIv_image01 = itemView.findViewById(R.id.iv_image01);
}
}
- onBindViewHolder方法中的第一个参数对应不同的viewholder,我们通过判断,来进行每个元素的写入
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof ImageThreeViewHolder) {
((ImageThreeViewHolder) viewHolder).mTv_title.setText(mNewsBeanList.get(position).getTitle());
((ImageThreeViewHolder) viewHolder).mTv_company.setText(mNewsBeanList.get(position).getAuthor_name());
((ImageThreeViewHolder) viewHolder).mTv_time.setText(mNewsBeanList.get(position).getDate());
Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s()).into(((ImageThreeViewHolder) viewHolder).mIv_image01);
Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s02()).into(((ImageThreeViewHolder) viewHolder).mIv_image02);
Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s03()).into(((ImageThreeViewHolder) viewHolder).mIv_image03);
} else if (viewHolder instanceof ImageOnlyOneViewHolder) {
((ImageOnlyOneViewHolder) viewHolder).mTv_title.setText(mNewsBeanList.get(position).getTitle());
((ImageOnlyOneViewHolder) viewHolder).mTv_company.setText(mNewsBeanList.get(position).getAuthor_name());
((ImageOnlyOneViewHolder) viewHolder).mTv_time.setText(mNewsBeanList.get(position).getDate());
Glide.with(mContext).load(mNewsBeanList.get(position).getThumbnail_pic_s()).into(((ImageOnlyOneViewHolder) viewHolder).mIv_image01);
}
}
13. RecyclerView 上拉刷新和下拉加载
- 下拉刷新(借助SwipeRefreshLayout)
private void initRefresh() {
srRefresh.setColorSchemeResources(R.color.colorPrimary);
srRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshFruits();
}
});
}
private void refreshFruits() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
initFruits();
adapter.notifyDataSetChanged();
srRefresh.setRefreshing(false);
}
});
}
}).start();
}
private void initFruits() {
fruitList.clear();
for (int i = 0; i < 50; i++) {
Random random = new Random();
int index = random.nextInt(fruits.length);
fruitList.add(fruits[index]);
}
}
说明:SwipeRefreshLayout设置一个监听器:setOnRefreshListener,onRefresh方法中进行数据更新的操作。
- 上拉加载
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (adapter.isFadeTips() == false && lastVisibleItem + 1 == adapter.getItemCount()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
}
}, 500);
}
if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
}
}, 500);
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
}
});
说明:recyclerView添加滑动监听器addOnScrollListener,在onScrollStateChanged方法中处理加载的动作。
14. RecyclerView添加头布局和脚布局
添加头布局和脚布局,其实和实现多布局一模一样,不再赘述。
15. RecyclerView拖曳排序和侧滑删除
private void initBind() {
//为RecycleView绑定触摸事件
ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//侧滑删除
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
//首先回调的方法 返回int表示是否监听该方向
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;//拖拽
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//滑动事件
Collections.swap(list, viewHolder.getAdapterPosition(), target.getAdapterPosition());
adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//侧滑事件
list.remove(viewHolder.getAdapterPosition());
adapter.notifyItemRemoved(viewHolder.getAdapterPosition());
}
@Override
public boolean isLongPressDragEnabled() {
//是否可拖拽
return true;
}
});
helper.attachToRecyclerView(recyclerView);
}
16. 分页加载、上拉加载、添加脚布局DEMO
分页加载的核心代码:
private final int PAGE_COUNT = 10;
adapter = new MyAdapter(getDatas(0, PAGE_COUNT), this, getDatas(0, PAGE_COUNT).size() > 0 ? true : false);
private List getDatas(final int firstIndex, final int lastIndex) {
List resList = new ArrayList<>();
for (int i = firstIndex; i < lastIndex; i++) {
if (i < list.size()) {
resList.add(list.get(i));
}
}
return resList;
}
private void updateRecyclerView(int fromIndex, int toIndex) {
List newDatas = getDatas(fromIndex, toIndex);
if (newDatas.size() > 0) {
adapter.updateList(newDatas, true);
} else {
adapter.updateList(null, false);
}
}
Adapter:
public class MyAdapter extends RecyclerView.Adapter {
private List datas;
private Context context;
private int normalType = 0;
private int footType = 1;
private boolean hasMore = true;
private boolean fadeTips = false;
private Handler mHandler = new Handler(Looper.getMainLooper());
private static final String TAG = "MyAdapter";
public MyAdapter(List datas, Context context, boolean hasMore) {
this.datas = datas;
this.context = context;
this.hasMore = hasMore;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == normalType) {
return new NormalHolder(LayoutInflater.from(context).inflate(R.layout.item, null));
} else {
return new FootHolder(LayoutInflater.from(context).inflate(R.layout.footview, null));
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof NormalHolder) {
((NormalHolder) holder).textView.setText(datas.get(position));
} else {
((FootHolder) holder).tips.setVisibility(View.VISIBLE);
if (hasMore == true) {
fadeTips = false;
if (datas.size() > 0) {
((FootHolder) holder).tips.setText("正在加载更多...");
}
} else {
if (datas.size() > 0) {
((FootHolder) holder).tips.setText("没有更多数据了");
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
((FootHolder) holder).tips.setVisibility(View.GONE);
fadeTips = true;
hasMore = true;
}
}, 500);
}
}
}
}
@Override
public int getItemCount() {
return datas.size() + 1;
}
public int getRealLastPosition() {
return datas.size();
}
public void updateList(List newDatas, boolean hasMore) {
if (newDatas != null) {
datas.addAll(newDatas);
}
this.hasMore = hasMore;
notifyDataSetChanged();
}
class NormalHolder extends RecyclerView.ViewHolder {
private TextView textView;
public NormalHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.tv);
}
}
class FootHolder extends RecyclerView.ViewHolder {
private TextView tips;
public FootHolder(View itemView) {
super(itemView);
tips = (TextView) itemView.findViewById(R.id.tips);
}
}
public boolean isFadeTips() {
return fadeTips;
}
public void resetDatas() {
datas = new ArrayList<>();
}
@Override
public int getItemViewType(int position) {
Log.e(TAG,"getItemCount()::"+getItemCount());
Log.e(TAG,"position::"+position);
if (position == getItemCount() - 1) {
return footType;
} else {
return normalType;
}
}
}
Activity:
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
private SwipeRefreshLayout refreshLayout;
private RecyclerView recyclerView;
private List list;
private int lastVisibleItem = 0;
private final int PAGE_COUNT = 10;
private LinearLayoutManager mLayoutManager;
private MyAdapter adapter;
private Handler mHandler = new Handler(Looper.getMainLooper());
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
findView();
initRefreshLayout();
initRecyclerView();
}
private void initData() {
list = new ArrayList<>();
for (int i = 1; i <= 40; i++) {
list.add("条目" + i);
}
}
private void findView() {
refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refreshLayout);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
}
private void initRefreshLayout() {
refreshLayout.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);
refreshLayout.setOnRefreshListener(this);
}
private void initRecyclerView() {
adapter = new MyAdapter(getDatas(0, PAGE_COUNT), this, getDatas(0, PAGE_COUNT).size() > 0 ? true : false);
mLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setAdapter(adapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (adapter.isFadeTips() == false && lastVisibleItem + 1 == adapter.getItemCount()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
}
}, 500);
}
if (adapter.isFadeTips() == true && lastVisibleItem + 2 == adapter.getItemCount()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Log.e(TAG, "lastVisibleItem::" + lastVisibleItem);
Log.e(TAG, "adapter.getItemCount()::" + adapter.getItemCount());
updateRecyclerView(adapter.getRealLastPosition(), adapter.getRealLastPosition() + PAGE_COUNT);
}
}, 500);
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
Log.e(TAG, "lastVisibleItem::" + lastVisibleItem);
Log.e(TAG, "adapter.getItemCount()::" + adapter.getItemCount());
}
});
}
private List getDatas(final int firstIndex, final int lastIndex) {
List resList = new ArrayList<>();
for (int i = firstIndex; i < lastIndex; i++) {
if (i < list.size()) {
resList.add(list.get(i));
}
}
return resList;
}
private void updateRecyclerView(int fromIndex, int toIndex) {
List newDatas = getDatas(fromIndex, toIndex);
if (newDatas.size() > 0) {
adapter.updateList(newDatas, true);
} else {
adapter.updateList(null, false);
}
}
@Override
public void onRefresh() {
refreshLayout.setRefreshing(true);
adapter.resetDatas();
updateRecyclerView(0, PAGE_COUNT);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
refreshLayout.setRefreshing(false);
}
}, 1000);
}
}
详细说明:http://blog.csdn.net/ljcITworld/article/details/70160820
下载地址:https://github.com/OnlyYouMyLove/PullToLoadData-RecyclerView
17. 后续
如果大家喜欢这篇文章,欢迎点赞;如果想看更多前端移动端后端Java或Python方面的技术,欢迎关注!