Recyclerview
RecyclerView可以说是ListView的增强版,它解决了ListView很多的不足。
目前 Android 官方更推荐使用RecyclerView。
由于RecyclerView是新增控件,位于support库,因此需要引入。
implementation 'com.android.support:recyclerview-v7:27.1.1'
主界面布局
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.activity.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_demo"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
RecyclerView 的 Item 要显示的布局,和上面List View的布局一致
Model也一致
Adapter配置
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private ArrayList<UserModel> mList;
public void setData(ArrayList<UserModel> list) {
this.mList = list;
notifyDataSetChanged();
}
public void insertData(UserModel user, int position) {
mList.add(position, user);
notifyItemInserted(position);
}
public void removeData(int position) {
mList.remove(position);
notifyItemRemoved(position);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(
R.layout.item_lv_cell,
parent,
false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
final UserModel userModel = mList.get(position);
holder.ivHead.setImageResource(R.drawable.ic_launcher_background);
holder.tvName.setText(userModel.getName());
holder.tvAge.setText(userModel.getAge() + "");
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mIOnItemClickListener != null)
mIOnItemClickListener.onItemClick(v, userModel, position);
}
});
}
@Override
public int getItemCount() {
return mList != null ? mList.size() : 0;
}
class ViewHolder extends RecyclerView.ViewHolder {
private ImageView ivHead;
private TextView tvName, tvAge;
public ViewHolder(View itemView) {
super(itemView);
ivHead = itemView.findViewById(R.id.iv_head);
tvName = itemView.findViewById(R.id.tv_name);
tvAge = itemView.findViewById(R.id.tv_age);
}
}
//RecyclerView不提供点击事件需要自定义
public interface IOnItemClickListener<T> {
void onItemClick(View v, T t, int position);
}
private IOnItemClickListener mIOnItemClickListener;
public void setOnItemClickListener(IOnItemClickListener listener) {
this.mIOnItemClickListener = listener;
}
}
public class MainActivity extends AppCompatActivity {
private RecyclerView mRvDemo;
private ArrayList<UserModel> mList;
private RecyclerAdapter mRvAdp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
loadData();
initEvent();
}
private void initEvent() {
mRvAdp.setOnItemClickListener(
new RecyclerAdapter.IOnItemClickListener<UserModel>() {
@Override
public void onItemClick(View v, UserModel userModel, int position) {
Toast.makeText(v.getContext(),
userModel.getName(),
Toast.LENGTH_SHORT).show();
}
});
}
private void loadData() {
mList = new ArrayList<>();
mRvAdp = new RecyclerAdapter();
for (int i = 1; i <= 20; i++) {
mList.add(new UserModel("Name" + i, i));
}
mRvAdp.setData(mList);
mRvDemo.setAdapter(mRvAdp);
}
private void initView() {
mRvDemo = findViewById(R.id.rv_demo);
mRvDemo.setLayoutManager(new LinearLayoutManager(
this,
LinearLayoutManager.VERTICAL,
false));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.insert:
if (mRvAdp != null)
mRvAdp.insertData(
new UserModel("Insert", 18),
mList.size());
break;
case R.id.delete:
if (mRvAdp != null)
mRvAdp.removeData(mList.size() - 1);
break;
}
return super.onOptionsItemSelected(item);
}
}
Recycler多布局实现
首先准备两个布局,其中两个布局内控件的ID相同,只是摆放位置不同。
重写RecyclerView.Adapter的getItemViewType方法,getItemViewType的返回值对应onCreateViewHolder(int viewType)
private static final int ITEM_LEFT = 0;
private static final int ITEM_RIGHT = 1;
@Override
public int getItemViewType(int position) {
if (position % 2 == 0) {
return ITEM_LEFT;
}
return ITEM_RIGHT;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mContext = parent.getContext();
LayoutInflater mInflater = LayoutInflater.from(mContext);
View view;
if (viewType == ITEM_LEFT) {
view = mInflater.inflate(R.layout.item_home_cardview, parent, false);
} else {
view = mInflater.inflate(R.layout.item_home_cardview2, parent, false);
}
return new ViewHolder(view);
}
Adapter封装
分析通用实现,可以发现
1. 集合的数据类型与布局,不能写死
集合的数据类型可以通过泛型处理,具体的布局样式,可以通过构造方法传入。
2. ViewHolder是通用的
提取ViewHolder,用于findView和设置整体点击事件
3. onBindViewHolder()处理的Item,需要暴露出去
onBindViewHolder() 需要暴露出去,可以用抽象方法暴露出去。
1. 封装Adapter
构建成抽象类,将onBindViewHolder()暴漏出去
构建泛型来传递数据
public abstract class BaseAdapter<T, H extends BaseViewHolder>
extends RecyclerView.Adapter<BaseViewHolder> {
protected List<T> mDatas;
private int mLayoutResId;
//设置事件回调
private OnItemClickListener mOnItemClickListener;
//填充数据,布局
public BaseAdapter(List<T> mDatas, int layoutResId) {
this.mDatas = mDatas;
this.mLayoutResId = layoutResId;
}
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(mLayoutResId, parent, false);
return new BaseViewHolder(view, mOnItemClickListener);
}
//暴露出去用来绑定数据
public abstract void convert(H holder, T t, int position);
@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
T t = mDatas.get(position);
convert((H) holder, t, position);
}
@Override
public int getItemCount() {
return mDatas != null ? mDatas.size() : 0;
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.mOnItemClickListener = listener;
}
public void clear() {
if (mDatas == null || mDatas.size() <= 0)
return;
for (Iterator it = mDatas.iterator(); it.hasNext(); ) {
T t = (T) it.next();
int position = mDatas.indexOf(t);
it.remove();
notifyItemRemoved(position);
}
}
/**
* 从列表中删除某项
*/
public void removeItem(T t) {
int position = mDatas.indexOf(t);
mDatas.remove(position);
notifyItemRemoved(position);
}
public void addData(int position, List<T> list) {
if (list != null && list.size() > 0) {
for (T t : list) {
mDatas.add(position, t);
notifyItemInserted(position);
}
}
}
public void addData(List<T> datas) {
addData(0, datas);
}
}
2. 构建加载数据的ViewHolder,绑定点击事件
public class BaseViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
private SparseArray<View> views;
//Adapter提供的点击事件
private BaseAdapter.OnItemClickListener mOnItemClickListener;
public BaseViewHolder(View itemView,
BaseAdapter.OnItemClickListener onItemClickListener) {
super(itemView);
this.views = new SparseArray<>();
//注册点击事件
itemView.setOnClickListener(this);
this.mOnItemClickListener = onItemClickListener;
}
@Override
public void onClick(View view) {
if (mOnItemClickListener != null)
mOnItemClickListener.onItemClick(view, getLayoutPosition());
}
/**
* 注册View控件
*/
protected <T extends View> T registerView(int viewId) {
View view = views.get(viewId);
if (view == null) {
//itemView 继承ViewHolder的父类成员
view = itemView.findViewById(viewId);
views.put(viewId, view);
}
return (T) view;
}
/**
* 获取View
*
* @param viewId
* @return
*/
public View getView(int viewId) {
return registerView(viewId);
}
/**
* 避免findView时强转
*/
public TextView getTextView(int viewId) {
return registerView(viewId);
}
public CheckBox getCheckBox(int viewId) {
return registerView(viewId);
}
public Button getButton(int viewId) {
return registerView(viewId);
}
public ImageView getImageView(int viewId) {
return registerView(viewId);
}
}
3. 封装一层,少写一个泛型
public abstract class SimpleAdapter<T> extends BaseAdapter<T, BaseViewHolder> {
public SimpleAdapter(List<T> mDatas, int layoutResId) {
super(mDatas, layoutResId);
}
}
4. 调用
private void initData() {
mUserModules = new ArrayList<>();
UserModule userModule;
for (int i = 1; i < 20; i++) {
userModule = new UserModule();
userModule.setUserHeadIcon(R.mipmap.ic_launcher);
userModule.setUserName("UserName" + i);
userModule.setUserInfo("UserInfo" + i);
mUserModules.add(userModule);
}
SimpleAdapter simpleAdapter = new SimpleAdapter<UserModule>(
mUserModules,
R.layout.item_user_info) {
@Override
public void convert(BaseViewHolder holder,
UserModule userModule,
int position) {
if (position == 1)
holder.getTextView(R.id.tv_user_info).setText("Test");
}
};
simpleAdapter.setOnItemClickListener(new BaseAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Log.i(TAG, "onItemClick: " + position);
}
});
mRecyclerView.addItemDecoration(new MyDivider(MainActivity.this,
LinearLayoutManager.VERTICAL));
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(simpleAdapter);
}