java listview用法_ListView浅析(一)——基本用法及常见问题总结

一、适用场景

ListViewListview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局;由于屏幕尺寸的限制,不能一次性展现所有条目,用户需要上下滚动查看所有条目。滚出显示区域的条目将被回收并在下一个条目可见时复用。(下面是一张很经典的图片)

2f59266268b7

可以看到,在这个屏幕中可以显示7条Item。当Item 1滑出屏幕外之后,就会进入到一个缓冲区(Recycler)中以便新的条目可见时(屏幕底部又滑出了新的Item)进行复用。

一个ListView通常有两个职责,一是将数据填充到特定布局,二是处理用户的选择点击事件;一个ListView的创建需要创建3个元素,(1)ListView中的每一列的View布局,(2)填入View数据或者图片,(3)连接View与ListView的适配器,下面我们就来具体聊聊ListView中的那些事。

二、适配器

什么是适配器?适配器(Adapter)是一个连接数据与AdapterView(ListView就是一个典型的AdapterView)的桥梁,实现数据与AdapterView的分离设置,使的AdapterView与数据的绑定更加方便,下面是Android提供的几个常见的Adapter。

ArrayAdapter 用来绑定一个数组,支持泛型操作

SimpleAdapter 用来绑定在xml中定义的控件对应的数据

BaseAdapter 通用的基础适配器

1.ArrayAdapter

我们先来看看他的继承结构:

java.lang.Object

↳ android.widget.BaseAdapter

↳ android.widget.ArrayAdapter

可以看到ArrayAdapter是继承自BaseAdapter这个大boss的,谷歌官网中对其的说明为:

A concrete BaseAdapter that is backed by an array of arbitrary objects. By default this class expects

that the provided resource id references a single TextView. If you want to use a more complex layout, use

the constructors that also takes a field id. That field id should reference a TextView in the larger

layout resource.

一种可以被任意对象填充的实类BaseAdapter。默认的,这个类期望提供的资源ID指向一个单一的TextView,如果你想用一个

更加复杂layout,用这个构造器也只是持有一个ID指向更大的Layout资源中的一个TextView。

也就是说,ArrayAdapter(数组适配器)一般用于显示一行文本信息,因此更多的指向的是一个简单的TextView。我们比较常见的构造方法是:

ArrayAdapter (Context context, int resource, List objects)

context Context: The current context.

resource int: The resource ID for a layout file containing a TextView to use when instantiating views.

objects List: The objects to represent in the ListView.

从官方对该方法的说明中可以看出,resource是“一个包含TextView的Layout”,实际上我们在使用的时候更多的直接就是一个TextView,

更加复杂的布局直接继承BaseAdapter(这个后面会讲)

objects是我们早ListView中药呈现的东西,这里可以传入泛型类,那么就可以传入很多我们自定义的Bean数据,非常的方便(具体看下边实例)

我们先看一段网上的代码,非常的简单:

public class ArrayListActivity extends Activity {

private ListView listView;

private String[] adapterData;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.array_list_layout);

listView = (ListView) findViewById(R.id.array_list);

/* 我们要在listView上面显示的数据,放到一个数组中 */

adapterData = new String[] { "Afghanistan", "Albania", "Algeria",

"American Samoa", "Andorra", "Angola", "Anguilla",

"Antarctica", "Antigua and Barbuda", "Argentina", "Armenia",

"Aruba", "Australia", "Austria", "Azerbaijan", "Bahrain",

"Bangladesh", "Barbados", "Belarus", "Belgium", "Belize",

"Benin", "Bermuda", "Bhutan", "Bolivia",

"Bosnia and Herzegovina", "Botswana", "Bouvet Island" };

/* 下面就是对适配器进行配置了 */

ArrayAdapter arrayAdapter = new ArrayAdapter( ArrayListActivity.this, android.R.layout.simple_list_item_1, adapterData);

/* 设置ListView的Adapter */

listView.setAdapter(arrayAdapter);

}

}

这应该是我们在开发中遇到的最简单的ListView使用了,这里我们用到的适配器是ArrayAdapter( ArrayListActivity.this, android.R.layout.simple_list_item_1, adapterData);

由于泛型中传入的是String类型,因此后面我们传入的数据(adapterData)是一个String类型的数组,这个要对的上号。

另外android.R.layout.simple_list_item_1是一个Android SDK中自带的布局,非常简单,就是一行TextVeiew文本。

上述例子中我们只是简单的呈现了一个静态数组,下面我们可以对这块代码加以修改,以动态的添自定义的数组:

首先我们自定义一个Bean类:

public class Restaurant {

private String name="";

private String address="";

public String getName() {

return(name);

}

public void setName(String name) {

this.name=name;

}

public String getAddress() {

return(address);

}

public void setAddress(String address) {

this.address=address;

}

@Override

public String toString() {

return("名称:"+getName()+";"+" 地址:"+getAddress());

}

}

然后我们对上面一段代码中ArrayAdapter arrayAdapter = new ArrayAdapter(

ArrayListActivity.this, android.R.layout.simple_list_item_1, adapterData);

做出如下修改:

ArrayAdapter arrayAdapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,restaurantList);

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

private Button save_btn;

private EditText name_edt;

private EditText adress_edt;

private ListView listView;

private List restaurantList;

private ArrayAdapter arrayAdapter;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView();

}

public void initView(){

name_edt = (EditText) findViewById(R.id.name_edt);

adress_edt = (EditText) findViewById(R.id.adress_edt);

listView = (ListView)findViewById(R.id.list);

save_btn = (Button)findViewById(R.id.save_btn);

save_btn.setOnClickListener(this);

restaurantList = new ArrayList<>();

arrayAdapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,restaurantList);

listView.setAdapter(arrayAdapter);

}

@Override

public void onClick(View v) {

switch(v.getId()){

case R.id.save_btn:

Restaurant restaurantData = new Restaurant();

restaurantData.setName(name_edt.getText().toString());

restaurantData.setAddress(adress_edt.getText().toString());

arrayAdapter.add(restaurantData); //每个增加的条目都会添加到适配器里面

break;

}

}

}

布局文件如下:

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/activity_main"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

tools:context="com.example.dell.arrayadpaterdome.MainActivity">

android:layout_width="match_parent"

android:layout_height="300dp"

android:id="@+id/list">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:id="@+id/name_edt"/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:id="@+id/adress_edt"/>

android:text="添加"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:id="@+id/save_btn" />

我们在xml布局中定义了两个EditText,用于获取我们输入的数据,分别是饭店的名字和地址。这里要注意的是adapter.add(r)这个方法,

类似于ArrayList(动态数组)中的.add()方法该方法用于在ArrayAdapter中动态的添加一条条数据,

下面我们来仔细分析一下上面的代码:我们定义一个实体类来存放我们所需要读取的数据,并在MainActivity中定义了一个动态数组List restaurantList = new ArrayList<>();表示restaurantList这个数组中只能存放实体类Restaurant的对象,这里需要注意的是我们在写实体类的时候一定要在最后复写toString()方法并在其中return我们需要返回的数据(原因待会讲)。

之后我们定义了一个ArrayAdapter arrayAdapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,restaurantList);其中泛型表明这个arrayAdapter中的数据只能是Restaurant这个实体类的对象,这也就是为什么我们定义restaurantList的原因。(this,android.R.layout.simple_list_item_1,restaurantList)这三个参数分别表示:this——当前的上下文(可以暂时粗略的理解为当前类) ; android.R.layout.simple_list_item_1——Android sdk中提供的一个族简单的用于适配ArrayAdapter的布局,就是一个TextView,我们可以点开源码看一下(本段末);最后一个参数restaurantList就是我们需要在ListView中呈现的数据内容。

android:id="@android:id/text1"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:textAppearance="?android:attr/textAppearanceListItemSmall"

android:gravity="center_vertical"

android:paddingStart="?android:attr/listPreferredItemPaddingStart"

android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"

android:minHeight="?android:attr/listPreferredItemHeightSmall" />

这里要着重说的是最后一个参数,注意他返回的是Restaurant实体类的对象,对象,对象!!!那么我们不可能把一个对象展现在ListView中吧?那ListView中展示的是什么呢?我们点开arrayAdapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,restaurantList);的源码,可以看到:

@Override

public @NonNull View getView(int position, @Nullable View convertView,

@NonNull ViewGroup parent) {

return createViewFromResource(mInflater, position, convertView, parent, mResource);

}

private @NonNull View createViewFromResource(@NonNull LayoutInflater inflater, int position,

@Nullable View convertView, @NonNull ViewGroup parent, int resource) {

final View view;

final TextView text;

if (convertView == null) {

view = inflater.inflate(resource, parent, false);

} else {

view = convertView;

}

try {

if (mFieldId == 0) {

// If no custom field is assigned, assume the whole resource is a TextView

text = (TextView) view;

} else {

// Otherwise, find the TextView field within the layout

text = (TextView) view.findViewById(mFieldId);

if (text == null) {

throw new RuntimeException("Failed to find view with ID "

+ mContext.getResources().getResourceName(mFieldId)

+ " in item layout");

}

}

} catch (ClassCastException e) {

Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");

throw new IllegalStateException(

"ArrayAdapter requires the resource ID to be a TextView", e);

}

final T item = getItem(position);

if (item instanceof CharSequence) {

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值