android两层控件,Android 学习笔记之ListView二层封装

本文介绍了如何对Android的ListView数据适配器进行封装,通过创建自定义的BaseAdapter父类和ViewHolder基类,实现了getCount(), getItem(), getItemId(), getView()等方法的通用化,简化了ListView在项目中的重复代码,提高了代码的复用性和可维护性。
摘要由CSDN通过智能技术生成

ListView作为Android 开发中使用最多的控件之一,相信很多人对他的用法应该都不陌生,最主要就是,定义好每个Itme的布局,给其设置一个数据适配器(Adapter)就完事,下面来回顾一下ListVew的一般用法。

/**

* Created by 毛麒添 on 2017/1/18 0018.

*/

public class MainActivity extends AppCompatActivity {

private ArrayListdata;

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

data=new ArrayList();

for (int i=0;i<30;i++){

data.add("listView数据"+i);

}

ListView listView=new ListView(getContext());

listView.setAdapter(new MyAdapter());

}

class MyAdapter extends BaseAdapter{

@Override

public int getCount() {

return data.size();

}

@Override

public String getItem(int position) {

return data.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder viewHolder=null;

if(convertView==null){

//1.加载布局文件

convertView= MyUIUtils.inflate(R.layout.list_home_item);

viewHolder=new ViewHolder();

//2.初始化控件

viewHolder.textView= (TextView) convertView.findViewById(R.id.tv_test);

//3.打一个标记tag

convertView.setTag(viewHolder);

}else {

viewHolder= (ViewHolder) convertView.getTag();

}

//4.根据数据来刷新界面

viewHolder.textView.setText(getItem(position));

return convertView;

}

}

static class ViewHolder{

TextView textView;

}

}

如果我们只是给一个ListView设置数据,则写一个上面的数据适配器无可厚非,但是如果在一个项目中有许多的ListView,则给每个ListView都写一个数据适配器,则上面的适配器中必须实现 getCount() getItem(),getItemId(),getView() 方法对每个都要写一次,这样多几次应该会感觉很烦,那有没有可能对这几个方法抽取出来,进行封装,简便要写多个 ListView 数据适配器的烦恼呢?答案是肯定的,下面就开始对ListView的数据适配器进行两层封装,以达到我们的目的。

ListView的第一层封装

首先可以对最简单的 getCount(),getItem(),getItemId() 方法进行封装,创建我们自己的父类Adapter,让其继承BaseAdpter.其中getCount(),getItem(),getItemId() 最后设置的返回值一般都是依赖一个List数组,但这个父类是我们定义的,则可以用构造方法来传入List数组,而这时候问题又来了,数组的泛型我们也不知道,这时候可以把泛型定义为Object,但是当我们传入数据的时候则就要将 Object 强转为我们传入数据对应的泛型,其实这里可以直接传入一个大写字母(ArrayList 源码中也是如此定义),代表传入的数据泛型,下面上代码:

/**

* Created by 毛麒添 on 2017/1/21 0021.

* 对Adapter的封装 简化数据适配器的设置

*/

public class MyBaseAdapter extends BaseAdapter {

private ArrayListdata; //T代表泛型,传入的是什么类型就是什么类型

public MyBaseAdapter(ArrayListdata){

this.data=data;

}

@Override

public int getCount() {

return data.size();

}

@Override

public T getItem(int position) {

return data.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

return null;

}

}

这样当我们使用 MyBaseAdapter 来作为数据适配器的父类,就不用再写 getCount(),getItem(),getItemId()这三个方法了,OK,完成对 ListView 的第一层封装,但是这个我们自定义的父类方法还没完成,接下来就是对getView()的封装。

ListView的第二层封装

前面只是对 getCount(), getItem() ,getItemId() 等方法进行了封装,接下来便是对 getView() 方法来进行封装,以前我们写ListView数据适配器的getView()方法一般都是以下四个步骤:

1.加载布局文件

2.初始化控件

3.打一个标记tag

4.根据数据来刷新界面

无论如何,这四个步骤都是要实现的。而这四个步骤中,都在其中有ViewHolder帮助类来帮助我们实现,所以我们可以考虑在将这四个步骤抽取成为一个工具类,也就是自己定义一个父类holder,在其中实现这几个步骤,进一步进行封装。

import android.view.View;

/**

* Created by 毛麒添 on 2017/1/21 0021.

* getView(); ViewHolder封装

*/

public abstract class BaseHolder {

private final View view;//ListView的item根布局View对象

private T data;

/**获取这个父类holder,就是执行

* 1.加载布局文件

* 2.初始化控件

* 3.打一个标记tag

* 这三个步骤

*/

public BaseHolder(){

view = initView();

//3.打一个标记tag,也就是当前的BaseHolder

view.setTag(this);

}

//设置当前Item的数据

public void setData(T data){

this.data=data;

//获取数据直接将其传递给子类刷新数据

RefreshView(data);

}

//获取当前Item的数据

public T getData(){

return data;

}

/**

* 本身并不知道需要加载什么样的布局和控件,让子类去实现

* 1.加载布局文件

* 2.初始化控件

* @return 返回相应的item根布局View对象

*/

public abstract View initView();

/**

* 获取Item布局对象

* @return 返回item布局对象

*/

public View getItemView(){

return view;

}

//4.根据数据来刷新界面,本身并不知道是什么数据,让子类去实现

public abstract void RefreshView(T data);

}

代码中,首选我们实现第一、二个步骤,但是这只是所有布局Item的父类,并不知道每个ListView的Item需要展现什么样的布局,所以定义一个抽象方法 initView()让子类去实现布局的加载与控件的初始化,而且在初始化父类的时候,也就是在构造方法中就调用该方法获取对应的Item的View对象,既然获取了对应的View对象,并且该类就是四个步骤ed封装,也就可以给其设置一个Tag,到此,前三个步骤已经搞定,最后一个步骤是给Item布局设置刷新数据,同理也是定义成抽象方法RefreshView(T data)让子类去实现,再加上两个数据set和get方法。

至此,四个步骤封装完成。

接下来搞个子类继承BaseHolder实现未实现的方法,指定特定的ListView的Item需要展示的数据。

/**

* Created by 毛麒添 on 2017/1/21 0021.

* BaseHolder子类

*/

public class MyHolder extends BaseHolder {

private TextView textView;

@Override

public View initView() {

//步骤1.加载布局文件

View view= MyUIUtils.inflate(R.layout.list_home_item);

//步骤2.初始化控件

textView = (TextView) view.findViewById(R.id.tv_test);

return view;

}

//步骤4刷新页面数据

@Override

public void RefreshView(String data) {

textView.setText(data);

}

}

现在,就可以把上面未完成的MyBaseAdapter父类完整实现:

public abstract class MyBaseAdapter extends BaseAdapter {

private ArrayListdata; //T代表泛型,传入的是什么类型就是什么类型

public MyBaseAdapter(ArrayListdata){

this.data=data;

}

@Override

public int getCount() {

return data.size();

}

@Override

public T getItem(int position) {

return data.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

BaseHolder baseHolder;

if(convertView==null){

/**

* 1.加载布局文件

* 2.初始化控件

* 3.打一个标记tag

*/

baseHolder=getHolder();//由子类返回具体对象

}else {

baseHolder= (BaseHolder) convertView.getTag();

}

//4.根据数据来刷新界面

baseHolder.setData(getItem(position));

//返回item对象

return baseHolder.getItemView();

}

//返回当前页面的holder对象,必须由子类去实现

public abstract BaseHolder getHolder();

}

在上面的getView()方法,只要初始化BaseHolder的对象,就已经完成了四个步骤中的前三个,第四个步骤只要将数据设置给BaseHolder的对象也就完成了,对象的初始化也是需要继承该方法的子类去实现,因为每个LsitView的所展示的Item是不同的。

终于,对ListView二层封装已经完成,下面我们来使用一发:

public class MainActivity extends AppCompatActivity {

private ArrayListdata;

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

data=new ArrayList();

for (int i=0;i<30;i++){

data.add("listView数据"+i);

}

ListView listView=new ListView(getContext());

listView.setAdapter(new MyAdapter());

}

class MyAdapter extends MyBaseAdapter{

public MyAdapter(ArrayList data) {

super(data);

}

@Override

public BaseHolder getHolder() {

return new MyHolder();

}

}

好了,以后我们在使用ListView,只需要写一个类继承BaseHolder,然后按照我们的数据获取初始化布局和控件,然后设置数据,只需要在数据适配器中初始化该类就完事。

最后

抽取相同的部分,封装,应该相当于搭建了一个小框架吧,也让我对适配器有了更进一步的认识。如果有哪些地方写得不对,欢迎大家给我提出来纠正,让我们一同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值