android中RecyclerView
来源:互联网 发布:蜻蜓fm电脑软件 编辑:程序博客网 时间:2024/04/29 18:04
这是官网对support.v4,support.v7等的一个说明:点击这里
那今天就先来讲RecyclerView。在RecyclerView中有几项比较重要
- ItemDecoration:这个一看就知道是对每个item进行装饰,也就是在每个item的外围对其进行装饰
- ItemAnimator:这个是说明每个item在删除、增加等时进行的动画。
- ItemTouchHelper:给每个item增加了drag、drop、swipe的手势,可以上下拉,也可以水平被滑出
- LayoutManager:该类是说明RecyclerView的布局方式,该类是一个抽象类,其子类有LinearLayoutManager和StaggeredGridLayoutManager,如果给RecyclerView设置LinearLayoutManager的话,效果就和普通的listView一样,不过还可以给其设置Horizontal和Vertical。如果给RecyclerView设置StaggeredGridLayoutManager的话,效果是错列的网格,和Grid的区别就是每个item的高度可以不一样,达到错列的效果。LinearLayoutManager的子类是GridLayoutManager,效果就是每个item等高的网格。
RecyclerView rv = (RecyclerView) findViewById(R.id.lv);GridLayoutManager layoutManager=new GridLayoutManager(this,3);rv.setLayoutManager(layoutManager);RecyclerViewAdapter adapter = new RecyclerViewAdapter();rv.setAdapter(adapter);你会发现初始化RecyclerView比ListView要稍微繁琐点,要为其设置LayoutManager,这是因为ListView默认是垂直排列的,但是RecyclerView需要给他设置LayoutManager,它才知道如何绘制Item,否则界面上什么也不显示。
public static abstract class ItemDecoration { /** * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. * Any content drawn by this method will be drawn before the item views are drawn, * and will thus appear underneath the views. * * @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView */ public void onDraw(Canvas c, RecyclerView parent, State state) { onDraw(c, parent); } /** * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. * Any content drawn by this method will be drawn after the item views are drawn * and will thus appear over the views. * * @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView. */ public void onDrawOver(Canvas c, RecyclerView parent, State state) { onDrawOver(c, parent); } /** * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies * the number of pixels that the item view should be inset by, similar to padding or margin. * The default implementation sets the bounds of outRect to 0 and returns. * * <p> * If this ItemDecoration does not affect the positioning of item views, it should set * all four fields of <code>outRect</code> (left, top, right, bottom) to zero * before returning. * * <p> * If you need to access Adapter for additional data, you can call * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the * View. * * @param outRect Rect to receive the output. * @param view The child view to decorate * @param parent RecyclerView this ItemDecoration is decorating * @param state The current state of RecyclerView. */ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), parent); } }
以上是api中的说明,还有三个方法没列出来,但声明为deprecated,所以也就不列了。
public void onDraw(Canvas c,RecyclerView parent,State state)该函数为item绘制底部,该函数中的内容会在item绘制前先被绘制。
public void onDrawOver(Canvas c,RecyclerView parent,State state)该函数中的内容会在item绘制后再被绘制,可能会导致遮住item的一部分。
public void getItemOffSet(Rect outRect, View view, RecyclerView parent, State state)该函数指定了为item的周围留出多少的空白来绘制decoration。如果想要为Item四周各空出10px的距离,只要在该函数中添加该句:outRect.set(10,10,10,10); item周围留出的空白需要根据读者需要自行设置。
使用RecyclerView会发现,不能在xml中为其设置divider,导致显示起来不那么好看,那我们现在就可以用ItemDecoration来为其添加divider。
public class GridDividerItemDecoration extends RecyclerView.ItemDecoration { //获取系统的属性 private final int[] ATTRS = new int[]{android.R.attr.listDivider}; private Drawable mDivider; public GridDividerItemDecoration(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) { drawVertical(c, parent); drawHorizontal(c, parent); } public void drawVertical(Canvas c, RecyclerView parent) { int left, right, top, bottom; for (int i = 0; i < parent.getChildCount(); i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); left = child.getLeft() - params.leftMargin; top = child.getBottom() + params.bottomMargin; right = child.getRight() + params.rightMargin; bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public void drawHorizontal(Canvas c, RecyclerView parent) { int top, bottom, left, right; for (int i = 0; i < parent.getChildCount(); i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); left = child.getRight() + params.rightMargin; top = child.getTop() - params.topMargin; right = left + mDivider.getIntrinsicHeight(); bottom = child.getBottom() + params.bottomMargin; mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { //getIntrinsicHeight()和getIntrinsicWidth()获取drawable的高度和宽度 outRect.set(10, 10, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight()); }}这是实现的一个ItemDecoration,并添加在RecyclerView上。
ItemDecoration decoration = new GridDividerITemDecoration(this);rc.addItemDecoration(decoration);在该实现中,是为网格的RecyclerView绘制divider,画出四周的格子,所以只用在右边和底部画divider即可。其中使用了系统资源的divider,在getItemOffsets函数中设置了右边和底部的空白处,宽度为divider的宽(高)。在onDraw函数中先纵向绘制(绘制底部的divider),再横向绘制(绘制右边的divider)。
在onDraw函数中,传入的参数RecyclerView parent,parent代表的是一行的所有item的总和,所以在绘制时,需要去获取parent中的各个child,去获取left,top,bottom,right,该left,right,bottom,top代表的都是item本身,并不包括周围留白处,例如在绘制底部时,取出child的bottom作为divider绘制的顶部,再加上divider的高度,计算出divier绘制的底部即可。
ItemAnimator:
如果你想要为item添加增删的动画的话,就要重写该类,而google已经为我们提供了几个默认的itemAnimator,分别是DefaultItemAnimator。使用如下
rv.setItemAnimator(new DefaultItemAnimator())有人会推荐github中的一些关于ItemAnimator的项目,我就用了一个项目,RecyclerViewItemAnimators ,我试用了其中一个animator,是ScaleInOutAnimator,效果的确不错,但是存在一定的bug,在添加和删除item的时候,因为该动画是放大和缩小,所以在绘制时,发现有些item绘制错误,被缩小了,所以使用github上的一些ItemAnimator的时候要慎重。
给各位看下其他博客上的效果
ItemTouchHelper
该类为item增加了一些手势,包括拖拉和横向滑动,现在我们做一种效果,可以长按上下拖动item,改变item在RecyclerView中的位置。也可以横向滑动item,将其删除。
Google已经为我们写好了ItemTouchHelper,其构造函数中需要传入Callback作为参数,Callback是抽象类,需要我们重写其中的一些方法,来告诉ItemTouchHelper是否需要拖拉或者滑动的手势,如果需要,在不同的手势需要有怎么样的效果,这些都是Callback来实现的。
下面是一个例子
public interface ItemTouchHelperViewHolder { /** * Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped. * Implementations should update the item view to indicate it's active state. */ void onItemSelected(); /** * Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item * state should be cleared. */ void onItemClear();}
public interface ItemTouchHelperAdapter { /** * Called when an item has been dragged far enough to trigger a move. This is called every time * an item is shifted, and <strong>not</strong> at the end of a "drop" event.<br/> * <br/> * Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after * adjusting the underlying data to reflect this move. * * @param fromPosition The start position of the moved item. * @param toPosition Then resolved position of the moved item. * @return True if the item was moved to the new adapter position. * * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder) * @see RecyclerView.ViewHolder#getAdapterPosition() */ boolean onItemMove(int fromPosition, int toPosition); /** * Called when an item has been dismissed by a swipe.<br/> * <br/> * Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after * adjusting the underlying data to reflect this removal. * * @param position The position of the item dismissed. * * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder) * @see RecyclerView.ViewHolder#getAdapterPosition() */ void onItemDismiss(int position);}
public class RecyclerListAdapter extends RecyclerView.Adapter<RecyclerListAdapter.ItemViewHolder> implements ItemTouchHelperAdapter { private ArrayList<String> datas; public RecyclerListAdapter(ArrayList<String> data) { datas = data; } @Override public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_friend_item, parent, false); ItemViewHolder itemViewHolder = new ItemViewHolder(view); return itemViewHolder; } @Override public void onBindViewHolder(final ItemViewHolder holder, int position) { holder.tvName.setText(datas.get(position)); } @Override public void onItemDismiss(int position) { datas.remove(position); notifyItemRemoved(position); } @Override public boolean onItemMove(int fromPosition, int toPosition) { Collections.swap(datas, fromPosition, toPosition); notifyItemMoved(fromPosition, toPosition); return true; } @Override public int getItemCount() { return datas.size(); } /** * Simple example of a view holder that implements {@link ItemTouchHelperViewHolder} and has a * "handle" view that initiates a drag event when touched. */ public static class ItemViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder { public CardView mCardView; public TextView tvName; public ItemViewHolder(View itemView) { super(itemView); mCardView = (CardView) itemView.findViewById(R.id.card_view); tvName = (TextView) itemView.findViewById(R.id.tv_name); } @Override public void onItemSelected() { itemView.setBackgroundColor(Color.LTGRAY); } @Override public void onItemClear() { itemView.setBackgroundColor(0); } }}
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { public static final float ALPHA_FULL = 1.0f; private final ItemTouchHelperAdapter mAdapter; public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { mAdapter = adapter; } @Override public boolean isLongPressDragEnabled() { return true; } @Override public boolean isItemViewSwipeEnabled() { return true; } @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { // Set movement flags based on the layout manager if (recyclerView.getLayoutManager() instanceof GridLayoutManager) { final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; final int swipeFlags = 0; return makeMovementFlags(dragFlags, swipeFlags); } else { final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); } } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { if (source.getItemViewType() != target.getItemViewType()) { return false; } // Notify the adapter of the move mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) { // Notify the adapter of the dismissal mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); } @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { // Fade out the view as it is swiped out of the parent's bounds final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth(); viewHolder.itemView.setAlpha(alpha); viewHolder.itemView.setTranslationX(dX); } else { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } } @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { // We only want the active item to change if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { if (viewHolder instanceof ItemTouchHelperViewHolder) { // Let the view holder know that this item is being moved or dragged ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder; itemViewHolder.onItemSelected(); } } super.onSelectedChanged(viewHolder, actionState); } @Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); viewHolder.itemView.setAlpha(ALPHA_FULL); if (viewHolder instanceof ItemTouchHelperViewHolder) { // Tell the view holder it's time to restore the idle state ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder; itemViewHolder.onItemClear(); } }}首先先声明了两个接口,分别是ItemTouchHelperAdapter,该接口需要Adapter实现,并且Adapter集成自RecyclerView.Adapter,另一个接口是ItemTouchHelperViewHolder,由ViewHolder实现,并且ViewHolder需要集成自RecyclerView.ViewHolder。
ItemTouchHelperAdapter中两个函数
- onItemMove(int fromPosition, int toPosition):调用该函数告诉adapter在fromPosition的item将会移植到toPosition的位置,所以在adapter中在该方法中,首先需要更新数据集,交换该两个数据的位置,在调用notifyItemMoved(fromPosition,toPosition)函数告诉adapter更新视图。这里需要注意的是,并不是调用notifyDataSetChanged,还有其他类似的函数。
notifyItemInserted(int position);notifyItemChanged(int position);notifyItemRemoved(int position);notifyItemRangeChanged(int positionStart,int itemCount);notifyItemRangeInserted(int positionStart,int itemCount);notifyItemRangeRemoved(int positionStart,int itemCount);
- onItemDismiss(int position):调用该函数告诉Adapter在position位置的item被删除了,需要在数据集中删除该item,并调用notifyItemRemoved(position)。
- onItemSelected():当一个item在拖拉或者滑动被选中时,会调用该函数,告诉ViewHolder,如果想要在item被选中时需要什么效果,可以写在该函数中。在该例子中,当选中时,为ViewHolder中的itemView添加一个灰色的背景,表示被选中。
- onItemClear():当一个item被滑动结束或者拖拉结束的时候,会调用该函数,告诉ViewHolder,如果刚刚在onItemSelected函数中对item有任何绘制上的改变,则需要在该函数中恢复至原样。
- public boolean isLongPressDragEnabled():当该函数返回true的时候,则item可以在长按下被拖拉,如果返回false,则不可以。该函数默认的实现是返回true。
- public boolean isItemViewSwipeEnabled():当该函数返回true的时候,则item可以被滑动,如果返回false,则不可以。该函数默认的实现是返回true。
- public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder):该函数中你需要为手势指明可以移动的方向,主要是通过调用makeMovementsFlags(dragFlags,swipeFlags),在该例子中,如果LayoutManager是GridLayoutManager的话,允许上下左右拖拉,只能水平滑动。如果是其他LayoutManager的话,则只能上下拖拉,水平滑动,相信大家看代码就能看懂了。
- public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target):当ItemTouchHelper想要拖拉一个item从source到target的时候会调用该函数,在该函数中需要通知adapter更新数据集,并且调用adapter的notifyItemViewMove(fromPosition,toPosition)即可,该函数还需要返回boolean类型的值,如果返回true,则标志该item已经被移置正确的位置,如果返回false,则表明未移置正确的位置。
- public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction):当一个item被swipe的时候会调用该函数,第二个参数代表swipe最开始是从哪个方向滑动的,读者可以根据不同的方向来处理不同的操作,现在默认都是删除,需要告知adapter去更新数据集,并调用notifyItemViewRemoved(position)。
- onChildDraw:该函数在ItemTouchHelper的onDraw中会被调用到,如果你想在拖拉或者滑动时有任何的效果的话,可以在该函数中写,在该例子中,当在滑动时,会根据dx来不断改变item的透明度。
- onSelectedChanged:当一个item被选中时(即当前正在被拖拉和滑动时)会调用该函数,在该例子中,当item被选中时,会为其itemView增加一个灰色的背景。
- clearView:该一个item被选中结束后,手势已结束,动画也结束了,调用该函数,在该函数中需要恢复item原来的样子
ItemTouchHelper.Callback mCallback = new SimpleItemTouchHelperCallback(adapter);ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(mCallback);mItemTouchHelper.attachToRecyclerView(rv);
效果如下:录得不太好,最后几帧有点仓促
- android中RecyclerView
- android中使用RecyclerView
- Android中RecyclerView刷新
- Android中RecyclerView
- Android中RecyclerView用法
- Android中RecyclerView的使用
- android中RecyclerView的使用
- Android中RecyclerView的使用
- Android中快速入门RecyclerView
- android studio中导入RecyclerView
- Android中RecyclerView源码解析
- android中RecyclerView添加下划线
- 【Android】eclipse中使用RecyclerView
- Android中RecyclerView基础用法
- Android中RecyclerView嵌套RecyclerView或嵌套ListView
- Android中Recyclerview使用8----Recyclerview的嵌套
- Android中RecyclerView使用,RecyclerView-Item点击事件设置
- Android开发---Scrollerview中嵌套RecyclerView RecyclerView显示不全问题
- DirectShow的中文资料之设备列举和捕捉接口
- Extjs 控件属性大全
- iOS 无线滚动相册之scrollView
- 学Android---Manifest.xml
- Java线程:概念与原理
- android中RecyclerView
- 关于java中的过滤器
- android4.0 USB Camera实例(六)ffmpeg mpeg编码
- 栈应用1:算术表达式求值
- session-timer
- 如何在Android手机上退出Google帐号
- ReactiveCocoa - iOS开发的新框架
- CentOS 6.3 下安装配置GO 1.2.1
- Unity3D之在Scene窗口显示Waypoint路径