Materail Design 入门(十)—— RecyclerView的使用(一)

墨迹了这么久终于写到了Material Design系列的最后一篇了。这篇RecyclerView的使用仅作是知识的回顾吧。本章节我们一起来复习下Recyclerview布局的设置(竖向列表,横向列表,竖向网格列表,横向网格列表,瀑布流),添加分割线,添加ItemClick事件,下拉刷新,上拉加载等功能。

RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好。

1、xml布局

  <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/light_grey" />

2、Adapter的创建

Adapter:使用RecyclerView之前,你需要一个继承自RecyclerView.Adapter的适配器,作用是将数据与每一个item的界面进行绑定。

public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
    private Context context;
    private final int mBackground;
    private List<Story> mDataset;

    private final TypedValue mTypedValue = new TypedValue();

    public class ViewHolder extends RecyclerView.ViewHolder{
        public TextView newsTitleTV;
        public ImageView newsIV;

        public ViewHolder(View v) {
            super(v);
            newsTitleTV = (TextView) v.findViewById(R.id.news_title);
            newsIV = (ImageView) v.findViewById(R.id.news_image);
        }
    }

    public NewsAdapter(Context context, List<Story> myDataset) {
        this.mDataset = myDataset;
        context.getTheme().resolveAttribute(R.attr.selectableItemBackground, mTypedValue, true);
        mBackground = mTypedValue.resourceId;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_view, parent, false);
//        v.setBackgroundResource(mBackground);
        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Story story = mDataset.get(position);
            holder.newsTitleTV.setText(mDataset.get(position).getTitle());
        Glide.clear(holder.newsIV);
        Glide.with(holder.newsIV.getContext())
                .load(story.getImages().get(0))
                .fitCenter()
                .into(holder.newsIV);
    }

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

    public Story getItem(int position){
        return mDataset.get(position);
    }

    public void updateData(List<Story> stories) {
        mDataset.clear();
        mDataset.addAll(stories);
        notifyDataSetChanged();
    }

    public void addData(List<Story> stories){
        mDataset.addAll(stories);
        notifyDataSetChanged();
    }
}

这里记住两点:
Recyclerview的Adapter继承RecyclerView.Adapter;
ViewHolder继承RecyclerView.ViewHolder;

3、设置布局管理器,分割线,加载动画

mRecyclerView = (RecyclerView)findViewById(R.id.recyclerView);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
//mRecyclerView.addItemDecoration(newDividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST).setmDivider(getResources().getDrawable(R.drawable.md_transparent)));
mRecyclerView.addItemDecoration(new DividerOffsetDecoration());
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
// 设置固定大小
mRecyclerView.setHasFixedSize(true);
NewsAdapter mAdapter = new NewsAdapter(this, myDataset);
mRecyclerView.setAdapter(mAdapter);

setLayoutManager:设置RecyclerView的布局,这里RecyclerView是一个竖向滚动列表,其他布局后面会介绍;

addItemDecoration:设置RecyclerView的布局的分隔线,RecyclerView不向ListView和GridView 可以在xml布局中设置行高,分割线,间距,只能在Java文件中设置;

  • addItemDecoration(RecyclerView.ItemDecoration decor),这个方法接受一个ItemDecoration对象,网上有许多写好的列子,可以直接拿来用,也可以自定义一个ItemDecoration,只需继承RecyclerView.ItemDecoration,然后重写onDraw()方法;
  • addItemDecoration (RecyclerView.ItemDecoration decor, int index),这个方法可以给某个特定的item设置分割线;

setItemAnimator:设置RecyclerView添加和移除条目的动画,系统默认给我们提供一个类DefaultItemAnimator,我们也可以重写RecyclerView.ItemAnimator实现自己想要的动画效果;

setHasFixedSize:设置RecyclerView 的Item宽或者高不会变,每一个Item添加或者删除都不会变。如果你没有设置setHasFixedSized没有设置的代价将会是非常昂贵的。因为RecyclerView会需要而外计算每个item的size。

4、添加Item的onClick监听事件

RecyclerView 中没有OnItemClickListener方法,但是提供了一个OnItemTouchListener事件,所以我们通过监听这个方法来实现对每个Item的点击事件监听;

mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, new RecyclerItemClickListener.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {

            }
}));

除此之外,我们还可以在Adapter实现onItemClick的监听:

holder.mOrderItem.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

            }
});

或者自己写一个接口:

private OnItemClickListener mInterface;

public void setOnItemClickListener(OnItemClickListener mInterface) {
        this.mInterface = mInterface;
}

public interface OnItemClickListener{
        void onItemClick(int position);
}

5、实现下拉加载更多,上拉刷新

这里推荐一个比较简单的框架XRecyclerView,添加依赖库

compile 'com.jcodecraeer:xrecyclerview:1.3.2'

这里我们对XRecyclerView 进行了一层封装,当时想的是如果项目重要替换XRecyclerView的话,可以直接更改VpRecyclerView 类,简单快速;其次,在VpRecyclerView 中我们设置了下拉刷新和上拉加载的动画样式,你可以自己更改,XRecyclerView提供的效果还挺多的,可以自行设置;同时,我们也统一设置了RecyclerView的刷新状态,在下拉刷新时判断是否是随后一页。

public class VpRecyclerView extends XRecyclerView {
    public static final int NONE = 0;
    //状态刷新
    public static final int REFRESH = 1;
    //状态加载更多
    public static final int LOADMORE = 2;
    private int curState = NONE;

    public VpRecyclerView(Context context) {
        super(context);
        setRefreshLoadingMoreStyle();
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    public VpRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setRefreshLoadingMoreStyle();
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    public VpRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setRefreshLoadingMoreStyle();
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    /**
     * 统一设置下拉刷新及上拉加载更多样式
     */
    private void setRefreshLoadingMoreStyle() {
        setRefreshProgressStyle(ProgressStyle.BallScale);
        setLoadingMoreProgressStyle(ProgressStyle.BallScale);
    }

    /**
     * 设置没有更多可以加载时不显示上拉加载
     */
    public void setLoadingMoreEnabled(boolean b) {
        super.setLoadingMoreEnabled(b);
    }

    /**
     * 刷新完成
     */
    public void refreshComplete() {
       super.refreshComplete();
    }
    /**
     * 加载更多完成
     */
    public void loadMoreComplete() {
        super.loadMoreComplete();
    }

    /**
     * 设置下拉刷新及上拉加载监听
     * @param listener
     */
    public void setLoadingListener(final LoadingListener listener){
        super.setLoadingListener(new XRecyclerView.LoadingListener() {
            @Override
            public void onRefresh() {
                curState = REFRESH;
                listener.onRefresh();
            }

            @Override
            public void onLoadMore() {
                curState = LOADMORE;
                listener.onLoadMore();
            }
        });
    }
    /**
     * 设置当前页及总页数,在刷新完成及加载完成调用
     */
    public boolean setCurrentAndTotal(int cur, int total) {
        if (cur >= 0 && total >= 0){
            if (cur == total) {
                setLoadingMoreEnabled(false);
                return true;
            }else if(cur < total){
                setLoadingMoreEnabled(true);
            }
        }
        return false;
    }

    /**
     * loading接口
     */
    public interface LoadingListener {

        void onRefresh();

        void onLoadMore();
    }

    /**
     *
     * @param type 刷新完成类型
     */
    public void setComplete(int type){
        switch (type){
            case REFRESH:
                super.refreshComplete();
                break;
            case LOADMORE:
                super.loadMoreComplete();
                break;
            default:
                super.refreshComplete();
                break;
        }
        curState = NONE;
    }

    public void setComplete(){
        setComplete(curState);
    }
}

如何在xml中使用呢,so easy。。。。和RecyclerView一样直接使用。

  <com.ysten.videoplus.client.widget.VpRecyclerView
        android:id="@+id/activity_search_resultlist"
        android:layout_width="match_parent"
        android:layout_height="match_parent""/>

6、RecyclerView的多种布局

LayoutManager:用来确定每一个item如何进行排列摆放,何时展示和隐藏。回收或重用一个View的时候,LayoutManager会向适配器请求新的数据来替换旧的数据,这种机制避免了创建过多的View和频繁的调用findViewById方法(与ListView原理类似)。
目前SDK中提供了三种自带的LayoutManager:LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager

前面我们已经提到RecyclerView有竖向列表,横向列表,竖向网格列表,横向网格列表,瀑布流等多种布局,现在就来看下各种布局的展现效果和实现方法吧。

//竖向滚动列表
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(layoutManager);
//横向滚动列表
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(layoutManager);
//竖向滚动网格列表(2列)
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 2);
mRecyclerView.setLayoutManager(layoutManager);
//横向滚动网格列表
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 2);
layoutManager.setOrientation(GridLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(layoutManager);
//竖向滚动瀑布流列表
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(layoutManager);
//横向滚动瀑布流列表
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(layoutManager);

7、RecyclerView添加和删除数据

以前在ListView当中,我们只要修改数据后用Adapter的notifyDatasetChange一下就可以更新界面。然而在RecyclerView中还有一些更高级的用法:

  • 添加数据:
public void addItem(DataModel content, int position) {
    datas.add(position, content);
    notifyItemInserted(position); //Attention!
}
  • 删除数据:
public void removeItem(DataModel model) {
    int position = datas.indexOf(model);
    datas.remove(position);
    notifyItemRemoved(position);//Attention!
}

8、RecyclerView加载多种不同布局

主要思路就是先定义好标识itemType的常量,然后重写getItemViewType()方法,根据不同的位置(position)返回不同的Type,接着在onCreateViewHolder()中根据参数viewType去判断该item项应该 inflate 哪个布局文件,并返回相应的ViewHolder实例(这里ViewHolder是根据不同的item布局预先自定义好的不同的ViewHolder)

public class MyRecyclerCardviewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{  

    public static enum ITEM_TYPE {  
        ITEM_TYPE_Theme,  
        ITEM_TYPE_Video  
    }  
    //数据集  
    public List<Integer> mdatas;  
    private TextView themeTitle;  

    public MyRecyclerCardviewAdapter(List<Integer> datas){  
        super();  
        this.mdatas = datas;  
    }  


    @Override  
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  

        if (viewType == ITEM_TYPE.ITEM_TYPE_Theme.ordinal()){  

            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.videothemelist,parent,false);  

            return new ThemeVideoHolder(view);  

        }else if(viewType == ITEM_TYPE.ITEM_TYPE_Video.ordinal()){  

            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.videocardview,parent,false);  
            return new VideoViewHolder(view);  

        }  
          return null;  
    }  


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

        if (holder instanceof ThemeVideoHolder){  

           themeTitle.setText("励志");  

        }else if (holder instanceof VideoViewHolder){  
            ((VideoViewHolder)holder).videologo.setImageResource(R.drawable.lianzai_02);  
            ((VideoViewHolder)holder).videovname.setText("励志,俄小伙练习街头健身一年的体型变化,Dear Hard Work!");  
            ((VideoViewHolder)holder).videoviewed.setText("2780次");  
            ((VideoViewHolder)holder).videocomment.setText("209条");  

          }  

    }  

    public int getItemViewType(int position){  
        return position % 5 == 0 ? ITEM_TYPE.ITEM_TYPE_Theme.ordinal() : ITEM_TYPE.ITEM_TYPE_Video.ordinal();  
    }  

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


    public class ThemeVideoHolder extends RecyclerView.ViewHolder{  

        public ThemeVideoHolder(View itemView) {  
            super(itemView);  
            themeTitle = (TextView) itemView.findViewById(R.id.hometab1_theme_title);  
        }  
    }  

    public class VideoViewHolder extends RecyclerView.ViewHolder {  
        public ImageView videologo;  
        public TextView videovname;  
        public TextView videoviewed;  
        public TextView videocomment;  

        public VideoViewHolder(View itemView) {  
            super(itemView);  
            videologo = (ImageView) itemView.findViewById(R.id.videologo);  
            videoviewed = (TextView) itemView.findViewById(R.id.videoviewed);  
            videocomment = (TextView) itemView.findViewById(R.id.videocomment);  
            videovname = (TextView) itemView.findViewById(R.id.videoname);  
        }  
    }  
}  

有点遗憾,最近还没有掌握怎么给Recyclerview添加header和footer,等哪天有空了再补充下。
到此,Material Design的内容已全部结束了,接下来可能再写一些目前App比较流行的UI的实现小例子了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值