文章目录
1. 背景
我们都知道在android 5.0
后引入了RecyclerView
来替代ListView
,由于其强大的功能和效果以及其规范化,已经逐渐完全替代了ListView
和GridView
,本文将简单探究RecyclerView
替代ListView
的具体使用,在下一篇中将探究RecyclerView
替代GridView
的具体使用。参考文章:here, Android
进阶之光。
2.使用
2.1 基本使用
- 依赖导入
- 布局文件定义
2.1.1 依赖
对于Android 9.0
(API level 28
)中提出了AndroidX
,它是Jetpack
的一部分。对于API level 27
或者更早的版本中可以使用support library
,对应于com.android.support.*
。但是Google
官方推荐使用在项目中使用AndroidX
,并停止了对com.android.support.*
的支持。AndroidX
是对android.support.xxx
包的整理后产物。由于之前的 support
包过于混乱,所以,Google
推出了AndroidX
。
故而在一些博客中常见的:
implementation 'com.android.support:appcompat-v7:22.2.0'
implementation 'com.android.support:appcompat-v7:26.1.0'
将之复制到相应的位置,可以看见如下:
它推荐使用Refactor->Migrate
来迁移到AndridX libraries
库。由于我们的项目默认创建的就是AndroidX
的了,这里提示的错误只是因为导入的依赖不对,这里应该是:
implementation 'androidx.recyclerview:recyclerview:1.1.0'
2.1.2 基本案例
主布局文件:recycleview.xml
<?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="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/myrecycleview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
和ListView
类似的,我们需要定义每一个item
的样式布局:recycleview_item.xml
<?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="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_item"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center" />
</LinearLayout>
同样,需要定义一个适配器方法,该适配器方法需要继承自RecyclerView.Adapter
,在该类中需要复写:onCreateViewHolder
、onBindViewHolder
和getItemCount
方法。
package com.example.myapplication;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter{
private List<String> mList;
private Context context;
public MyAdapter(Context context, List<String> mList){
this.context = context;
this.mList = mList;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.recycleview_item, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
((MyViewHolder) holder).tv.setText(mList.get(position));
}
@Override
public int getItemCount() {
return mList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView tv;
public MyViewHolder(View view){
super(view);
tv = (TextView) view.findViewById(R.id.tv_item);
}
}
}
和之前写ListView
中的ViewHolder
中的区别在于,这里的适配器,需要强制实现onBindViewHolder
,也就是必须要写一个ViewHolder
类,继承自RecyclerView.ViewHolder
,以保存已经实例化好的变量。使用onBindViewHolder
方法来得到已经实例化过的对象,进而进行一些必要的赋值操作。
然后是我们的函数入口:
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private MyAdapter adapter;
private List<String> mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycleview);
recyclerView = findViewById(R.id.myrecycleview);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
mList = getList();
adapter = new MyAdapter(this, mList);
recyclerView.setAdapter(adapter);
}
private List<String> getList(){
List<String> list = new ArrayList<>();
for (int i = 0; i < 20; i++) {
list.add(i+"");
}
return list;
}
}
注意到与ListView
不同的一点就是,需要设置布局管理器用于设置条目的排列样式,可以是垂直排列或者水平排列。其余的都是类似的处理。
可以看见效果:
2.1.3 案例添加分割线
谷歌目前没有提供默认的分割线,这就需要我们继承RecyclerView.ItemDecoration
来自定义分割线。然后使用recyclerView.addItemDecoration()
来加入分割线。
package com.example.myapplication;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class VerticalDividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable divider;
public VerticalDividerItemDecoration(Context context){
final TypedArray a = context.obtainStyledAttributes(new int[]{android.R.attr.listDivider});
divider = a.getDrawable(0);
a.recycle();
}
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
RecyclerView v = new RecyclerView(parent.getContext());
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
}
上面的代码是我从Android
进阶之光中抄的。然后使用就是:
recyclerView.addItemDecoration(new VerticalDividerItemDecoration(MainActivity.this));
可以看见效果:
2.1.4 案例添加点击事件
列表中条目的点击事件需要我们自己来定义。这种方式需要结合接口来进行编程处理,比较灵活。有点类似javascript
中定义的回调函数处理。我们对Item
的点击事件,也就是放置在Adapter
中进行处理,然后设置接口函数,添加添加点击回调
,然后在MainActivity
中进行实例化该接口对象即可。
package com.example.myapplication;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter{
private List<String> mList;
private Context context;
public MyAdapter(Context context, List<String> mList){
this.context = context;
this.mList = mList;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.recycleview_item, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
final MyViewHolder myViewHolder = ((MyViewHolder) holder);
myViewHolder.tv.setText(mList.get(position));
if(onItemClickListener!=null){
// 点击
myViewHolder.tv.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
onItemClickListener.onItemClick(myViewHolder.tv, position);
}
});
// 长按
myViewHolder.tv.setOnLongClickListener(new View.OnLongClickListener(){
@Override
public boolean onLongClick(View view) {
onItemClickListener.onItemLongClick(myViewHolder.tv, position);
return false;
}
});
}
}
@Override
public int getItemCount() {
return mList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView tv;
public MyViewHolder(View view){
super(view);
tv = (TextView) view.findViewById(R.id.tv_item);
}
}
private OnItemClickListener onItemClickListener;
public interface OnItemClickListener{
void onItemClick(View veiw, int position);
void onItemLongClick(View view, int position);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
}
MainActivity.java
中:
adapter = new MyAdapter(this, mList);
adapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
@Override
public void onItemClick(View veiw, int position) {
Toast.makeText(MainActivity.this, "点击了第"+(position+1)+"条", Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(MainActivity.this, "长按了第"+(position+1)+"条", Toast.LENGTH_SHORT).show();
}
});
recyclerView.setAdapter(adapter);