您的位置:首页 > 移动开发 > Android开发

Android RecyclerView

2015-10-09 20:14 591 查看
RecyclerView作为升级版的ListView和GridView,更加的先进和灵活。接下来就介绍下RecyclerView的用法。

首先,在gradle脚本中添加,

compile 'com.android.support:recyclerview-v7:23.0.1'


在布局中引用

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>

</RelativeLayout>


RecyclerView是没有divider属性的。

Adapter的编写,这里的Adapter应该继承public static abstract class Adapter {},可以看到,这里内部就有一个ViewHolder,我们只需要实现自己的ViewHolder就好,我们必须要实现Adapter的3个方法:

onCreateViewHolder 创建holder

onBindViewHolder 绑定holder

getItemCount 得到view的数目

最终的代码我会在后面给出。

设置分割线

recyclerView.addItemDecoration(new DividerItemDecoration(MainActivity.this, DividerItemDecoration.VERTICAL_LIST));


我们通过addItemDecoration来添加分割线,DividerItemDecoration这个类就是实现分割线的。

这个类我是抄网上的。。。

package gl.com.as;

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;

/**
* Created by mac on 15-10-9.
*/
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 orienttation){
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orienttation);
}

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, RecyclerView.State state) {

if (mOrientation==VERTICAL_LIST){
drawVertival(c,parent);
}else{
drawHorizontal(c,parent);
}
}

/**
* draw vertival line
* @param c
* @param parent
*/
public void drawVertival(Canvas c,RecyclerView parent){
final int left = parent.getPaddingLeft();
final int right = 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,bottom,right);
mDivider.draw(c);
}
}

/**
* draw horizaontal line
* @param c
* @param parent
*/
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.getIntrinsicWidth();
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);
}
}
}


上面的类就实现了横 竖2中分割线,想实现其他样式的参考张鸿洋

LayoutManager

这里有3种:

1.LinearLayoutManager(..) listview风格

2.GridLayoutManager(..) GridView

3.StaggeredGridLayoutManager(..) 同样可以实现gridview,还可以实现瀑布流,只要设置好高度就行。

添加增加删除动画

recyclerView.setItemAnimator(new DefaultItemAnimator());


这是系统默认的动画,我们当然也可以定制自己的动画啦。具体实现参考DefaultItemAnimator类的实现,不过github上 有很多牛人已经做了很多了。小伙伴们可以去github上找找。Github上的动画

监听器的实现

RecyclerView没有提供设置监听器的方法 ,不过没关系。我们可以实现自己的回调接口

public interface OnItemClickListener {
void onClick(int pos);
void onLongClick(int pos);
}

private OnItemClickListener listener;
public void setOnclickListener(OnItemClickListener listener){
this.listener=listener;
}
//然后在onBindViewHolder中添加
if (listener!=null){
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos=holder.getLayoutPosition();
listener.onClick(pos);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int pos = holder.getLayoutPosition();
listener.onLongClick(pos);
return false;
}
});
}


接下来,在Activity中

mAdapter.setOnclickListener(new RecyclerViewAdapter.OnItemClickListener() {
@Override
public void onClick(int pos) {
Toast.makeText(MainActivity.this,pos+"click",Toast.LENGTH_SHORT).show();
}

@Override
public void onLongClick(int pos) {
Toast.makeText(MainActivity.this,pos+"long click",Toast.LENGTH_SHORT).show();
}
});


多布局的实现

重写getItemViewType(int pos)方法 ,onCreateViewHolder(ViewGroup parent, int viewType),第二个参数就position对应的type了,我们只需要根据viewType返回不同的viewholder即可。

下面是Adapter的完整代码

package gl.com.as;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
* Created by mac on 15-10-9.
*/
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>{

private Context context;
private List<String> mDatas;
private List<Integer> mHeight;

public RecyclerViewAdapter(Context context,List<String> mDatas){
this.context=context;
this.mDatas=mDatas;
mHeight = new ArrayList<Integer>();
for (int i =0;i<mDatas.size();i++){
mHeight.add((int) (100+Math.random()*300));
}
}
public interface OnItemClickListener {
void onClick(int pos);
void onLongClick(int pos);
}

private OnItemClickListener listener;

@Override
public int getItemViewType(int position) {
if (position%2==0){
return 0;
}else{
return 1;
}

}

public void setOnclickListener(OnItemClickListener listener){
this.listener=listener;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ViewHolder holder=null;
Log.e("tag","this is on onCreateViewHolder"+viewType);
switch (viewType){
case 0:
holder = new ViewHolder(LayoutInflater.from(context).inflate(R.layout.rccyclerview_item,parent,false));
break;
default:
holder = new ViewHolder(LayoutInflater.from(context).inflate(R.layout.rccyclerview_item2,parent,false));
break;
}
return holder;
}

@Override
public void onBindViewHolder(final ViewHolder holder, int position) {

ViewGroup.LayoutParams lp = holder.textView.getLayoutParams();
lp.height=mHeight.get(position);
holder.textView.setLayoutParams(lp);
holder.textView.setText(mDatas.get(position));
if (listener!=null){
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos=holder.getLayoutPosition();
listener.onClick(pos);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int pos = holder.getLayoutPosition();
listener.onLongClick(pos);
return false;
}
});
}
}

@Override
public int getItemCount() {
return mDatas.size();
}

public void addData(int position){
mDatas.add(position,"Insert One");
notifyItemInserted(position);
}

public void removeData(int position){
mDatas.remove(position);
notifyItemRemoved(position);
}

class ViewHolder extends RecyclerView.ViewHolder {
private TextView textView;

public ViewHolder(View itemView) {
super(itemView);
textView= (TextView) itemView.findViewById(R.id.id_text);
}
}
}


上图:


下拉刷新和上拉加载更多

利用SwipeRefreshLayout,因为SwipeRefreshLayout没有上拉加载更多,所以我这里给出大概思路。

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/image"
>

<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:divider="#dddd0000"
android:dividerHeight="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</android.support.v4.widget.SwipeRefreshLayout>
<ImageView
android:id="@+id/image"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@mipmap/ic_launcher"
android:visibility="gone"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>


其实这里用FrameLayout更好一点,我这里为了省事。下拉刷新实现SwipeRefreshLayout.OnRefreshListener接口就好。上拉刷新的话

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int lastVisiableItem = ((LinearLayoutManager)manager) .findLastVisibleItemPosition();
if (lastVisiableItem+1==mDatas.size()){
image.setVisibility(View.VISIBLE);
//do something
}
}
});


这里是LinearLayoutManager,其他2个的话做相应的逻辑处理。关于SwipeRefreshLayout封装上拉加载更多,网上很多人写了。百度。。。



头部尾部问题

关于Recycler添加头部尾部问题是在蛋疼。不过好在有ListView,我们可以参考ListView的实现方法来实现。

以下为ListView的部分源码,以添加headview为例:

private ArrayList<FixedViewInfo> mHeaderViewInfos = Lists.newArrayList();
private ArrayList<FixedViewInfo> mFooterViewInfos = Lists.newArrayList();


public void addHeaderView(View v, Object data, boolean isSelectable) {
final FixedViewInfo info = new FixedViewInfo();
info.view = v;
info.data = data;
info.isSelectable = isSelectable;
mHeaderViewInfos.add(info);
mAreAllItemsSelectable &= isSelectable;

// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewListAdapter)) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}

// In the case of re-adding a header view, or adding one later on,
// we need to notify the observer.
if (mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
}


关键就在于HeaderViewListAdapter。根据HeaderViewListAdapter的代码依葫芦画瓢就行了。小弟在这里就不献丑了。给出参考资料,去看这位大神的代码吧。添加头部尾部

好累,到这里就完了。

参考资料:添加头尾

参考资料:张鸿洋
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android RecyclerVi