列表控制項 ListView

列表控制項 ListView-基本用法

這是一個非常常用的控制項。

我們的螢幕空間有限,但透過這個控制項,可以在畫面上顯示更多資料。

用手指上下滑動,就能把畫面外的資料帶入畫面中。

基本用法

建立一個 TestListView 專案。

在檢視中加入以下程式碼,加入 ListView。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:id="@+id/listview1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>Code language: HTML, XML (xml)

初始化資料來源

public class MainActivity extends AppCompatActivity {
    private  String[] courses = {"Java 入門", "Android 入門", "C# 入門", "C 語言", "ASP.NET MVC"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, courses);

        ListView listView = (ListView) findViewById(R.id.listview1);
        listView.setAdapter(adapter);
    }
}Code language: JavaScript (javascript)

這些資料可以從網路下載(例如透過 Web API)、從資料庫讀取,甚至直接在程式碼中定義字串陣列。

資料無法直接傳遞給 ListView,需要透過介面卡(Adapter)來協助。

Android 提供了許多介面卡,這裡我們使用 ArrayAdapter。

我們使用 android.R.layout.simple_list_item_1 作為 ListView 的子版面配置。

這是 Android 內建的版面配置檔案,只有一個 TextView 用來顯示一段文字。

列表控制項 ListView-自訂介面

如果只顯示一段文字,似乎太過簡單

我們可以在列表項目中顯示更豐富的內容。

新增一個 Book 實體類別

package com.foxdevelop.www.testlistview;

public class Book {
    private String name;
    private int imageId;

    public  Book (String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
}Code language: PHP (php)

新增一個 book 的檢視檔案

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/imageid"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="12dp"
        />
</LinearLayout>Code language: HTML, XML (xml)

自訂介面卡

package com.foxdevelop.www.testlistview;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class BookAdapter extends ArrayAdapter<Book> {
    private  int resource;

    public BookAdapter(@NonNull Context context, int resource, @NonNull List<Book> objects) {
        super(context, resource, objects);
        this.resource = resource;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Book book =  getItem(position);
        View view = LayoutInflater.from(getContext()).inflate(resource, parent, false);

        ImageView imageView = (ImageView) view.findViewById(R.id.imageid);
        imageView.setImageResource(book.getImageId());

        TextView name = (TextView) view.findViewById(R.id.name);
        name.setText(book.getName());

        return view;
    }
}Code language: JavaScript (javascript)

在活動的 onCreate 中初始化資料來源

package com.foxdevelop.www.testlistview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private List<Book> courses = new ArrayList<Book>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LoadBooks();
        BookAdapter adapter = new BookAdapter(MainActivity.this, R.layout.booklistview, courses);

        ListView listView = (ListView) findViewById(R.id.listview1);
        listView.setAdapter(adapter);
    }

    private  void LoadBooks() {
        courses.add(new Book("人類思想史上第一", R.drawable.access));
        courses.add(new Book("剝削階段政治", R.drawable.book));
        courses.add(new Book("印度古代法律的珍貴文獻", R.drawable.bookmarks));
        courses.add(new Book("欽定羅馬私法教科書", R.drawable.center));
        courses.add(new Book("知識就是力量", R.drawable.date));
        courses.add(new Book("我的民法典會永遠存在", R.drawable.clock));
        courses.add(new Book("研究美國民主的經典之作", R.drawable.ftp));
        courses.add(new Book("西方國際法權威教材", R.drawable.notes));
        courses.add(new Book("最貼近歷史真實的力作", R.drawable.set));
        courses.add(new Book("宗教改革的一面鏡子", R.drawable.energy));
        courses.add(new Book("神學的祕密就是人本學", R.drawable.tux));
        courses.add(new Book("三百多年前就介紹到了中國的名", R.drawable.science));
        courses.add(new Book("刻畫偽君子的千古傑作", R.drawable.joystick));
        courses.add(new Book("沒有圍牆的名牌大學", R.drawable.center));
        courses.add(new Book("人類思想史上第一個烏托邦方案", R.drawable.access));
    }
}Code language: JavaScript (javascript)

透過設定

android:orientation=”horizontal”

可以讓它橫向排列。

最佳化 ListView 效能

目前每次開啟活動都會重新載入資料來源,這會影響執行效率。透過快取 View,我們可以提升速度。

透過判斷 convertView,我們不需要每次都重新取得 view。

public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    Book book =  getItem(position);
    View view;
    if (convertView == null) {
        view = LayoutInflater.from(getContext()).inflate(resource, parent, false);
    } else {
        view = convertView;
    }

    ImageView imageView = (ImageView) view.findViewById(R.id.imageid);
    imageView.setImageResource(book.getImageId());

    TextView name = (TextView) view.findViewById(R.id.name);
    name.setText(book.getName());

    return view;
}Code language: PHP (php)

快取控制項

定義一個類別來存放圖片控制項和文字控制項。

class ViewData {
    ImageView imageUI;
    TextView textViewUI;
}Code language: JavaScript (javascript)
package com.foxdevelop.www.testlistview;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class BookAdapter extends ArrayAdapter<Book> {
    private  int resource;

    public BookAdapter(@NonNull Context context, int resource, @NonNull List<Book> objects) {
        super(context, resource, objects);
        this.resource = resource;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Book book =  getItem(position);
        View view;
        ViewUI viewUI;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resource, parent, false);
            ImageView imageView = (ImageView) view.findViewById(R.id.imageid);
            TextView textView = (TextView) view.findViewById(R.id.name);

            viewUI = new ViewUI();
            viewUI.imageUI = imageView;
            viewUI.textViewUI = textView;
            view.setTag(viewUI);
        } else {
            view = convertView;
            viewUI = (ViewUI) view.getTag();
        }

        viewUI.imageUI.setImageResource(book.getImageId());
        viewUI.textViewUI.setText(book.getName());
        return view;
    }

    class ViewUI {
        ImageView imageUI;
        TextView textViewUI;
    }
}Code language: JavaScript (javascript)

ListView 點擊事件

為 listview 中的項目加入點擊事件。

例如,我們實作點擊每一項時顯示書本名稱。

在主活動的 onCreate 裡:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    LoadBooks();
    BookAdapter adapter = new BookAdapter(MainActivity.this, R.layout.booklistview, courses);

    final ListView listView = (ListView) findViewById(R.id.listview1);
    listView.setAdapter(adapter);

    // 點擊事件
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            Book b = courses.get(i);
            Toast.makeText(MainActivity.this, b.getName(), Toast.LENGTH_LONG).show();
        }
    });
}Code language: PHP (php)

在 gradle 的 dependencies 中加入依賴函式庫

Configuration ‘compile’ is obsolete and has been replaced with ‘implementation’ and ‘api’.

它將在 2018 年底被移除。更多資訊請參閱:http://d.android.com/r/tools/update-dependency-configurations.html

我們需要加入對

android.support.v7.widget.RecyclerView

依賴函式庫的支援。

<?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.support.v7.widget.RecyclerView
       android:id="@+id/testrecy"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
   </android.support.v7.widget.RecyclerView>
</LinearLayout>Code language: HTML, XML (xml)

捲動控制項 RecyclerView 的使用-1

ListView 很強大,應用非常廣泛,至今仍有許多應用程式在使用。

不過它的效能稍差,擴充性也不強。

只能實作資料縱向捲動,無法橫向捲動。

RecyclerView 是 ListView 的強化版。

它可以實作與 ListView 相同的效果,並且最佳化了 ListView。

官方推薦使用 RecyclerView。

基本用法

首先,請先在 gradle 中加入:

compile ‘com.android.support:recyclerview-v7:27.1.1’

上一節中,我們加入了另一個 RecyclerView。

<android.support.v7.widget.RecyclerView
    android:id="@+id/testrecy"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>Code language: HTML, XML (xml)

我們繼續使用書本的例子。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *