ListView và Custom Adapter | How Kteam

Dẫn nhập

Ở các bài học trước, chúng ta đã cùng nhau tìm hiểu về MATERIAL DESIGN , một số nguyên lý cơ bản của nó, và cách tích hợp nó vào trong ứng dụng Android, cũng như các coding convention dành riêng cho Android mà Kteam cho là khá hiệu quả.

Và ở bài này, chúng ta sẽ cùng đến một phần khác mà các bạn nghe đến đã yêu luôn: Hiển thị danh sách.

Rồi hẳn có bạn sẽ nói: “Hư cấu! Danh sách thì có gì mà yêu”.

Có đấy, nhiều là đằng khác. Nào, xin mời!

Nội dung

Để đọc hiểu bài này tốt nhất các bạn nên có kiến thức cơ bản về các phần:

Trong bài học này, chúng ta sẽ cùng tìm hiểu các vấn đề:

  • Các cách hiển thị danh sách trên ứng dụng Android.
  • ListView là… cái gì?
  • Cách hiển thị một danh sách đơn giản, toàn chữ.
  • Cách hiển thị một danh sách phức tạp hơn một chút, bao gồm 2 dòng và 1 biểu tượng.

ListView là cái gì?

ListView là một View đặc biệt. Ấy ấy nếu bạn chưa biết View là gì thì hãy đọc qua bài “CÁC THÀNH PHẦN GIAO DIỆN CƠ BẢN” đã nhé.

Đặc biệt là sao? Là ListView có thể hiển thị một danh sách nào đó.

Hẳn sẽ có nhiều bạn nghĩ đơn giản: “Ùi dào ôi, nếu muốn hiển thị n phần tử thì tạo ra n cái View là xong chứ gì?”

Không, đừng làm vậy. Đã là lập trình viên thì chúng ta cần tối ưu và tự động hóa mọi thứ có thể. Đặc biệt là sau này khi danh sách được bổ sung / thêm bớt thì sao?

Ví dụ đây là một danh sách cơ bản, chỉ gồm chữ:

ListView và Custom Adapter

Còn đây là một danh sách phức tạp hơn một tí, bao gồm ảnh, và chữ, sắp xếp theo từng ô (nếu bạn muốn biết tên app thì nó là MangaRock, app đọc truyện tranh ưa thích của mình):

ListView và Custom Adapter

Các bạn có để ý là, mỗi item trong danh sách ở 2 ảnh ví dụ trên đều na ná nhau không? Đều có cùng kích thước item, khác nội dung mỗi item thôi. Còn đây là ví dụ về một loại danh sách phức tạp hơn nữa, từ app Messenger của Facebook:

ListView và Custom Adapter

Đó, có 2 kiểu bong bóng thoại màu xám màu xanh dương, căn lề theo 2 bên.

ListView cơ bản nhất

Đúng! Sau đây mình sẽ hướng dẫn các bạn làm một ListView dạng cơ bản nhất.

Tại sao ListView cũng là View mà mình không giới thiệu ở bài trước mà lại đặt ra một bài riêng? Vì cách thực hiện nó khó hơn View bình thường.

Nhưng nếu phân tích ra thì chúng ta sẽ có ListView là:

  • Một

    View

    bình thường.

  • Nó có thể chứa được các

    View

    khác (nhưng không phải là ViewGroup) << điểm đặc biệt là đây.

  • Nó cần dữ liệu để hiển thị danh sách ra (mảng, list, array list,…).

Bước 1: Chúng ta lại tạo một project mới, đặt tên là ListViewExample nhé. Với Activity chính là MainActivity:

ListView và Custom Adapter

Bước 2: Ở đây chúng ta sẽ làm một ListView với nội dung hiển thị vô cùng đơn giản: Một mảng các String.

Code thẳng luôn vào MainActivity.java nhé:

  • MainActivity.java

package com.howkteam.listviewexample;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

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

        String[] items = {"Doan Ngoc Giau", "Pham Kim Long", "Kteam"};
    }
}

Ok, thế là có mảng rồi, thích nhé. Sang bước tiếp theo nào.

Bước 3: Thêm ListView vào file XML:

Chúng ta xóa bỏ cái TextView đi và thay bằng ListView, nhớ đặt id cho nó:

  • activity_main.xml

<?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="com.howkteam.listviewexample.MainActivity">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

Vậy là xong… chúng ta sang bước… à khoan!

Chưa xong, để hiển thị được mảng String ở trên vào ListView thì chúng ta phải đưa mỗi String vào một View con nằm trong ListView. Mỗi item trong ListView đều có một layout riêng. Các bạn chuột phải vào res/layout > New Android resource file như hình:

ListView và Custom Adapter

Đặt tên cho nó là item_name nhé (mỗi String là tên người mà, để “name” cho dễ hiểu):

ListView và Custom Adapter

Nội dung của file như sau:

  • item_name.xml

<?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="wrap_content"
              android:orientation="vertical"
              android:padding="16dp">

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

</LinearLayout>

Bước 4: Phần này quan trọng đây! Chúng ta sẽ tạo ra Adapter.

Hỏi: Ớ ớ, Adapter là cái gì?

Trả lời: Adapter là class để ánh xạ item view của bạn và item trong danh sách String đầu vào. Trong trường hợp này, nó ánh xạ mỗi phần tử trong mảng String[] items vừa khai báo ở trên.

Nếu các bạn vẫn chưa hiểu thì cứ làm tiếp, bắt chước y như mình, code tiếp, sau đó mình sẽ giải thích bổ sung. Trước đây mình cũng rất mù mờ về khái niệm adapter, sau khi code thì vỡ lẽ ra hết.

Chúng ta tạo một class mới có tên là DataAdapter và cho nó extends từ BaseAdapter:

ListView và Custom Adapter

Các bạn thấy có lỗi đúng không? Không sao, là tại chúng ta chưa viết các method cần implement thôi. Vào menu Code > Implement Methods… (nhớ đặt chuột trong khối lệnh của class DataAdapter):

ListView và Custom Adapter

Hoặc một cách khác là đặt con trỏ chuột giữa dòng báo lỗi và nhấn Alt+Enter > Implement Methods:

ListView và Custom Adapter

Cửa sổ Select Methods to implement hiện ra, chọn tất cả 4 method và nhấn OK:

ListView và Custom Adapter

Và chúng ta có class khung sơ bộ như sau:


package com.howkteam.listviewexample;

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public class DataAdapter extends BaseAdapter {

    @Override
    public int getCount() {
        return 0;
    }

    @Override
    public Object getItem(int i) {
        return null;
    }

    @Override
    public long getItemId(int i) {
        return 0;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        return null;
    }
}

Bước 5: Để có thể sử dụng Adapter thì chúng ta cần truyền cho class này dữ liệu dạng danh sách hoặc mảng (ở đây chúng ta dùng mảng, để ý cái String[] items ở bước trước), và truyền qua constructor của nó:


private String[] items;

public DataAdapter(String[] items) {
    this.items = items;
}

Tiếp theo, ở hàm getCount(), hàm này sẽ trả về số lượng phần tử hiển thị trong danh sách. Con số này bắt buộc phải nhỏ hơn hoặc bằng số lượng phần tử trong mảng đầu vào, nếu không sẽ bị lỗi IndexOutOfBoundException:

@Override
public int getCount() {
    return items.length;
}

Code đầy đủ của cả class DataAdapter.java

package com.howkteam.listviewexample;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class DataAdapter extends BaseAdapter {

    private Activity activity;
    private String[] items;

    public DataAdapter(Activity activity, String[] items) {
        this.activity = activity;
        this.items = items;
    }

    @Override
    public int getCount() {
        return items.length;
    }

    @Override
    public Object getItem(int i) {
        return items[i];
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        // Gọi layoutInflater ra để bắt đầu ánh xạ view và data.
        LayoutInflater inflater = activity.getLayoutInflater();

        // Đổ dữ liệu vào biến View, view này chính là những gì nằm trong item_name.xml
        view = inflater.inflate(R.layout.item_name, null);

        // Đặt chữ cho từng view trong danh sách.
        TextView tvName = (TextView) view.findViewById(R.id.tv_name);
        tvName.setText(items[i]);

        // Trả về view kết quả.
        return view;
    }
}

Và cuối cùng cài đặt adapter cho ListView tại MainActivity.java:

package com.howkteam.listviewexample;

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

public class MainActivity extends AppCompatActivity {

    private ListView listView;

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

        String[] items = {"Doan Ngoc Giau", "Pham Kim Long", "Kteam"};

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

        DataAdapter adapter = new DataAdapter(this, items);
        listView.setAdapter(adapter);
    }
}

Và chúng ta được như sau:

ListView và Custom Adapter

Ok! tạm thời là như vậy, bài viết này sẽ tạm dừng tại đây với các kiến thức cơ bản nhất về ListView. Chúng ta có một số lưu ý như sau:

  • ListView

    cũng chỉ là một

    View

    bình thường.

  • Để hiển thị danh sách các phần tử,

    ListView

    cần một mảng hoặc một danh sách các dữ liệu đầu vào (model chẳng hạn).

  • Chúng ta không truyền thẳng mảng hay list cho

    ListView

    mà cần truyền qua

    Adapter

    .

  • Adapter

    là cầu nối giữa dữ liệu và

    ListView

    .

Kết luận

Qua bài này chúng ta đã nắm được ListView là gì, chúng ta phải làm gì để ListView có thể hiển thị danh sách các String đơn giản.

Bài sau chúng ta sẽ quay lại tìm hiểu thêm một chút về ListView, và RECYCLERVIEW – một loại View chứa danh sách khác, họ hàng với ListView nhưng tốt hơn, dễ tùy biến hơn rất nhiều. Bên cạnh đó là cơ chế ViewHolder áp dụng được cho cả ListView và RecyclerView nhằm tăng tốc độ khi sử dụng danh sách.

Cảm ơn các bạn đã theo dõi bài viết. Hãy để lại bình luận hoặc góp ý của mình để phát triển bài viết tốt hơn. Đừng quên “Luyện tập – Thử thách – Không ngại khó”.

Thảo luận

Nếu bạn có bất kỳ khó khăn hay thắc mắc gì về khóa học, đừng ngần ngại đặt câu hỏi trong phần bên dưới hoặc trong mục HỎI & ĐÁP trên thư viện Howkteam.com để nhận được sự hỗ trợ từ cộng đồng.