RecycleView学习总结复习篇
recyclerView是android5.0之后推出的一款新的View布局,功能相较于ListView有过之而无不及,相信在以后的学习和工作中都将可能会用上,这两天自己在边看边学其中功能与各种效果,现来博客与诸君分享,也为日后自己复习设下渠道。
首先,我们了解一下为什么要叫做RecyclerView?
它不关心Item是否显示在正确位置,如何显示;不关心Item间如何分割;不关注Item增加和删除的动画效果;仅仅关注如何回收和服用View(即英文Recycle的译义)。
那可能有人要问了,这些都是View里比较重要的且频繁使用的属性和效果,都不关心的话,如何做到控制和实现呢?其实,不必担心,我们可以通过LayoutManager来实现Item的显示,ItemDecoration来自定义Item之间的分割线,以及ItemAnimator来完成Item增加和删除时所需要的各种动画(下面的文章会详细介绍)。所以它的功能还是很强大的,值得我们深入研究!
知道了RecyclerView的概念,我们来大体了解一下它具备的功能:
1.ListView
2.GridView
3.横向ListView
4.横向GridView
5.瀑布流
6.定制Item增加和删除动画
大致为以上功能,是不是挺强大的。
工欲善其事必先利其器,下面给出2个需要使用到的链接:
https://gist.github.com/alexfu/0f464fc3742f134ccd1e
github上recyclerviewItemDecoration原地址
https://github.com/gabrielemariotti/RecyclerViewItemAnimators
github/上recyclerview动画效果集合原地址
下面进入今天的主题:
由于我们的工程依赖android.support.v7包里的recyclerViewjar包,建立工程时要找到你的sdk存放路径的extras/android/support/v7/recyclerview/libs文件目录下的jar包拷贝到工程目录libs下,才能实现全部功能!
首先我们要首先ListView,写两个方法:initViews();initDatas();
private void initDatas() {
mDatas = new ArrayList();
for (int i = 'A'; i <= 'z'; i++) {
mDatas.add("" + (char) i);
}
}
private void initViews() {
mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
}
这两个方法用来创建View和存放数据。这里我放的是A-z。
然后创一个SimpleAdapter来适配主界面。这里需要注意的是
要继承RecyclerView.Adapter ,以自己写的MyViewHolder类作为泛型,才能对recycleView里的Item进行配置。
class MyViewHolder extends ViewHolder {
TextView tv;
public MyViewHolder(View arg0) {
super(arg0);
tv = (TextView) arg0.findViewById(R.id.id_tv);
}
这里我就给每个Item一个TextView,然后通过我们自己的ViewHolder来初始化它。
另外还要重写父类的方法:
@Override
public int getItemCount() {
return mDatas.size();
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int pos) {
holder.tv.setText(mDatas.get(pos));
// click
setUpItemEvent(holder);
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup arg0, int arg1) {
View view = mInflater.inflate(R.layout.item_simple_textview, arg0, false);
MyViewHolder viewHolder = new MyViewHolder(view);
return viewHolder;
}
这里主要关注第二个和第三个方法,顾名思义就是绑定ViewHolder和创建Viewholder,
绑定里用位置来设置Item内Text显示的文字,
setUpItemEvent(holder);
这个方法后面会讲到大家先忽略。然后Create方法里就是初始化View工作,要创建一个item_simple_textview布局文件,里面只放了一个TextView这里我就不做过多赘述,最后返回我们的viewHolder。别忘了做绑定,
mAdapter = new SimpleAdapter(this, mDatas);
mRecyclerView.setAdapter(mAdapter);
还要给布局设置一个管理器:
// 设置recyclerview的布局管理
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
然而此时我们运行程序会发现虽然ListView正常展示了,可是Item直接并没有分割。
看起来很不舒服,接下来,我们就完成自定义分割线的工作。
由于RecyclerView自身并不能为Item添加分割线,所以我们采用外部开源文件的方法叫做DividerItemDecoration,该方法可以在正文开篇的地址里找到并下载。
// 设置recyclerview的Item分割线,通过抽象类来控制
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
这里给Item加一个垂直方向的默认的分割线。(稍后说下自定义)可以得到如下效果
但是,如果默认的分割线不合你的胃口,你完全可以自定义你想要的分割线样式。这就需要我们对开源代码进行简单的分析!
public DividerItemDecoration(Context context, int orientation)
{
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
这是DividerItemDecoration类的构造方法,从中我们不难看出a对象是从context.obtainStyledAttributes(ATTRS);中获取到的,也就是说从theme中可以得到,这样我们就可以自己定义一个shape放入theme里,就可以给方法查找和调用了。
这里我们写了一个4dp高度的矩形,中间有三种颜色的渐变来作为我们的分割线。
然后由于我使用的SDK是6.0版本,所以讲它放入values-v14包里。
到这里我们的ListView差不多就实现了。接下来说明一下各自布局的切换使用。
-------------------------------------------------------------------------------------------------------------------
我们用menu里的item来实现不同布局的切换!
进入main.xml添加三个Item
分别代表ListView、GridView、瀑布流布局。然后根据id来设置点击到不同Item时显示的布局样式。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch (id) {
case R.id.action_add:
mAdapter.addData(1);
break;
case R.id.action_delete:
mAdapter.deleteData(1);
break;
case R.id.action_listView:
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
break;
case R.id.action_gridView:
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 3));
break;
case R.id.action_staggered:
Intent intent = new Intent(this, StaggeredActivity.class);
startActivity(intent);
break;
default:
break;
}
return false;
}
同样,上面两个后面再做解释,先看后面三个选项。每当不同id被选中时,我们给予recyclerView不同的LayoutManager,这样它就显示不同的布局了!由于GridView和ListView是继承自同一父类,所以他们之间转化不要开启新的Activity而瀑布流布局就需要开启新Acitivity来显示,我们采用显式Intent切换。
GridView就这样了,比较简单,下面我们主要研究一下瀑布流的代码。
我们把MainActivity和SimpleAdapter都拷贝一份,改名为StaggeredActivity和StaggeredAdapter。
为了防止代码复写的麻烦,直接在SimpleAdapter里提供一个回调方法,供StaggeredAdapter使用,实现点击和长按事件。
// 设置一个接口回调,给Item绑定一个点击事件
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
private OnItemClickListener onItemClickListener;
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
protected void setUpItemEvent(final MyViewHolder holder) {
if (onItemClickListener != null) {
holder.itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int layoutPosition = holder.getLayoutPosition();
onItemClickListener.onItemClick(holder.itemView, layoutPosition);
}
});
}
// longclick
holder.itemView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int layoutPosition = holder.getLayoutPosition();
onItemClickListener.onItemLongClick(holder.itemView, layoutPosition);
return false;
}
});
}
这样处理的话,就可以让
StaggeredAdapter的代码更加简洁:
public class StaggeredAdapter extends SimpleAdapter {
private LayoutInflater mInflater;
private Context mContext;
private List mDatas;
private List mHeight;
public StaggeredAdapter(Context context, List datas) {
super(context, datas);
mHeight = new ArrayList();
for (int i = 0; i < mDatas.size(); i++) {
mHeight.add((int) (100 + Math.random() * 300));
}
}
@Override
public void onBindViewHolder(MyViewHolder holder, int pos) {
LayoutParams lp = (LayoutParams) holder.itemView.getLayoutParams();
lp.height = mHeight.get(pos);
holder.itemView.setLayoutParams(lp);
holder.tv.setText(mDatas.get(pos));
setUpItemEvent(holder);
}
}
把height做一个随机数处理,就可以得到瀑布流那样不规则的分布布局。然后通过LayoutParams和height进行绑定,就可以动态的设置item的高度了。setUpItemEvent就是响应点击和长按事件。效果如下:
关于Item增加和删除的动画:
在menu里加入两个图标,增加和删除,对应前面代码所示的switch方法内add和delete方法。代码如下:
public void addData(int pos) {
mDatas.add(pos, "Insert one");
notifyItemInserted(pos);
}
public void deleteData(int pos) {
mDatas.remove(pos);
notifyItemRemoved(pos);
}
注意:这里使用了notifyItemInserted和notifyItemRemoved两个方法,它会导致点击加入或者删除Item后,新增的Item和删除的Item后面那个Item的postion不变,因为他只notify了增加和移除,并没有重绘View,所以后面代码里用getParamPosition()方法来得到View所显示的Item的动态位置,就不会造成多个position相同的情况。
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
这里我使用的默认的动画效果,大家可以去开篇给出的链接下载动画效果源码,实现各种炫酷的动画!
-------------------------------------------------------------------------------------------------------------------
好了,基本的功能已经介绍的差不多了,更多的炫酷动画和花式布局,需要靠我们更多的去研究和学习!本人也只是小白阶段,跟着视频学习完写个博客记录一下学习成果,方便以后的复习同时也能给需要的人带来一点参考和建议吧。共勉!