RecyclerView

RecyclerView 可以说是一个增强版的ListView,相对于ListView,RecyclerView已经实现了对view的回收与复用,我们可以完全自由定制。
如果想定制一款自己的RecyclerView需要掌握5点:

LayoutManager
Adapter
ItemAnimator
ItemDecoration
OnItemClickListener


LayoutManager

RecyclerView 有三种样式,如图所示:

LinearLayoutManager
GridLayoutManager
StaggeredGridLayoutManager

我们通过设定布局管理器来指定RecyclerView的样式,注意:必须指定其中一种RecyclerView才能显示,代码如下:

    mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
    //类似于ListView,item竖直排列
    //LinearLayoutManager manager = new LinearLayoutManager(this);
    //类似于GridView,参数二:指定列数
    //LinearLayoutManager manager = new GridLayoutManager(this,2);
    //瀑布流布局,参数一:指定列数或者行数,参数二:指定排列方向(竖直或者水平排列)
    StaggeredGridLayoutManager manager = new     StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
    mRecyclerView.setLayoutManager(manager);

Adapter

直接上代码,相应解释会写在注释中:

//继承Adapter 时填的泛型是自己创建的内部类Holder
public class RAdapter extends RecyclerView.Adapter {


    private List mResultsBeen;
    private Context mContext;

    public RAdapter(Context context) {
        mResultsBeen = new ArrayList();
        this.mContext = context;
    }

    public void setResultsBeen(RBeans.ResultsBean resultsBeen) {
        mResultsBeen.add(resultsBeen);
        notifyDataSetChanged();
    }

//该方法用于创建一个item布局填充到参数一所示的parent中,并将该view作为参数传入Holder构造,然后返回这个holder对象给onBindViewHolder()中,
//参数二表示布局类型,一般用于多布局
    @Override
    public RHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.item, parent, false);
        RHolder rHolder = new RHolder(view);
        return rHolder;
    }

//该方法用将holder对象和数据源绑定
    @Override
    public void onBindViewHolder(RHolder holder, int position) {
        Glide.with(mContext)
                .load(mResultsBeen.get(position).getUrl())
                .error(R.mipmap.ic_launcher)
                .placeholder(R.mipmap.ic_launcher)
                .into(holder.image);
    }

//返回该RecyclerView的item数量
    @Override
    public int getItemCount() {
        return mResultsBeen.size();
    }

    class RHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.image)
        ImageView image;

        public RHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this,itemView);
        }
    }
}

ItemAnimator

ItemAnimator是一个抽象类,系统为我们提供了一种默认的实现类,用于当Item添加和移除的时的动画效果;
首先在代码中:

mRecyclerView.setItemAnimator(new DefaultItemAnimator());

然后Adapter中更新数据就不要用adapter.notifyDataSetChanged(),而应该是
notifyItemInserted(position)与notifyItemRemoved(position) 否则没有动画效果。

public void addData(int position) {
        mResultsBeen.add("new");
        //只更新集合中position位置的数据
        notifyItemInserted(position);
    }

public void addData(int position) {
        mResultsBeen.addAll(mList);
        //更新集合中0~mList.size()范围的数据,
        notifyItemRangeInserted(0,mList.size());
    }

效果如下:

ItemAnimator

更多动画效果推荐 GitHub:gabrielemariotti/RecyclerViewItemAnimators


ItemDecoration

  • getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)

    参数outRect 设置的4个方向的值,会被计入了 RecyclerView 每个 item view 的 padding 中(内嵌偏移)。

  • onDraw(Canvas c, RecyclerView parent, State state)

    该onDraw()会先于ItemView的onDraw()调用,所以如果在onDraw()方法中绘制的东西出现在ItemView显示区域,就会被ItemView盖住

  • onDrawOver(Canvas c, RecyclerView parent, State state)

    该onDrawOver()会在ItemView的onDraw()之后调用,所以在onDrawOver()方法中绘制的东西如果出现在ItemView显示区域,就会盖住ItemView内容。

顺序:就是先执行ItemDecoration的onDraw()、再执行ItemView的onDraw()、再执行ItemDecoration的onDrawOver()。

官方示例:DividerItemDecoration

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

分割线的样式是系统默认的,在styles的.xml文件中可以进行更改,

      
        ...
        @drawable/itemDivider   
    

itemDivider文件内容如下:

  
  

          
         

        
        

效果图:

itemDivider

OnItemClickListener

RecyclerView没有item的OnClick事件,依旧需要我们自定义:

首先在Adapter中声明一个内部接口,

     interface OnItemClickListener {
        void onClick();
    }

然后在Adapter中创建该接口的对象,并设置set()方法,

    private OnItemClickListener mOnItemClickListener;

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
    }

再然后在内部类ViewHolder中给itemView设置点击事件,

        public RHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mOnItemClickListener.onClick();
                }
            });
        }

最后在Activity或者Fragment中set一个匿名对象,并且在回调的方法中进行具体操作

        mRAdapter.setOnItemClickListener(new RAdapter.OnItemClickListener() {
            @Override
            public void onClick() {
                ...
            }
        });
IT文库 » RecyclerView
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址