一、简介:
RecyclerView 是 Android5.0 之后新出的控件。
RecyclerView 是 ListView 的增强版,不仅能实现 ListView 的效果,还优化了 ListView 的很多不足之处。
想对于 ListView 来说,官方更推荐使用 RecyclerView
二、使用 RecyclerView
- 演示思路:布局 RecyclerView ,CardView 充当其 Item !
2.1 app 的 build.gradle 中添加依赖
// cardview 是因为这个 Demo 也要用到 cardview
compile 'com.android.support:cardview-v7:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
2.2 主页面布局文件
2.3 Actiity 和 Adapter 的代码
public class MyRecyclerViewActivity extends AppCompatActivity {
@BindView(R.id.floating)
FloatingActionButton floating;
@BindView(R.id.toolbar_title)
TextView toolbarTitle;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
private Snackbar snackbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycleview);
ButterKnife.bind(this);
//设置透明状态栏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();
localLayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
}
toolbar.setTitle("");
setSupportActionBar(toolbar);
toolbar.setNavigationIcon(R.drawable.setting);
initRecyclerViewData();
initRcyclerView();
}
private void initRcyclerView() {
LinearLayoutManager manager = new LinearLayoutManager(this);
// GridLayoutManager manager = new GridLayoutManager(getApplicationContext(),2);
// StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2, OrientationHelper.HORIZONTAL);
recyclerView.setLayoutManager(manager);
myRecyclerAdapter = new MyRecyclerAdapter();
recyclerView.setAdapter(myRecyclerAdapter);
}
private List listData;
/**
* 初始化 RecyclerView 的数据
*/
private void initRecyclerViewData() {
listData = new ArrayList<>();
int m = 0;
for (int i = 0; i < 20; i++) {
listData.add("珞璃之神" + m);
m++;
}
}
private MyRecyclerAdapter myRecyclerAdapter;
public class MyRecyclerAdapter extends RecyclerView.Adapter {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_card_view, parent, false);
// View view = View.inflate(getApplicationContext(), R.layout.activity_card_view, parent);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.cardText.setText(listData.get(position));
}
@Override
public int getItemCount() {
return listData.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.card_text)
TextView cardText;
@BindView(R.id.card_image)
ImageView cardImage;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
}
注意: RecyclerView 的三种 manager ,分别为 线性、宫格、瀑布流样式。
2.4 RecyclerView 的 item 的样式为:
2.5 运行结果如下:
-
LinearLayoutManager manager = new LinearLayoutManager(this); 结果:
-
GridLayoutManager manager = new GridLayoutManager(getApplicationContext(),2);结果如下:
-
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2, OrientationHelper.HORIZONTAL);结果如下:
三、RecyclerView 添加条目点击事件
3.1 RecyclerView 并没有对外暴露的具体的单击或长按监听事件,需要我们自己来处理单击或长按事件,如下所示:
recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener(){
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
这种需要自己增加单击或长按事件的逻辑,然后利用接口回调出去。
Android 给我们提供了一个手势监测帮助类 GestureDetector ,我们可以借助这个类来处理不同的手势,我们重新建个类实现 RecyclerView.OnItemTouchListener 接口。代码如下:
/**
* 自定义手势监听
*/
public class RecyclerViewClickListener implements RecyclerView.OnItemTouchListener {
// GestureDetectorCompat 是为了版本兼容
private GestureDetectorCompat mGestureDetector;
private OnItem2ClickListener mListener;
//自定义内部监听
public interface OnItem2ClickListener {
//单击
void onItemClick(View view, int position);
//长按
void onItemLongClick(View view, int position);
}
public RecyclerViewClickListener(Context context, final RecyclerView mRecyclerView,
OnItem2ClickListener listener) {
this.mListener = listener;
// SimpleOnGestureListener 是为了选择重写需要的方法
mGestureDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() {
//单击事件
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.i("mGestureDetector","onSingleTapUp");
View childViewUnder = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
if (childViewUnder != null && mListener != null) {
mListener.onItemClick(childViewUnder, mRecyclerView.getChildLayoutPosition(childViewUnder));
return true;
}
return false;
}
//长按事件
@Override
public void onLongPress(MotionEvent e) {
Log.i("mGestureDetector","onLongPress");
View childView = mRecyclerView.findChildViewUnder(e.getX(),e.getY());
if(childView != null && mListener != null){
mListener.onItemLongClick(childView,mRecyclerView.getChildLayoutPosition(childView));
}
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
//是否拦截事件交给 mGestureDetector 处理
if(mGestureDetector.onTouchEvent(e)){
return true;
}else
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
- 代码中只实现了,单击和长按事件的回调,更多的事件操作方法可以参考 GestureDetector 类。
3.2 另一种方式是在 Adapter 的 onBindViewHolder 方法中,利用 View 本身的监听事件,来设置回调监听,代码如下:
public class MyRecyclerAdapter extends RecyclerView.Adapter {
private List listData;
public MyRecyclerAdapter(List listData){
this.listData = listData;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_card_view, parent, false);
// View view = View.inflate(getApplicationContext(), R.layout.activity_card_view, parent);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
/**
* 在 onBindViewHolder 中,设置单击和长按的监听回调
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.cardText.setText(listData.get(position));
//单击
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//触发自定义监听的单击事件
onItemClickListener.onItemClick(holder.itemView,position);
}
});
//长按
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//触发自定义监听的长按事件
onItemClickListener.onItemLongClick(holder.itemView,position);
return true;//表示此事件已经消费,不会触发单击事件
}
});
}
@Override
public int getItemCount() {
return listData.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.card_text)
TextView cardText;
@BindView(R.id.card_image)
ImageView cardImage;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
public void setOnItemClickListener(MyRecyclerAdapter.OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
private OnItemClickListener onItemClickListener;
/**
* 自定义监听回调,RecyclerView 的 单击和长按事件
*/
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
}
3.3 两种添加点击事件比较
第一种方式更加灵活,解耦性更高,第二种因为设置在 Adapter 内,只能用作特定的 RecyclerView
第二种相对第一种来说,更加简便,实现起来也方便,也比较好理解。
第一种还能用于更加复杂的手势监听,我们可以利用 GestureDetector 类来实现更加复杂的事件监听回调,而第二种监听的事件比较有限。