一、RecycleView的基本使用
RecycleView同ListView一样在APP页面中以列表的形式显示元素,由于提供数据的方式有很多种list,array,map或者set等,但是最终都需要将这些数据源,以统一的样式显示出来。因此在RecycleView(ListView)的使用中,有RecycleView负责显示,Adpter负责对数据进行适配操作,数据源(一般是List)部分。
1.1 gradle倒包
compile
'com.android.support:recyclerview-v7:25.2.0'
|
1.2 布局控件
在Activity的activity_main.xml布局文件中添加RecycleView控件
<?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:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/id_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
|
为这个RecycleView创建一个item布局文件item_recycleview.xml,并为它添加简单的元素TextView,代码如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center_vertical">
<TextView
android:id="@+id/recycle_textview"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textSize="20sp"/>
</LinearLayout>
|
1.3 Adater代码和Activity代码的编写
新建一个
RecyclerView.Adapter适配器TestRecycleViewAdapter,在新建的Adapter中需要完成三个重要的操作:
1.实现一个RecycleView.ViewHolder,该ViewHolder主要用来绑定创建的item_recycleview.xml布局文件中的控件元素。
2.重写父类的onCreateViewHolder函数,该函数主要用来创建刚定义的ViewHolder的对象,可以用来显示Item元素。
3.重写父类的onBindViewHolder函数,在函数中可以设置每个Item项特有的参数信息。
public
class
TestRecycleViewAdapter
extends
RecyclerView
.
Adapter<TestRecycleViewAdapter
.
ViewHolderA>
{
private
Context
mContext;
private
List
<
String
> mList;
public
TestRecycleViewAdapter
(
Context
context,
List
<
String
> list) {
mContext = context;
mList = list;
}
//
创建每个显示的
Item
元素
@Override
public
ViewHolderA
onCreateViewHolder(
ViewGroup
parent, int viewType) {
//
此处动态加载
ViewHolder
的布局文件并返回
holder
View
view =
LayoutInflater
.from(mContext).inflate(
R
.layout.recycleview_item, parent,
false
);
ViewHolderA
holderA =
new
ViewHolderA
(view);
return
holderA;
}
//
设置每个显示的
Item
元素的独特的参数
@Override
public void onBindViewHolder(
ViewHolderA
holder, int position) {
//
此处设置
Item
中
view
的数据
holder.mTextView.setText(mList.get(position));
}
@Override
public int getItemCount() {
//
生成的
item
的数量
return
mList.size();
}
//RecyclerView
中每个
Item
的
ViewHolder
,以及
item
内部布局控件进行
id
绑定
class
ViewHolderA
extends
RecyclerView
.
ViewHolder
{
TextView
mTextView;
public
ViewHolderA
(
View
itemView) {
super
(itemView);
mTextView = (
TextView
) itemView.findViewById(
R
.id.recycle_textview);
}
}
}
|
在Activity中使用的代码
public class MainActivity extends AppCompatActivity {
private List<String> list;
//数据源
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.activity_main_recycle_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
initData();
//实例化adapter,并传输数据给adapter
TestRecycleViewAdapter adapter = new TestRecycleViewAdapter(getApplicationContext(), list);
mRecyclerView.setAdapter(adapter);
}
/**
* 添加数据
* */
private void initData() {
list = new ArrayList<>();
for (int i = 0; i < 50; i++) {
list.add("item" + i);
}
}
}
|
二、RecycleView的不同风格和布局的显示
三、RecycleView的Item点击事件
RecycleView的Item点击事件的处理方式有三种:
3.1 在Adpater中实现
直接在Adapter中的onBindViewHolder()方法中实现点击事件,参考如下代码。
@Override
public
void
onBindViewHolder
(MyViewHolder viewHolder,
final
int
postion) {
viewHolder.textView.setText(mDatas.get(postion));
viewHolder.rootView.setOnClickListener(
new
OnClickListener() {
@Override
public
void
onClick
(View arg0) {
// 点击事件
Toast.makeText(mContext, postion +
""
,
1000
).show();
}
});
}
|
这种方式的优点是,可以很方便的实现点击事件,代码不用很复杂;缺点也很明显,就是adapter一般只持有数据源的引用,不能实现很复杂的逻辑处理操作。
3.2 在Activity中实现
1.先在Adapter中定义一个接口。
public
interface
onRecyclerViewItemClick {
void
onItemClick(View v,
int
position);
}
|
2. 在Adapter中定义一个刚才定义的接口变量,并定义一个函数,或者在Adapter的构造函数中接受接口的引用。
private
onRecyclerViewItemClick mOnRvItemClick;
public
DemoAdapter(Context ctx, String[] strings, onRecyclerViewItemClick onRvItemClick) {
mContext = ctx;
this
.mOnRvItemClick = onRvItemClick;
this
.strings = strings;
}
|
3. 在自定义的ViewHolder中实现onClickListenr接口,并设置onItemClick事件,将点击事件传到自定义的接口上去,最终传到外面的Activity调用者上去。
public
class
ViewHolder
extends
RecyclerView.ViewHolder
implements
View.OnClickListener {
@BindView(R.id.textView)
TextView textView;
public
ViewHolder(View itemView) {
super
(itemView);
ButterKnife.bind(
this
, itemView);
itemView.setOnClickListener(
this
);
}
public
void
setData(
int
position) {
textView.setText("第" + position + "行");
}
//设置onItemClick事件
@Override
public
void
onClick(View view) {
if
(mOnRvItemClick !=
null
)
mOnRvItemClick.onItemClick(view, getAdapterPosition());
}
}
|
4.在Activity中实现onItemClick方法
public
class
MainActivity
extends
AppCompatActivity {
@BindView(R.id.recycler_view)
RecyclerView mRecyclerView;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(
this
);
DemoAdapter myAdapter =
new
DemoAdapter(
this
,
null
,
new DemoAdapter.onRecyclerViewItemClick() {
@Override
public void onItemClick(View v, int position) {
Snackbar.make(v, "第" + position + "行", Snackbar.LENGTH_SHORT).show();
}
}
);
mRecyclerView.setLayoutManager(
new
LinearLayoutManager(
this
, LinearLayoutManager.VERTICAL,
false
));
mRecyclerView.setAdapter(myAdapter);
}
}
|
5.为了便于查阅,整体的Adapter的代码如下。
public
class
DemoAdapter
extends
RecyclerView.Adapter<DemoAdapter.ViewHolder> {
private
onRecyclerViewItemClick mOnRvItemClick;
private
Context mContext;
String[] strings;
public
DemoAdapter(Context ctx, String[] strings, onRecyclerViewItemClick onRvItemClick) {
mContext = ctx;
this
.mOnRvItemClick = onRvItemClick;
this
.strings = strings;
}
@Override
public
ViewHolder onCreateViewHolder(ViewGroup parent,
int
viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.activity_main_item, parent,
false
);
return
new
ViewHolder(view);
}
@Override
public
void
onBindViewHolder(ViewHolder holder,
int
position) {
holder.setData(position);
}
@Override
public
int
getItemCount() {
return
20;
}
public
class
ViewHolder
extends
RecyclerView.ViewHolder
implements
View.OnClickListener {
@BindView(R.id.textView)
TextView textView;
public
ViewHolder(View itemView) {
super
(itemView);
ButterKnife.bind(
this
, itemView);
itemView.setOnClickListener(
this
);
}
public
void
setData(
int
position) {
textView.setText("第" + position + "行");
}
@Override
public
void
onClick(View view) {
if
(mOnRvItemClick !=
null
)
mOnRvItemClick.onItemClick(view, getAdapterPosition());
}
}
/**
* item点击接口
*/
public
interface
onRecyclerViewItemClick {
void
onItemClick(View v,
int
position);
}
}
|
3.3
修改RecyclerView源码
这种方式一般不常见,也推荐使用。
四、RecycleView中的乱序处理
4.1问题由来
在RecycleView的使用过程中可能会出现这样,比如使用了checkbox控件,在勾选某项的checkbox之后,滑动checkbox的过程中后面的checkbox也被勾选上了,这种问题是由于RecycleView使用的复用的机制。
4.2解决办法
解决该问题的办法一般是用一个数组或者hashmap将列表中position对应Item的checkbox的状态值保存下来,并在
onBindViewHolder
绑定视图时重新更新checkbox的状态,如果在对Item的checkbox状态进行更新时,一定要对对应的数组或者map中对应的值进行更新,参见如下代码:
@Override
public
void
onBindViewHolder(ViewHolder holder, final
int
position
) {
//设置checkBox改变监听
holder.checkBox.setOnCheckedChangeListener(
new
CompoundButton.OnCheckedChangeListener() {
@Override
public
void
onCheckedChanged(CompoundButton buttonView,
boolean
isChecked) {
//用map集合保存checkbox改变的状态值
map
.
put
(
position
, isChecked);
}
});
// 用map集合保存checkbox不确定情况下的状态值
if
(
map
.
get
(
position
) == null) {
map
.
put
(
position
, false);
}
//用map中的值更新checkbox的状态
holder.checkBox.setChecked(
map
.
get
(
position
));
}
|
4.3 乱序问题的进一步升级和处理
如果RecycleView列表中需要删除某项Item项时,在重复删除操作之后依旧可能出现乱序的情况(具体问题描述详情参考:
http://blog.csdn.net/Zackratos/article/details/52346986),该问题的处理步骤包括:
1.删除数组中对应的元素值
2.删除对应的Item项,并对整个Item列表进行调整。
五、参考博客链接如下
RecycleView的Item点击事件处理:
RecycleView的乱序处理: