Android中ListView的使用


1、主要概念

ListView用於將大數據集以列表的形式展示。

ListView可以看成一個容器,它有如下繼承鏈:

View <- ViewGroup <- AdapterView <- AbsListView <- ListView

可見 ListView繼承自AdapterView, 而AdapterView的作用就是為ListView提供數據。
主要的API:

listView.setAdapter(adapter實例)

我們通常用的Adapter有如下幾個:BaseAdapter, CursorAdapter, ArrayAdapter, SimpleAdapter.它們有如下的繼承關系:

Adapter <- ListAdapter <- BaseAdapter

SimpleAdapterCursorAdapterArrayAdapter都是BaseAdapter的子類。

2、使用方法
  • Activity布局文件中加入一個ListView組件
<ListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:entries="@array/listItems"></ListView>

這里entries用於指定一個數組來渲染ListView,它定義在strings.xml中,內容如下:

<resources>
    <string-array name="listItems">
        <item>orange</item>
        <item>apple</item>
        <item>banana</item>
        <item>pear</item>
        <item>watermelon</item>
        <item>lemon</item>
        <item>peach</item>
        <item>strawberry</item>
    </string-array>
</resources>

到這里,運行項目已經可以看到列表項了。但這種方式只是靜態的給ListView添加數據,有很大的局限性。基本不用。下面通過給ListView設置Adapter提供數據。

  • 刪除上面的entries屬性, 修改Activity的內容
public class ArrayAdapterActivity extends AppCompatActivity {

    private String[] items = new String[]{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_array_adapter);
        ListView lv = findViewById(R.id.array_adapter_list_view);
        //可以這里為ListView設置了一個Adapter
        //並且指定了一個array_adapter_list_item.xml的布局文件,因此要新建一個這樣的布局文件
        //這個布局文件限制了一個數據項的顯示形式,即一行數據如何展示
        //該布局文件的根標簽為TextView
        //然后用上面的定義的字符串數組填充每一個TextView
        lv.setAdapter(new ArrayAdapter<>(this, R.layout.array_adapter_list_item, items));
    }
}

這樣,運行程序ListView顯示的便是數組中定義的值了。

  • 不同的Adapter使用方式基本一致

下面是SimpleAdapter的使用:

lv.setAdapter(new SimpleAdapter(context, data, resource, from, to));

1.context: 當前上下文

2.data: List<Map<String, ?>>類型的數據集

3.resource:單個數據項的布局文件

5.from:data中map的各個key

6.to: 將key對應的值映射到數據項布局文件的某個組件
看個例子:

public class SimpleAdapterActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple_adapter);
        ListView lv = findViewById(R.id.simple_adapter_list_view);
        Map<String, Object> student1 = new HashMap<>();
        student1.put("username", "jack");
        student1.put("gender", "male");
        student1.put("age", 33);
        Map<String, Object> student2 = new HashMap<>();
        student2.put("username", "nacy");
        student2.put("gender", "female");
        student2.put("age", 13);
        List<Map<String, Object>> students = new ArrayList<>();
        students.add(student1);
        students.add(student2);
        //from對應map的key
        String[] from = new String[]{"username", "gender", "age"};
        //to對應單行數據項布局文件中組件的id
        int[] to = new int[]{R.id.simple_adapter_username, R.id.simple_adapter_gender, R.id.simple_adapter_age};
        lv.setAdapter(new SimpleAdapter(this, students, R.layout.simple_adapter_list_item, from, to));
    }
}

單行數據項布局文件:

<?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="match_parent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/simple_adapter_username"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"></TextView>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="3"
        android:orientation="vertical">

        <TextView
            android:id="@+id/simple_adapter_gender"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"></TextView>

        <TextView
            android:id="@+id/simple_adapter_age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"></TextView>
    </LinearLayout>

</LinearLayout>

3、BaseAdapter的使用

BaseAdapter作為一個抽象類,比前幾種Adapter使用起來更靈活。

下面是一個例子:

創建一個類繼承BaseAdapter

public class MyBaseAdapter extends BaseAdapter {

    //根據當前上下文將一個布局文件加載到內存,實例化為對象的一個類
    private LayoutInflater layoutInflater;

    public MyBaseAdapter(Context context) {
        layoutInflater = LayoutInflater.from(context);
    }

    //決定數據項的個數
    @Override
    public int getCount() {
        return 20;
    }

    //指定位置的數據項
    @Override
    public Object getItem(int position) {
        return null;
    }

    //指定位置數據項的索引
    @Override
    public long getItemId(int position) {
        return 0;
    }

    //容納當前數據項布局文件的一個類
    private class ViewHolder {
        public ImageView header;
        public TextView username;
    }

    //手機在滾動屏幕時,超出屏幕之外的ViewItem要被移除
    //如果有10000個ViewItem,那么getView方法就要調用10000次,加載布局文件10000次,然后創建ViewItem,這是相當耗資源的
    //為了提高性能,就需要對移除的ViewItem進行復用,每次滾動屏幕移除的ViewItem就是convertView
    //因此每次調用方法時,都要對convertView判空,如果為空才去加載布局文件,創建新的View,否則進行復用。
    //這里的ViewHolder相當於一個容器,承載了一個ViewItem中所有的組件,避免了每次都要findViewById
    //一次findViewById之后,通過setTag方法將其設置到convertView中,下次就不用再查找了
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = layoutInflater.inflate(R.layout.base_adapter_list_item, null);
            holder = new ViewHolder();
            holder.header = convertView.findViewById(R.id.iv_header);
            holder.username = convertView.findViewById(R.id.tv_username);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.header.setImageResource(R.drawable.ic_launcher_foreground);
        holder.username.setText("這是第" + position + "項");
        return convertView;
    }
}

數據項布局文件:

<?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="match_parent"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/iv_header"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="#008080"></ImageView>

    <TextView
        android:id="@+id/tv_username"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"></TextView>
</LinearLayout>

Activity文件

public class BaseAdapterActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base_adapter);
        ListView lv = findViewById(R.id.base_adapter_list_view);
        lv.setAdapter(new MyBaseAdapter(this));
        lv.setOnItemClickListener(new ListView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(BaseAdapterActivity.this, "點擊" + position, Toast.LENGTH_SHORT).show();
            }
        });

        lv.setOnItemLongClickListener(new ListView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(BaseAdapterActivity.this, "長按" + position, Toast.LENGTH_SHORT).show();
                return true;
            }
        });
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM