RecyclerView
什么是RecyclerView?
RecyclerView其实就是一个在5.0推出的控件,可以用它来代替ListView和GridView,从这一点也能看出来它的特性和ListView以及GridView类似,注意我说的是整体上类似,既然是更高的版本推出的,岂能再和再和低版本的小崽子们一个层次,所以它加入了很多新的特征,下面会讲到。
为什么叫RecyclerView?
虽然在计算机界,起名字一直都比较个性,比较不符合常理,通常情况下试图通过名字来了解一件事物的人都会走火入魔,想当年,我就想知道android为啥叫android,是不是什么缩写,但是后来确实让朕很失望,类似的还有apple(这里指手机),oracle(甲骨文)通过这些名字来了解一些事物真是相当困难,但是RecyclerView和他的功能还是有一些联系的:
- RecyclerView不关心Item是否显示在正确的位置,以及如何显示。
- RecyclerView不关心Item之间如何间隔。
- 不关注Item增加与删除的动画效果。
- 它只关注如何回收和复用View(这就是叫RecycleView的原因)。
嗯?什么都不关心,那还玩个毛线啊?
这位看官说的好,RecyclerView既然敢这么玩,当然是有手段的:
- 不关心Item是否显示在正确的位置,以及如何显示,此时我们用LayoutManager来解决。
- 不关心Item之间如何间隔,此时我们用ItemDecoration来解决。
- 不关心Item的增加与删除的动画效果,此时用ItemAnimator来解决。
看到了吧,真正牛逼的人是不需要什么都管的,只要有人就行。
这位看官又问啦,RecyclerView都有啥人(相关类)啊?看官且看:
- Adapter
- ViewHolder
- LayoutManager
- ItemDecoration
- ItemAnimator
O啦,主公以及大将都悉数登场了,看官可能又要问了,这阵容能干点啥大事呢? 嗯,问的好,以下就是此阵容能干的事:
- Just like ListView(实现listview的效果)
- Just like GridView(实现GridView的效果)
- 实现横向的ListView效果
- 实现横向的GridView效果
- 实现瀑布流(此处可以通过名字来理解其效果)
- 定制Item增加和删除动画
都是字啊,是骡子是马拉出来溜溜,来图让我看看!好,看官既然这么急切,那就来一波:
实现listview的效果
实现垂直GridView的效果
实现横向的GridView效果
瀑布流:
动画效果(可以自己设置各种动画)
好,准备工作完成,开始编写:
实现Recyclerview
首先:导入android-support-v7-recyclerview.jar包,如果是android studio 直接加入依赖即可。
设置主布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/idrecyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hello World!" />
</RelativeLayout>
item布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark"
>
<TextView
android:id="@+id/item_recyclerview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
MainActivity代码:
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<String> list;
private SimpleAdap adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iniDatas();
iniView();
adapter = new SimpleAdap(this,list);
recyclerView.setAdapter(adapter);
//设置以listview形式显示
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);
recyclerView.setLayoutManager(layoutManager);
}
private void iniView() {
recyclerView = (RecyclerView) findViewById(R.id.idrecyclerview);
}
private void iniDatas() {
list = new ArrayList<>();
Random ran = new Random(50);
for(int i=0;i<50;i++){
list.add(String.valueOf(ran.nextInt())+i);
}
}
}
class SimpleAdap extends RecyclerView.Adapter<MyViewHolder>{
private LayoutInflater layoutInflater;
private List<String> mData;
private Context context;
public SimpleAdap(Context context, List<String> list) {
this.context = context;
mData = list;
layoutInflater = LayoutInflater.from(context);
}
//google将对viewholder的操作分成了两步,创建和绑定,体现了google对viewholder的强制性
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.item_recyclerview,parent,false);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
//绑定数据
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.text.setText(mData.get(position));
}
@Override
public int getItemCount() {
return mData.size() ;
}
}
class MyViewHolder extends RecyclerView.ViewHolder {
public TextView text;
public MyViewHolder(View itemView) {
super(itemView);
text = (TextView) itemView.findViewById(R.id.item_recyclerview);
}
}
此时的item之间是没有分割线的
如图:
这怎么能行呢?跟块黑板似的,listview得有分割线啊!
看官且看下面,待我添加分割线!
添加分割线
其实对于recyclerView来说,添加分割线很简单,可以交给它的小弟ItemDecoration来实现:
//设置listview之间的分割线
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST);
recyclerView.addItemDecoration(dividerItemDecoration);//参数是抽象类itemDecoration的实现类,因为没有现成的,所以从github download一个
需要注意的是,recyclerView.addItemDecoration(dividerItemDecoration);
中传入的参数系统并没有为我们提供,我在此是在github上down的一个类,链接地址。
现在有了分割线,如图:
利用github上的源码自定义分割条
看官心中是否有疑问,这个白色的分割线是设置的颜色?还是图片?从哪设置的?
这就需要看刚才从github上下载的那个源码了
在源码中,有这么一句代码:
final TypedArray a = context.obtainStyledAttributes(ATTRS);
通过顺藤摸瓜,我们就可以知道,白色分割线就是从style中得到的,哼哼,知道了这些那就好办了,我们可以自定义我们的分割条了。
只需要在styles.xml中添加这样的一句代码:
<item name="android:listDivider">@drawable/ic_launcher</item>
此时我用系统提供的一张图片来作为分割线,如图所示:
什么?没有看到分割线? android图标那个就是分割线(确实有点大)
在此只是实例,在正式使用的时候,我们完全可以自定义一个drawale,然后进行设置。
实现GridView
在实现之前先说一点,当我们使用recyclerview的时候,要把它作为listview和gridview的综合体,不要总想着以前的listview和gridview是两个不同的控件,这是一个思想上的转变(思想是最重要的)。
竖直gridview
//第二个参数为gridview的列数
recyclerView.setLayoutManager(new GridLayoutManager(this,4));
横向gridview
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(5,StaggeredGridLayoutManager.HORIZONTAL));
注意:在使用水平的gridview的是有,itemview的宽不能为match_parent,并且上面分割线的设置在此也不适用了。
瀑布流
瀑布流,其实就是item的宽或者高不一样,造成参差不齐的效果而已!
设置瀑布管理器:
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));
在适配器中初始化一个数据集合:
mHeight = new ArrayList<>();
for(int i=0;i<mData.size();i++){
mHeight.add((int) (100+Math.random()*300));
}
在onBindViewHolder中设置item高度:
public void onBindViewHolder(seViewHolder holder, int position) {
holder.text.setText(mData.get(position));
ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
layoutParams.height = mHeight.get(position);
holder.itemView.setLayoutParams(layoutParams);
}
增加删除动画
设置动画:
recyclerView.setItemAnimator(new DefaultItemAnimator());
在适配器中添加两个方法:
public void add(int position){
mData.add(position,"Insert data");
notifyItemInserted(position);//此处要注意,和listview不一样
}
public void delete(int position){
mData.remove(position);
notifyItemRemoved(position);
}
在onOptionsItemSelected中调用方法:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.listview:
recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
break;
case R.id.heng_listview:
break;
case R.id.gridview:
recyclerView.setLayoutManager(new GridLayoutManager(this,4));
//recyclerView.addItemDecoration(dividerItemDecoration);
break;
case R.id.heng_grid:
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(5, StaggeredGridLayoutManager.HORIZONTAL));
break;
case R.id.pubu:
Intent intent = new Intent(this,PubuActivity.class);
startActivity(intent);
break;
case R.id.delete:
adapter.delete(1);
break;
case R.id.add:
adapter.add(1);
break;
}
return super.onOptionsItemSelected(item);
}
添加监听
说到recyclerview的监听,我要告诉看官一个悲伤的故事—-recyclerview的监听需要自己实现
实现监听的方式有很多,在此,利用在适配器中设置接口回调的方法!
在适配器中定义接口:
public interface OnItemClickListener{
void onItemClick(View view,int position);
void onItemLongClick(View view,int position);
}
对外提供方法:
private OnItemClickListener onItemClickListener;
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
在中定义监听:
public void onBindViewHolder(MyViewHolder holder, final int position) {
holder.text.setText(mData.get(position));
// ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
// layoutParams.height = mHeight.get(position);
// holder.itemView.setLayoutParams(layoutParams);
if(onItemClickListener!=null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onItemClickListener.onItemClick(v, position);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
onItemClickListener.onItemLongClick(v, position);
return false;
}
});
}
}
使用回调方法设置监听:
adapter.setOnItemClickListener(new SimpleAdap.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(MainActivity.this, "item"+position, Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(MainActivity.this, "long"+position, Toast.LENGTH_SHORT).show();
}
});
注意:如果我们此时利用上面介绍的添加删除item的方法,添加了或者删除了item,这是我们点击item的时候,会发现position会不正常,具体表现在当我们添加多个item的时候,会发现所添加的每个item点击的时候都是同一个position。
解决方法:
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.text.setText(mData.get(position));
if(onItemClickListener!=null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int layoutPosition = holder.getLayoutPosition();//用此方法得到全局position,传入点击事件中
onItemClickListener.onItemClick(v, layoutPosition);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int layoutPosition = holder.getLayoutPosition();
onItemClickListener.onItemLongClick(v, layoutPosition);
return false;
}
});
}
}
OK,散会!
相关知识点,是本人对慕课网相关课程的总结,也是作为自己的学习记录