Materail Design 入门(十)—— RecyclerView的使用(一)
2017-07-06 17:29
357 查看
墨迹了这么久终于写到了Material Design系列的最后一篇了。这篇RecyclerView的使用仅作是知识的回顾吧。本章节我们一起来复习下Recyclerview布局的设置(竖向列表,横向列表,竖向网格列表,横向网格列表,瀑布流),添加分割线,添加ItemClick事件,下拉刷新,上拉加载等功能。
RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好。
这里记住两点:
Recyclerview的Adapter继承RecyclerView.Adapter;
ViewHolder继承RecyclerView.ViewHolder;
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。
除此之外,我们还可以在Adapter实现onItemClick的监听:
或者自己写一个接口:
这里我们对XRecyclerView 进行了一层封装,当时想的是如果项目重要替换XRecyclerView的话,可以直接更改VpRecyclerView 类,简单快速;其次,在VpRecyclerView 中我们设置了下拉刷新和上拉加载的动画样式,你可以自己更改,XRecyclerView提供的效果还挺多的,可以自行设置;同时,我们也统一设置了RecyclerView的刷新状态,在下拉刷新时判断是否是随后一页。
如何在xml中使用呢,so easy。。。。和RecyclerView一样直接使用。
目前SDK中提供了三种自带的LayoutManager:LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager
前面我们已经提到RecyclerView有竖向列表,横向列表,竖向网格列表,横向网格列表,瀑布流等多种布局,现在就来看下各种布局的展现效果和实现方法吧。
添加数据:
删除数据:
有点遗憾,最近还没有掌握怎么给Recyclerview添加header和footer,等哪天有空了再补充下。
到此,Material Design的内容已全部结束了,接下来可能再写一些目前App比较流行的UI的实现小例子了。
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的实现小例子了。
相关文章推荐
- Materail Design 入门(十)—— RecyclerView的使用(二)万能分隔线
- Materail Design 入门(七)——AppBarLayout的使用方法
- Materail Design 入门(四)——Toolbar的使用方法(1)
- Materail Design 入门(五)—— 使用DrawerLayout实现仿qq6.0的侧滑菜单功能
- Materail Design 入门(九)—— NavigationView的使用
- Materail Design 入门(八)——CollapsingToolbarLayout的使用方法
- Materail Design 入门(六)—— TabLayout之标题中添加自定义View(2)
- Materail Design 入门(四)——Toolbar的使用方法(2)
- Materail Design 入门(六)—— TabLayout之使用介绍(1)
- Android编程入门--RecyclerView使用
- Android应用开发中RecyclerView组件使用入门教程
- Android Study Material Design 二 之:这可能是RecyclerView最全解析 初级使用(一)
- Android Kotlin入门(RecyclerView的使用)
- Materail Design 入门(三)——FloatingActionButton和Snackbar
- Materail Design 入门(六)—— TabLayout之设置自定义指示器宽度(3)
- RecyclerView使用——入门篇
- Android L中的RecyclerView 、CardView 、Palette的使用
- UltimateRecyclerView的使用方法详解
- RecyclerView使用介绍
- Android RecyclerView 使用完全解析 体验艺术般的控件