前言
ListView与Adapter是Android一组很常用的组合,本篇博客旨在探究它们的各种应用场景:
1、自定义万用Adapter+自定义同布局不可交互ListView(简单)
2、自定义万用Adapter+自定义不同布局可交互ListView(略复杂)
自定义万能用Adapter
一、准备内容:
1.自定义ViewHolder;
2.自定义Abstract CommonAdapter(extends BaseAdapter)
3.自定义Entity用于存储数据(复杂情况下可以对多种数据类型进行封装)
4.自定义回调接口或抽象类
二、CommonAdapter需要数据:
1.Context context;--上下文不要解释
2.List<Entity>;--Entity里可封装多种数据类型
三、CommonAdapter提供调用方法(不包含BaseAdapter的抽象方法):
1.abstract void convert;--获取item组件的抽象方法,子类继承实现
2.abstract int getLayoutId;--获取item布局的抽象方法,子类继承实现,可用于获取不同布局
四、自定义ViewHolder提供给CommonAdapter的调用方法
1.getViewHolder;--获取ViewHolder实例
2.getmContertView;--返回已加载ContertView实例
3.getView;--获取item内组件
五、子类XXXAdapterCommonAdapter
1.实现抽象方法;
2.设置回调onXXXListener;
六、演示效果
七、直接贴代码
1.FirstListActivity:
(1)activity_firstlist:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="heros.example.com.mylistview.MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="20dp"
android:text="自定义万能用Adapter" />
<ListView
android:id="@+id/firstlist"
android:layout_marginTop="20dp"
android:layout_below="@+id/textView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</RelativeLayout>
(2)FirstListActivity.class
public class FirstListActivity extends AppCompatActivity {
List<MyEntity> entityList;
MyEntity firstEntity;
FirstAdapter mAdapter;
@BindView(R.id.firstlist)
ListView firstlist;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_firstlist);
ButterKnife.bind(this);
setItem();
}
private void setItem() {
//构造数据
entityList = new ArrayList<MyEntity>();//空指针高发处
for (int i=0; i < 20; i++) {
firstEntity = new MyEntity(R.layout.item_fistlist,R.drawable.book,
"神经网络与深度学习","电子工业出版社","价格:¥"+(40+i));
entityList.add(firstEntity);
}
//创建adapter
mAdapter = new FirstAdapter(this,entityList, mClickListener, onItemClickListener);
firstlist.setAdapter(mAdapter);
//设置回调
firstlist.setOnItemClickListener(onItemClickListener);
}
//Item响应回调
AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(FirstListActivity.this, "这一本:¥" + (40+position),
Toast.LENGTH_SHORT).show();
}
};
//控件响应回调
MyClickListener mClickListener = new MyClickListener() {
@Override
public void myOnClick(int position, View view) {
Toast.makeText(FirstListActivity.this, "这一本是:神经网络与深度学习",
Toast.LENGTH_SHORT).show();
}
public void onClick(View v) { //先响应onclick(权限高) 可以将响应移交出去
myOnClick((Integer) v.getTag(), v);
}
};
}
2.自定义适配器
(1)FirstAdapter.class继承自CommonAdapter.class
public class FirstAdapter extends CommonAdapter {
//这里声明了两种回调响应
//OnItemClickListenerListView自带属性
AdapterView.OnItemClickListener onItemClickListener;
//MyClickListener自定义响应接口(也可使用抽象类回调)
MyClickListener mClickListener;
public FirstAdapter(Context context, List<MyEntity> list, MyClickListener myClickListener,
AdapterView.OnItemClickListener onItemClickListener) {
//回调父类构造方法
super(context, list);
this.onItemClickListener = onItemClickListener;
this.mClickListener = myClickListener;
}
//实现父类抽象方法,加载item内组件
@Override
public void convert(ViewHolder mViewHolder, MyEntity mEntity, int position) {
ImageView leftImg = (ImageView) mViewHolder.getView(R.id.leftImg);
TextView tv1 = (TextView) mViewHolder.getView(R.id.itemTv1);
TextView tv2 = (TextView) mViewHolder.getView(R.id.itemTv2);
TextView tv3 = (TextView) mViewHolder.getView(R.id.itemTv3);
leftImg.setImageResource(mEntity.getImgId());
tv1.setText(mEntity.getNameStr());
tv2.setText(mEntity.getIntroduceStr());
tv3.setText(mEntity.getPirceStr());
leftImg.setOnClickListener(mClickListener);
}
//实现父类抽象方法,传送item布局id
@Override
public int getLayoutId(int type) {
return R.layout.item_fistlist;
}
}
(2)抽象类CommomAdapetr.class
public abstract class CommonAdapter extends BaseAdapter {
ViewHolder mViewHolder;
List<MyEntity> mEntityList;
MyEntity mEntity;
LayoutInflater mInflater;
Context context;
public CommonAdapter(Context context, List<MyEntity> list){
this.context = context;
this.mEntityList = list;
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return mEntityList.size();
}
//这里主要返回的类型修改为MyEntity
@Override
public MyEntity getItem(int position) {
return mEntityList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//从MyEntity中获取布局类型号,调用子类实现抽象方法getLayoutId,获取布局int
int layoutId = getLayoutId(getItem(position).getType());
//获取mViewHolder实例
ViewHolder mViewHolder = getViewHolder(context,position,convertView,parent,layoutId);
convert(mViewHolder,getItem(position),position);
//一定注意这里返回的方式,我就遗忘这里不止一次造成空指针
return mViewHolder.getContertView();
}
//获取item组件的抽象方法,子类继承实现
public abstract void convert(ViewHolder mViewHolder, MyEntity mEntity, int position);
//获取item布局的抽象方法,子类继承实现,可用于获取不同布局
public abstract int getLayoutId(int type);
}
(3)ViewHolder.class(也可以写成内部类)
public class ViewHolder {
private SparseArray<View> mView;//存储要获取组件的数组
private int position;
private View mContertView;//装载组件的容器
public ViewHolder(Context context,int position,ViewGroup parent,int layoutId){
this.position = position;
this.mView = new SparseArray<View>();
mContertView = LayoutInflater.from(context).inflate(layoutId,parent,false);
mContertView.setTag(this);
}
public static ViewHolder getViewHolder(Context context,int position, View convertView, ViewGroup parent,int layoutId){
//判断是否首次调用getViewHolder
if(convertView==null){
//首次为空
return new ViewHolder(context,position,parent,layoutId);
}else{
//非首次不为空
return (ViewHolder) convertView.getTag();
}
}
//获取item内组件
public <T extends View> T getView(int viedId){
View view = mView.get(viedId);
if(view==null){
view = mContertView.findViewById(viedId);
mView.put(viedId,view);
}
return (T)view;
}
//返回已加载mContertView实例
public View getContertView(){
return mContertView;
}
}
3.自定义数据存储与回调接口
(1)MyEntity.class
public class MyEntity{
public MyEntity(int type, int imgId, String nameStr, String introduceStr, String pirceStr) {
this.type = type;
this.imgId = imgId;
this.nameStr = nameStr;
this.introduceStr = introduceStr;
this.pirceStr = pirceStr;
}
int type;
int imgId;
String nameStr;
String introduceStr;
String pirceStr;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getNameStr() {
return nameStr;
}
public void setNameStr(String nameStr) {
this.nameStr = nameStr;
}
public int getImgId() {
return imgId;
}
public void setImgId(int imgId) {
this.imgId = imgId;
}
public String getIntroduceStr() {
return introduceStr;
}
public void setIntroduceStr(String introduceStr) {
this.introduceStr = introduceStr;
}
public String getPirceStr() {
return pirceStr;
}
public void setPirceStr(String pirceStr) {
this.pirceStr = pirceStr;
}
public String toString(){
String str = "MyEntity{type:"+Integer.toString(type)+",nameStr:"+nameStr+
",introduceStr"+introduceStr+",pirceStr:"+pirceStr+"}";
return str;
}
}
(2)MyClickListener.class
public interface MyClickListener extends View.OnClickListener {
public void myOnClick(int position, View view);
}
4.程序入口MainActivity
(1)activity_main
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="heros.example.com.mylistview.MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="20dp"
android:text="自定义ListView应用场景探究" />
<Button
android:id="@+id/button1"
android:text="自定义万用Adapter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView"
android:layout_alignLeft="@+id/textView"
android:layout_alignRight="@+id/textView"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"/>
<Button
android:id="@+id/button2"
android:text="自定义不同布局可交互ListView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/button1"
android:layout_alignLeft="@+id/textView"
android:layout_alignRight="@+id/textView"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"/>
</RelativeLayout>
(2)MainActivity.class
public class MainActivity extends AppCompatActivity {
@BindView(R.id.textView)
TextView textView;
@BindView(R.id.button1)
Button button1;
@BindView(R.id.button2)
Button button2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
@OnClick({R.id.button1, R.id.button2})
public void onClick(View view) {
switch (view.getId()) {
case R.id.button1:
Intent i1 = new Intent(MainActivity.this,FirstListActivity.class);
startActivity(i1);
break;
case R.id.button2:
Intent i2 = new Intent(MainActivity.this,SecondListActivity.class);
startActivity(i2);
break;
}
}
}
总结
1.通过abstract CommonAdapter + ViewHolder,仅仅需要FirstAdatper extends CommonAdapter,实现其中两个抽象方法就可以完成基础的adapter功能;
2.使用Entity可以传送多类型数据,并且可以通过设置type实现不同item布局;
3.使用XXXListener可以实现事件回调,自定义回调更好用;
源码连接
# 转载请注明出处!!!