Android RecyclerView

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);
        }
    }
}

上图:Android RecyclerView_第1张图片

  • 下拉刷新和上拉加载更多
    利用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封装上拉加载更多,网上很多人写了。百度。。。
Android RecyclerView_第2张图片

  • 头部尾部问题
    关于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)