本篇博文主要给大家分享关于RecyclerView控件的使用及通过继承RecyclerView来实现滑动时加载图片的优化方案,也同样能解决防止图片乱序的问题,之前有在网上有看到大神对Android中ListView异步加载图片乱序问题进行过分析,并深入剖析原理后分别给出了3种对应的解决方案:一 、使用findViewWithTag。二、使用弱引用关联。三、使用ImageLoad框架进行处理。
RecyclerView的优点是什么?
根据官方的介绍RecylerView是ListView的升级版,既然如此那RecylerView必然有它的优点,现就RecylerView相对于ListView的优点罗列如下:
①RecylerView封装了viewholder的回收复用,也就是说RecylerView标准化了ViewHolder,编写Adapter面向的是ViewHolder而不再是View了,复用的 逻辑被封装了,写起来更加简单。
②提供了一种插拔式的体验,高度的解耦,异常的灵活,针对一个Item的显示RecylerView专门抽取出了相应的类,来控制Item的显示,使其的扩展性非常强。
例如:setLayoutManager(),该方法参数就是设置不同的排列样式,你想控制横向或者纵向滑动列表效果可以通过LinearLayoutManager这个类来进行控制(与GridView效果对应的是GridLayoutManager,与瀑布流对应的还有StaggeredGridLayoutManager等),也就是说RecylerView不再拘泥于ListView的线性展示方式,它也可以实现GridView的效果等多种效果。你想控制Item的分隔线,可以通过继承RecylerView的ItemDecoration这个类,然后针对自己的业务需求去抒写代码。
③可以控制Item增删的动画,可以通过ItemAnimator这个类进行控制,当然针对增删的动画,RecylerView有其自己默认的实现。
现在给大家讲解RecyclerView的使用和步骤:
首先是Android Studio依赖:
compile 'com.android.support:recyclerview-v7:24.2.1' ,
添加分割线的依赖:
compile 'com.dinuscxj:recycleritemdecoration:1.0.0',
其次,在.xml中添加布局:
接下来就是对Activity的操作了,也是最主要的代码:
下面是Activity的代码如下:
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import com.daimajia.swipe.util.Attributes;
import com.wjf.cool.app.recyclerview.adapter.RecyclerViewAdapter;
import com.wjf.cool.app.ui.R;
import java.util.ArrayList;
import java.util.List;
public class RecyclerViewActivity extends AppCompatActivity {
RecyclerView recyclerView;
private RecyclerViewAdapter mAdapter;
private List list;//添加item
private String[] data={"北京","上海","广州","深圳","青海","合肥","宿州","苏州","盐城","南海",
"南京","毕加索","美国","天津","湖南","浙江","内蒙古","爱迪生","爱琴海",
"泗洪","海南","哈尔滨","淮安","黑龙江","丽江",};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_view);
recyclerView= (RecyclerView) findViewById(R.id.recyclerView);
initData();//方法
mAdapter=new RecyclerViewAdapter(this,list);
mAdapter.setMode(Attributes.Mode.Single);
recyclerView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
//设置布局管理器(布局风格)
recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
//设置item增加 删除动画
recyclerView.setItemAnimator(new DefaultItemAnimator());
//添加分割线(需要依赖recycleritemdecoration第三方库)
//recyclerView.addItemDecoration(new LinearDividerItemDecoration(this,4));
//recyclerView.setItemAnimator(new DefaultItemAnimator());
//给适配器设置监听
mAdapter.setNewOnItemClickListener(listener);
//设置侧滑事件监听
recyclerView.setOnScrollListener(onScrollListener);
}
private void initData(){
list=new ArrayList<>();
for (int i=0;i
二:给RecylerView设置适配器:
可以看到对RecylerView的设置过程,比ListView要复杂一些,这也是RecylerView高度解耦的表现,虽然代码抒写上有点复杂,但它的扩展性是极高的。
在了解了RecyclerView的一些控制之后,紧接着来看看它的Adapter的写法,RecyclerView的Adapter与ListView的Adapter还是有点区别的,RecyclerView.Adapter,需要实现3个方法:
①onCreateViewHolder()
这个方法主要生成为每个Item inflater出一个View,但是该方法返回的是一个ViewHolder。该方法把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例,当然这个ViewHolder需要我们自己去编写。直接省去了当初的convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。
②onBindViewHolder()
这个方法主要用于适配渲染数据到View中。方法提供给你了一个viewHolder,而不是原来的convertView。
③getItemCount()
这个方法就类似于BaseAdapter的getCount方法了,即总共有多少个条目。
下面是适配器Adapter的代码:
/**
* Created by Administrator on 2016/11/29.
*
* 实现RecyclerView适配器:
* 1.先创建自定义ViewHolder的内部类继承ViewHolder
* 2.自定义RecyclerView适配器继承系统的适配器:泛型为自定义的内部类ViewHolder
*/
public class RecyclerViewAdapter extends RecyclerSwipeAdapter {
private LayoutInflater layoutInflater;
private Context context;
private List list;
protected SwipeItemRecyclerMangerImpl mItemManger = new SwipeItemRecyclerMangerImpl(this);
public RecyclerViewAdapter(Context context, List list) {
this.list = list;
this.context = context;
layoutInflater = LayoutInflater.from(context);
}
//添加item
public void addData(int pos) {
list.add(pos, "Insert One");
//更新,不是notifyDataSetChanged();
notifyItemChanged(pos);
}
//删除
public void delectData(int pos) {
list.remove(pos);
//更新删除,不是notifyDataSetChanged();
notifyItemRemoved(pos);
}
//onCreateViewHolder+onBindViewHolder这两个方法其实就是ListView中的getView方法,只是分开定义了
//创建ViewHolder
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemview = layoutInflater.inflate(R.layout.item_recycler_view, parent, false);
MyViewHolder viewHolder = new MyViewHolder(itemview);
return viewHolder;
}
//绑定ViewHolder(操作item)
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.swipeLayout.setShowMode(SwipeLayout.ShowMode.LayDown);
//设置侧滑方向 默认向左滑
holder.swipeLayout.addDrag(SwipeLayout.DragEdge.Left, holder.swipeLayout.findViewById(R.id.bottom_wrapper_1));
// holder.swipeLayout.addSwipeListener(new SimpleSwipeListener() {
// @Override
// public void onOpen(SwipeLayout layout) {
// YoYo.with(Techniques.Tada).duration(5000).delay(1000).playOn(layout.findViewById(R.id.img_delete));
// }
// });
//item左侧滑动监听(删除)
holder.imgDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mItemManger.removeShownLayouts(holder.swipeLayout);
list.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, list.size());
mItemManger.closeAllItems();//关闭侧滑菜单
Toast.makeText(view.getContext(), "删除: " + holder.tvTitle.getText().toString() + "!", Toast.LENGTH_SHORT).show();
}
});
//设置控件内容
holder.tvTitle.setText((position + 1) + ". "+list.get(position));
mItemManger.bindView(holder.itemView, position);
if (listener != null) {
//给item实体设置监听(或给对象里面的控件设置监听,看自己需要设置那个控件 )
//点击监听
holder.tvTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (holder.swipeLayout != null) {
mItemManger.closeAllItems();//判断点击item是关闭侧滑
}
listener.onNewItemClick(v, position);
}
});
//长按监听
holder.tvTitle.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mItemManger != null) {
mItemManger.closeAllItems();//判断点击item是关闭侧滑
}
listener.OnNewItemLongClick(v, position);
return true;
}
});
}
}
@Override
public int getItemCount() {
return list.size();
}
//侧滑重写方法
@Override
public int getSwipeLayoutResourceId(int position) {
return R.id.swipe;
}
//创建自定义item布局类优化
class MyViewHolder extends RecyclerView.ViewHolder {
SwipeLayout swipeLayout;
LinearLayout linLayTitle;
TextView tvTitle;
ImageView imgDelete;//删除
ImageView imgCollect;//收藏(未对此操作)
public MyViewHolder(View itemView) {
super(itemView);
swipeLayout = (SwipeLayout) itemView.findViewById(R.id.swipe);
linLayTitle = (LinearLayout) itemView.findViewById(R.id.linearLoyout_title);
tvTitle = (TextView) itemView.findViewById(R.id.tv_reclyer_title);
imgDelete = (ImageView) itemView.findViewById(R.id.img_delete);
imgCollect = (ImageView) itemView.findViewById(R.id.img_collect);
//
// itemView.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View view) {
// Toast.makeText(view.getContext(), "onItemSelected: " + tvTitle.getText().toString(), Toast.LENGTH_SHORT).show();
// }
// });
}
}
/**
* Recycler的适配器中没有Item的监听方法,因此需要自己定义
* 监听接口去实现监听效果
*/
//点击监听接口
public interface OnNewItemClickListener {
//点击时的方法
void onNewItemClick(View view, int postion);
//长按时的方法
void OnNewItemLongClick(View view, int postion);
}
//声明监听接口对象
public OnNewItemClickListener listener;
//对外提供一个监听方法
public void setNewOnItemClickListener(OnNewItemClickListener listener) {
this.listener = listener;
}
}
需要注意的是!!!:
一、RecyclerView瀑布流(StaggeredGridLayoutManager)的实现也很简单,给定一个集合设置随机的高度;在适配器RecyclerView.Adapter中的onBindViewHolder()中设置。
代码如下:
public StaggeredAdapter(Context context, List lists) {
this.context = context;
this.lists = lists;
getRandomHeight(this.lists);
//设置随机高度
getRandomHeight(this.lists);
}
//得到随机item的高度
private void getRandomHeight(List lists){//得到随机item的高度
heights = new ArrayList<>();
for (int i = 0; i < lists.size(); i++) {
heights.add((int)(200+Math.random()*400));
}
}
//绑定ViewHolder
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
//设置随机高度
ViewGroup.LayoutParams params = holder.itemView.getLayoutParams();//得到item的LayoutParams布局参数
params.height = heights.get(position);//把随机的高度赋予item布局
holder.itemView.setLayoutParams(params);//把params设置给item布局
holder.mTv.setText(lists.get(position));//为控件绑定数据
if(mListener!=null){//如果设置了监听那么它就不为空,然后回调相应的方法
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos = holder.getLayoutPosition();//得到当前点击item的位置pos
mListener.ItemClickListener(holder.itemView,pos);//把事件交给我们实现的接口那里处理
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int pos = holder.getLayoutPosition();//得到当前点击item的位置pos
mListener.ItemLongClickListener(holder.itemView,pos);//把事件交给我们实现的接口那里处理
return true;
}
});
}
}
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));
这里需要注意的是:StaggeredGridLayoutManager构造的第二个参数传一个orientation,如果传入的是StaggeredGridLayoutManager.VERTICAL那么前面那个参数就代表有多少列;如果传是StaggeredGridLayoutManager.HORIZONTAL那么前面那个参数就代表有多少行。
RecyclerView.LayoutManager是一个抽象类,系统为我们提供了三个实现类。
①LinearLayoutManager即线性布局,这个是在上面的例子中我们用到的布局。
②GridLayoutManager即表格布局。
③StaggeredGridLayoutManager即流式布局,如瀑布流效果。
二、RecycleView增加和删除Item的动画
在上面也提到了控制RecyclerView增加和删除的动画是通过ItemAnimator这个类来实现的,ItemAnimator这类也是个抽象的类,系统默认给我们提供了一种增加和删除的动画,下面我们就来看看这种动画的效果,我们需要做的修改如下,在适配器中自定义增加和删除的两个方法:
//添加item
public void addData(int pos) {
list.add(pos, "Insert One");
//更新,不是notifyDataSetChanged();
notifyItemChanged(pos);
notifyItemInserted(pos);
notifyItemRangeChanged(pos, list.size());
}
//删除
public void delectData(int pos) {
list.remove(pos);
//更新删除,不是notifyDataSetChanged();
notifyItemRemoved(pos);
notifyItemRangeChanged(pos, list.size());
}
之后在Activity中添加监听点击调用即可,这里我就不给大家写代码了。
public final void notifyDataSetChanged()
public final void notifyItemChanged(int position)
public final void notifyItemRangeChanged(int positionStart, int itemCount)
public final void notifyItemInserted(int position)
public final void notifyItemMoved(int fromPosition, int toPosition)
public final void notifyItemRangeInserted(int positionStart, int itemCount)
public final void notifyItemRemoved(int position)
public final void notifyItemRangeRemoved(int positionStart, int itemCount)
notifyDataSetChanged():这个方法跟我们平时用到的ListView的Adapter的方法一样,这里就不多做描述了。
notifyItemChanged(int position):当position位置的数据发生了改变时就会调用这个方法,就会回调对应position的onBindViewHolder()方法了,当然,因为ViewHolder是复用的,所以如果position在当前屏幕以外,也就不会回调了,因为没有意义,下次position滚动会当前屏幕以内的时候同样会调用onBindViewHolder()方法刷新数据了。其他的方法也是同样的道理。notifyItemRangeChanged(int positionStart, int itemCount):顾名思义,可以刷新从positionStart开始itemCount数量的item了(这里的刷新指回调onBindViewHolder()方法)。
notifyItemInserted(int position):这个方法是在第position位置被插入了一条数据的时候可以使用这个方法刷新,注意这个方法调用后会有插入的动画,这个动画可以使用默认的,也可以自己定义。
notifyItemMoved(int fromPosition, int toPosition):这个方法是从fromPosition移动到toPosition为止的时候可以使用这个方法刷新。
notifyItemRangeInserted(int positionStart, int itemCount):显然是批量添加。
notifyItemRemoved(int position):第position个被删除的时候刷新,同样会有动画。
将上述更改运行,点击添加和删除按钮效果图如下:
notifyItemRangeRemoved(int positionStart, int itemCount):批量删除。
三、 RecyclerView增加分隔线样式:
前面我们说到可以通过RecyclerView.addItemDecoration(ItemDecoration decoration)这个方法进行设置,其中它需要的参数就是我们自己定义的继承自ItemDecoration的一个对象。我们可以创建一个继承RecyclerView.ItemDecoration类来绘制分隔线,通过ItemDecoration可以让我们每一个Item从视觉上面相互分开来,例如ListView的divider非常相似的效果。当然像我们上面的例子ItemDecoration我们没有设置也没有报错,那说明ItemDecoration我们并不是强制需要使用,作为我们开发者可以设置或者不设置Decoration的。实现一个ItemDecoration,系统提供的ItemDecoration是一个抽象类,内部除去已经废弃的方法以外,我们主要实现以下三个方法:
public static abstract class ItemDecoration {
public void onDraw(Canvas c,RecyclerView parent,State state) {
onDraw(c,parent);
}
public void onDrawOver(Canvas c,RecyclerView parent,State state) {
onDrawOver(c,parent);
}
public void getItemOffsets(RectoutRect, View view,RecyclerView parent,State state) {
getItemOffsets(outRect,((LayoutParams)view.getLayoutParams()).getViewLayoutPosition(),parent);
}
}
然而因为当我们RecyclerView在进行绘制的时候会进行绘制Decoration,那么会去调用onDraw和onDrawOver方法,那么这边我们其实只要去重写onDraw和getItemOffsets这两个方法就可以实现啦。然后LayoutManager会进行Item布局的时候,会去调用getItemOffset方法来计算每个Item的Decoration合适的尺寸,下面我们来具体实现一个Decoration,DividerListItemDecoration.Java:
mport 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 com.wjf.cool.app.ui.R;
/**
* Created by 王建法 on 2017/3/9.
* 列表分割线
*/
public class DividerLineItemDecoration 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 DividerLineItemDecoration(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) {
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);
}
}
}
这里我们采用系统主题(android.R.attr.listDivider)来设置成分隔线的,然后来获取尺寸,位置进行setBound(),绘制,接着通过outRect.set()来设置绘制整个区域范围,当然了它是有两种情况的一种LinearLayoutManager.HORIZONTAL另外一种LinearLayoutManager.VERTICAL需要分别对其进行处理,最后不要忘记往RecyclerView中设置该自定义的分割线,然后在MainActivity中加上一句recyclerView .addItemDecoration(new DividerListItemDecoration(MainActivity.this,LinearLayoutManager.VERTICAL))即给RecyclerView增加分隔线,效果如下:
上面的代码只适合listView那样的列表样式,而当展示成GridView那样的效果时,每一行就不止一个条目了,而有可能是多个,所以这个类就不再适用了,我们需要重新写一个添加分割线类。
代码如下:
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.StaggeredGridLayoutManager;
import android.view.View;
/**
* Created by 王建法 on 2017/3/9.
*
* 表格分割线
*/
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());
}
}
}
其它没有什么需改动的,最后不要忘记往RecyclerView中设置该自定义的分割线,然后在MainActivity中加上一句recyclerView.addItemDecoration(new DividerGridItemDecoration(StaggeredGridLayoutActivity.this));即给RecyclerView增加分隔线,效果如下:
可以看到已经有了分隔线,跟ListView的效果基本一致了。当然了,既然谷歌给我们提供了这个专门添加分隔线的方法,那它肯定会允许我们自定义分隔线的样式,那么如何自定义分割线的样式呢?请看下面。
1、改变分隔线样式
在上面的DividerItemDecoration这个类中可以看到这个分隔线是跟ListView一样的,即系统的默认的样式,因此我们可以在styles的xml文件中进行更改,更改如下:
divideritem代码如下:
修改分割线样式之后的效果图如下:
四、 给RecyclerView的Item添加点击事件
到这里还有一点从文章开头到现在我们都没有提及,就是Item的点击事件RecyclerView监听事件处理在ListView使用的时候,该控件给我们提供一个onItemClickListener监听器,这样当我们点击Item的时候,会回调相关的方法,以便我们方便处理Item点击事件。对于RecyclerView来讲,非常可惜的是,该控件没有给我们提供这样的内置监听器方法,不过我们可以进行改造实现,可以这样实现Item的点击事件的监听,在我们的adapter中增加这两个方法:
/**
* Recycler的适配器中没有Item的监听方法,因此需要自己定义
* 监听接口去实现监听效果
*/
//点击监听接口
public interface OnNewItemClickListener {
//点击时的方法
void onNewItemClick(View view, int postion);
//长按时的方法
void OnNewItemLongClick(View view, int postion);
}
//声明监听接口对象
public OnNewItemClickListener listener;
//对外提供一个监听方法
public void setNewOnItemClickListener(OnNewItemClickListener listener) {
this.listener = listener;
}
然后onBindViewHolder方法要做如下更改:
//绑定ViewHolder(操作item)
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
//设置控件内容
holder.tvTitle.setText((position + 1) + ". "+list.get(position));
mItemManger.bindView(holder.itemView, position);
if (listener != null) {
//给item实体设置监听(或给对象里面的控件设置监听,看自己需要设置那个控件 )
//点击监听
holder.tvTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (holder.swipeLayout != null) {
mItemManger.closeAllItems();//判断点击item是关闭侧滑
}
listener.onNewItemClick(v, position);
}
});
//长按监听
holder.tvTitle.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mItemManger != null) {
mItemManger.closeAllItems();//判断点击item是关闭侧滑
}
listener.OnNewItemLongClick(v, position);
return true;
}
});
}
}
最后在MainAcitivity中增加如下代码:
//给适配器设置监听
RecyclerViewAdapter.OnNewItemClickListener listener=new RecyclerViewAdapter.OnNewItemClickListener() {
@Override
public void onNewItemClick(View view, int postion) {
if (onScrollListener !=null){
}
//实现效果
Toast.makeText(RecyclerViewActivity.this, "点击了" + postion, Toast.LENGTH_SHORT).show();
}
@Override
public void OnNewItemLongClick(View view, int postion) {
Toast.makeText(RecyclerViewActivity.this, "长按了" + postion, Toast.LENGTH_SHORT).show();
}
};
运行效果如下:
可以看到Item的onClick和onLongClick事件都触发了。到此关于RecyclerView的基本用法就介绍的差不多了,当然,还有几个点没有提到,比方说瀑布流、下拉刷新、上拉加载等,之后会给大家一一介绍!!!
大家需要什么样的功能和需求布局样式,自行改动上面的代码就OK了!!!