RecyclerView——Android新的列表(瀑布流)

Home / Android MrLee 2016-1-19 3637

我们常用的列表控件一般有2种,ListView和GridView,现在Android开发者又多了一个选择,那就是RecyclerView,从名字上面可以看出来,这是一个循环复用视图。RecyclerView出现其实已经有一段时间了。现在就来学习一下吧!
整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。
RecyclerView项目结构如下:

  • 你想要控制其显示的方式,请通过布局管理器LayoutManager
  • 你想要控制Item间的间隔(可绘制),请通过ItemDecoration
  • 你想要控制Item增删的动画,请通过ItemAnimator
  • 你想要控制点击、长按事件,请自己写(擦,这点尼玛。)
看下面简单代码(用的是匿名类,简单粗暴实现):
package com.androiddemo;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.android.dev.base.BaseActivity;
import com.android.dev.util.Tools;
public class RecyclerActivity extends BaseActivity {
	RecyclerView recyclerView;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_recycler);
		recyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
		recyclerView.setLayoutManager(new LinearLayoutManager(this));
		recyclerView.setAdapter(new MainAdapter());
	}
	class MainAdapter extends Adapter {
		private List mDatas;
		public MainAdapter() {
			super();
			// TODO Auto-generated constructor stub
			mDatas = new ArrayList();
			for (int i = 0; i < 10; i++) {
				mDatas.add("索引:" + (int) (Math.random() * 100) / 100f);
				Tools.sleep(1);// 休眠
			}
		}
		@Override
		public int getItemCount() {
			// TODO Auto-generated method stub
			return mDatas.size();
		}
		@Override
		public void onBindViewHolder(MainHolder holder, int position) {
			// TODO Auto-generated method stub
			holder.textView.setText(mDatas.get(position));
		}
		@Override
		public MainHolder onCreateViewHolder(ViewGroup group, int viewType) {
			// TODO Auto-generated method stub
			View view = getLayoutInflater().inflate(R.layout.recycler_item,
					group, false);
			MainHolder holder = new MainHolder(view);
			return holder;
		}
	}
	class MainHolder extends ViewHolder {
		TextView textView;
		public MainHolder(View view) {
			super(view);
			// TODO Auto-generated constructor stub
			textView = (TextView) view.findViewById(R.id.id_text);
		}
	}
}

layout布局:

    

子视图布局:


    

运行效果图:

QQ截图20160119194950

直线显示

recyclerview可以通过addItemDecoration来添加分隔线,我们先从最简单的直线入手。
DividerItemDecoration
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;
/**
 * This class is from the v7 samples of the Android SDK. It's not by me!
 * 

* See the license above for details. */ 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); 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); } } }


调用代码
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));

然后就有和listview的divider分隔线了。这个简单就不上图了。继续看Grib格子,DividerGridItemDecoration.java
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.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
/**
 * 
 * @author zhy
 * 
 */
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, State state) {
		drawHorizontal(c, parent);
		drawVertical(c, parent);
	}
	private int getSpanCount(RecyclerView parent) {
		// 列数
		int spanCount = -1;
		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) {
		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) {
		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());
		}
	}
}

调用方法
recyclerView.setAdapter(new MainAdapter());
		recyclerView.setLayoutManager(new GridLayoutManager(this, 4));// 格子排列
		recyclerView.addItemDecoration(new DividerGridItemDecoration(this));

效果图如下:

QQ截图20160120161724


如果你觉得到这里就完了就错了,还有更精彩的。我们先把每个元素的边距设置20dp,然后设置一个背景颜色#abcdef,adapter里面的数据调到100个。

QQ截图20160120162246


运行效果图:

QQ截图20160120162325


到了这里还是没有感觉到什么强大之处,因为GridView也可以完成这个效果,对吧。接下来看动画。注意,这里更新数据集不是用adapter.notifyDataSetChanged()而是 notifyItemInserted(position)与notifyItemRemoved(position)
		public void addItem(String text, int position) {
			mDatas.add(text);
			notifyItemInserted(position);
		}
		public void removeItem(int position) {
			mDatas.remove(position);
			notifyItemRemoved(position);
		}

我们就随便点击一个item就自动添加一个元素吧。说到这个事件就不得不说recyclerview的个性,人家不支持onItemClickListener,要实现子控件点击事件只能自己去实现。那怎么整呢?我们知道任何view可以可以添加click事件,既然如此就简单了,我们把每一个view都注册click事件不就行了嘛。下面是修改完成之后的源码,事件是基于最外层的Linearlayout视图的。
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView;
import com.android.dev.base.BaseActivity;
import com.android.dev.base.MLog;
import com.android.dev.util.Tools;
import com.androiddemo.other.DividerGridItemDecoration;
public class RecyclerActivity extends BaseActivity implements
		OnItemClickListener {
	RecyclerView recyclerView;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_recycler);
		recyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
		// recyclerView.setLayoutManager(new LinearLayoutManager(this));//线性排列
		// recyclerView.addItemDecoration(new
		// DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));
		final MainAdapter adapter = new MainAdapter();
		recyclerView.setAdapter(adapter);
		adapter.setItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClickListener(int position) {
				// TODO Auto-generated method stub
				MLog.makeText("点击:" + position);
				if (position == 6) {
					adapter.addItem("添加6", position);
				}
				if (position == 8) {
					adapter.removeItem(8);
				}
			}
		});
		// recyclerView.setLayoutManager(new GridLayoutManager(this, 4));// 格子排列
		// recyclerView.addItemDecoration(new DividerGridItemDecoration(this));
		recyclerView.setLayoutManager(new StaggeredGridLayoutManager(6,
				StaggeredGridLayoutManager.HORIZONTAL));// 瀑布流
		recyclerView.addItemDecoration(new DividerGridItemDecoration(this));
		recyclerView.setItemAnimator(new DefaultItemAnimator());// 子视图动画
	}
	class MainAdapter extends Adapter {
		private List mDatas;
		private OnItemClickListener itemClickListener;
		public MainAdapter() {
			super();
			// TODO Auto-generated constructor stub
			mDatas = new ArrayList();
			for (int i = 0; i < 100; i++) {
				mDatas.add("索引:" + i);
				Tools.sleep(1);// 休眠
			}
		}
		public void setItemClickListener(OnItemClickListener itemClickListener) {
			this.itemClickListener = itemClickListener;
		}
		public void addItem(String text, int position) {
			mDatas.add(text);
			notifyItemInserted(position);
		}
		public void removeItem(int position) {
			mDatas.remove(position);
			notifyItemRemoved(position);
		}
		@Override
		public int getItemCount() {
			// TODO Auto-generated method stub
			return mDatas.size();
		}
		@Override
		public void onBindViewHolder(MainHolder holder, int position) {
			// TODO Auto-generated method stub
			holder.textView.setText(mDatas.get(position));
			holder.parent.setTag(position);
		}
		@Override
		public MainHolder onCreateViewHolder(ViewGroup group, int viewType) {
			// TODO Auto-generated method stub
			View view = getLayoutInflater().inflate(R.layout.recycler_item,
					group, false);
			view.setOnClickListener(listener);
			MainHolder holder = new MainHolder(view);
			return holder;
		}
		OnClickListener listener = new OnClickListener() {
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				if (itemClickListener != null)
					itemClickListener.onItemClickListener(Integer.parseInt(v
							.getTag().toString()));
			}
		};
	}
	public interface OnItemClickListener {
		public void onItemClickListener(int position);
	}
	class MainHolder extends ViewHolder {
		View parent;
		TextView textView;
		public MainHolder(View view) {
			super(view);
			// TODO Auto-generated constructor stub
			this.parent = view;
			textView = (TextView) view.findViewById(R.id.id_text);
		}
	}
	@Override
	public void onItemClick(AdapterView parent, View view, int position,
			long id) {
		// TODO Auto-generated method stub
	}
}

效果图:

QQ截图20160120164907


我这边没上GIF动画,不然点击6会自动添加一个视图,点击8会自动减少一个视图。好了,就到这里吧!最后把修改过的资源贴出来


    

 
 

本文链接:https://www.it72.com/7709.htm

推荐阅读
最新回复 (0)
返回