openplanning

Hướng dẫn và ví dụ Android GridView

  1. GridView là gì?
  2. GridView cơ bản sử dụng ArrayAdapter
  3. Tùy biến GridView sử dụng BaseAdapter

1. GridView là gì?

GridView là một viewgroup, nó hiển thị các phần tử con trên một lưới cuộn 2 chiều.
GridItem
Một GridView được tạo từ một danh sách các GridItem. GridItem là một ô (cell) riêng lẻ trong gridview nơi mà dữ liệu sẽ được hiển thị. Bất kỳ dữ liệu nào trong gridview chỉ được hiển thị thông qua griditem.
Một GridItem là một mảnh giao diện, nó có thể được làm bởi một số View.

Android xây dựng sẵn một số mẫu GridItem khác nhau, chúng được gọi là các Layout định nghĩa sẵn, sẽ được tôi đề cập trong các ví dụ của tài liệu này.

Adapter
Android Adapter (Bộ tiếp nối) là một cầu nối giữa các View và các dữ liệu cơ bản cho View đó. Một Adapter quản lý dữ liệu và ghép nối với các ô riêng lẻ (GridItems) của view.

Bạn có ràng buộc các Adapter với GridView thông qua phương thức setAdapter. Bây giờ, Chúng ta hãy xem làm thế nào Adapter làm việc với sự giúp đỡ của hình ảnh sau đây.
GridView Selector
Để GridView hiển thị đẹp hơn, bạn cần phải tùy biến các hiệu ứng, chẳng hạn, đổi mầu nền của GridItem khi con trỏ di chuyển trên nó hoặc đổi mầu nền khi GridItem được chọn. Bạn có thể xem ví dụ tùy biến GridView Selector ở cuối tài liệu này.

2. GridView cơ bản sử dụng ArrayAdapter

ArrayAdapter
ArrayAdapter sử dụng để hiển thị các GridView với các GridItem đơn giản, GridItem có thể làm từ duy nhất một TextView, CheckedTextView, EditText,...

Trong trường hợp bạn muốn có một GridView với GridItem phức tạp hơn, bạn có thể tự tạo ra một Adapter tùy biến.
Ví dụ GridView với ArrayAdapter
Tạo mới một Android project có tên SimpleGridView.
  • File > New > New Project > Empty Activity
    • Name: SimpleGridView
    • Package name: org.o7planning.simplegridview
    • Language: Java
Thiết kế giao diện:
Thay đổi các thuộc tính:
GridView
  • android:numColumns ="2"
  • android:stretchMode ="columnWidth"
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <GridView
        android:id="@+id/gridView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:layout_marginBottom="16dp"
        android:numColumns="2"
        android:stretchMode="columnWidth"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
Website.java
package org.o7planning.simplegridview;

public class Website {

    private String name;
    private String url;

    public Website(String name, String url)  {
        this.name= name;
        this.url= url;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString()  {
        return name;
    }
}
MainActivity.java
package org.o7planning.simplegridview;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.GridView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

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

        this.gridView = (GridView)findViewById(R.id.gridView);

        //

        Website o7planning = new Website("o7planning","http://o7planning.org");
        Website google = new Website("Google","http://google.com");
        Website facebook = new Website("Facebook","http://facebook.com");
        Website eclipse = new Website("Eclipse","http://eclipse.org");
        Website yahoo = new Website("Yahoo","http://yahoo.com");

        Website[] websites = new Website[]{o7planning,google, facebook,eclipse, yahoo};

        // android.R.layout.simple_list_item_1 is a constant predefined layout of Android.
        // used to create a GridView with simple GridItem (Only one TextView).

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


        gridView.setAdapter(arrayAdapter);

        // When the user clicks on the GridItem
        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> a, View v, int position, long id) {
                Object o = gridView.getItemAtPosition(position);
                Website website = (Website) o;
                Toast.makeText(MainActivity.this, "Selected :" + " " + website.getName()+"\n("+ website.getUrl()+")",
                        Toast.LENGTH_LONG).show();
            }
        });
    }

}
Chạy ví dụ:
Các Layout có sẵn để làm việc với ArrayAdapter
Android xây dựng sẵn một số Layout (cho GridItem, ListItem,..) có thể làm việc với ArrayAdapter.
android.R.layout.simple_list_item_1
  • Đây là layout đơn giản của GridItem, được tạo bởi duy nhất một TextView (Bạn có thể xem ví dụ ở trên).
android.R.layout.simple_list_item_checked & android.R.layout.simple_list_item_multiple_choice
  • 2 Layout trên là layout đơn giản để tạo ra một GridView với GridItem có một checkbox.
  • TODO

    3. Tùy biến GridView sử dụng BaseAdapter

    Bạn có thể xây dựng tùy biến một GridViewer. Adapter của bạn nên mở rộng từ lớp BaseAdapter.
    Ví dụ GridView tùy biến
    Tạo một "Empty Activity" project có tên CustomGridView.
    • File > New > New Project > Empty Activity
      • Name: CustomGridView
      • Package name: org.o7planning.customgridview
      • Language: Java
    Đây là hình ảnh ứng dụng sẽ làm:
    Chuẩn bị một vài file ảnh:
    Copy và paste các file ảnh này vào thư mục mipmap:
    vn.png
    us.png
    ru.png
    jp.png
    au.png
    Bạn cần tạo layout cho Griditem. Trên Android Studio nhấn phải chuột vào res/layout chọn:
    • New/Layout resource file
    Nhập vào:
    • File name: grid_item_layout.xml
    • Root element: androidx.constraintlayout.widget.ConstraintLayout
    Thiết kế giao diện của GridItem.
    Slider các bước thiết kế giao diện của GridItem:
    ImageView
    • ID: imageView_flag

    TextView 1:
    • ID: textView_countryName
    • Text: Country Name

    TextView 2:
    • ID: textView_population
    • Text: Population ....
    grid_item_layout.xml
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ImageView
            android:id="@+id/imageView_flag"
            android:layout_width="80dp"
            android:layout_height="60dp"
            android:layout_marginStart="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/ic_launcher_foreground" />
    
        <TextView
            android:id="@+id/textView_countryName"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginRight="8dp"
            android:text="Country Name"
            android:textSize="18sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/imageView_flag"
            app:layout_constraintTop_toTopOf="parent" />
    
        <TextView
            android:id="@+id/textView_population"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="3dp"
            android:layout_marginEnd="8dp"
            android:layout_marginRight="8dp"
            android:text="Population"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/imageView_flag"
            app:layout_constraintTop_toBottomOf="@+id/textView_countryName" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    activity_main.xml
    GridView
    • android:numColumns ="2"
    • android:stretchMode ="columnWidth"
    activity_main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <GridView
            android:id="@+id/gridView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginBottom="8dp"
            android:numColumns="2"
            android:stretchMode="columnWidth"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    CustomGridAdapter là class mở rộng từ BaseAdapter, nó làm nhiệm vụ hiển thị dữ liệu lên các Grid Item.
    Country.java
    package org.o7planning.customgridview;
    
    public class Country {
    
        private String countryName;
    
        // Image name (Without extension)
        private String flagName;
        private int population;
    
        public Country(String countryName, String flagName, int population) {
            this.countryName= countryName;
            this.flagName= flagName;
            this.population= population;
        }
    
        public int getPopulation() {
            return population;
        }
    
        public void setPopulation(int population) {
            this.population = population;
        }
    
        public String getCountryName() {
            return countryName;
        }
    
        public void setCountryName(String countryName) {
            this.countryName = countryName;
        }
    
        public String getFlagName() {
            return flagName;
        }
    
        public void setFlagName(String flagName) {
            this.flagName = flagName;
        }
    
        @Override
        public String toString()  {
            return this.countryName+" (Population: "+ this.population+")";
        }
    }
    CustomGridAdapter.java
    package org.o7planning.customgridview;
    
    import android.content.Context;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    import java.util.List;
    
    public class CustomGridAdapter  extends BaseAdapter {
    
        private List<Country> listData;
        private LayoutInflater layoutInflater;
        private Context context;
    
        public CustomGridAdapter(Context aContext,  List<Country> listData) {
            this.context = aContext;
            this.listData = listData;
            layoutInflater = LayoutInflater.from(aContext);
        }
    
        @Override
        public int getCount() {
            return listData.size();
        }
    
        @Override
        public Object getItem(int position) {
            return listData.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if (convertView == null) {
                convertView = layoutInflater.inflate(R.layout.grid_item_layout, null);
                holder = new ViewHolder();
                holder.flagView = (ImageView) convertView.findViewById(R.id.imageView_flag);
                holder.countryNameView = (TextView) convertView.findViewById(R.id.textView_countryName);
                holder.populationView = (TextView) convertView.findViewById(R.id.textView_population);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
    
            Country country = this.listData.get(position);
            holder.countryNameView.setText(country.getCountryName());
            holder.populationView.setText("" + country.getPopulation());
    
            int imageId = this.getMipmapResIdByName(country.getFlagName());
    
            holder.flagView.setImageResource(imageId);
    
            return convertView;
        }
    
        // Find Image ID corresponding to the name of the image (in the directory mipmap).
        public int getMipmapResIdByName(String resName)  {
            String pkgName = context.getPackageName();
    
            // Return 0 if not found.
            int resID = context.getResources().getIdentifier(resName , "mipmap", pkgName);
            Log.i("CustomGridView", "Res Name: "+ resName+"==> Res ID = "+ resID);
            return resID;
        }
    
        static class ViewHolder {
            ImageView flagView;
            TextView countryNameView;
            TextView populationView;
        }
    
    }
    ActivityMain.java
    package org.o7planning.customgridview;
    
    import androidx.appcompat.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.GridView;
    import android.widget.ListView;
    import android.widget.Toast;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
            List<Country> image_details = getListData();
            final GridView gridView = (GridView) findViewById(R.id.gridView);
            gridView.setAdapter(new CustomGridAdapter(this, image_details));
    
            // When the user clicks on the GridItem
            gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    
                @Override
                public void onItemClick(AdapterView<?> a, View v, int position, long id) {
                    Object o = gridView.getItemAtPosition(position);
                    Country country = (Country) o;
                    Toast.makeText(MainActivity.this, "Selected :"
                            + " " + country, Toast.LENGTH_LONG).show();
                }
            });
        }
    
        private  List<Country> getListData() {
            List<Country> list = new ArrayList<Country>();
            Country vietnam = new Country("Vietnam", "vn", 98000000);
            Country usa = new Country("United States", "us", 320000000);
            Country russia = new Country("Russia", "ru", 142000000);
            Country australia = new Country("Australia", "au", 23766305);
            Country japan = new Country("Japan", "jp", 126788677);
    
            list.add(vietnam);
            list.add(usa);
            list.add(russia);
            list.add(australia);
            list.add(japan);
    
            return list;
        }
    
    }
    Chạy ứng dụng:
    Ví dụ Tùy biến Selector
    Để GridView hiển thị đẹp hơn, bạn cần phải tùy biến các hiệu ứng, chẳng hạn khi đổi mầu nền của GridItem khi con trỏ di chuyển trên nó hoặc đổi mầu nền khi GridItem được chọn. Chúng ta sẽ tiếp tục với với vụ ở trên.
    Tạo các file cấu hình:
    • File name: item_state_normal.xml
    • Directory: drawable
    Tương tự tạo mới 3 file khác:
    • item_state_pressed.xml
    • item_state_selected.xml
    • list_selector.xml
    Khi Grid Item ở trạng thái bình thường các style sét đặt trong item_state_normal.xml sẽ được áp dụng cho GridItem.
    item_state_normal.xml
    <?xml version="1.0" encoding="utf-8"?>
    
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
      android:shape="rectangle">
    
      <gradient
          android:startColor="#f1f1f2"
          android:centerColor="#e7e7e8"
          android:endColor="#cfcfcf"
          android:angle="270" />
    
    </shape>
    Khi Grid Item bị nhấn các style sét đặt trong item_state_pressed.xml sẽ được áp dụng cho GridItem
    item_state_pressed.xml
    <?xml version="1.0" encoding="utf-8"?>
    
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
      android:shape="rectangle">
    
      <gradient
          android:startColor="#18d7e5"
          android:centerColor="#16cedb"
          android:endColor="#09adb9"
          android:angle="270" />
    
    </shape>
    Khi GridItem được chọn các style (kiểu dáng) sét đặt trong item_state_selected.xml sẽ được áp dụng cho GridItem
    item_state_selected.xml
    <?xml version="1.0" encoding="utf-8"?>
    
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    
       <gradient
           android:startColor="#18d7e5"
           android:centerColor="#16cedb"
           android:endColor="#09adb9"
           android:angle="270" />
    
    </shape>
    Gắn các trạng thái cụ thể của GridItem với các file xml nói trên.
    list_selector.xml
    <?xml version="1.0" encoding="utf-8"?>
    
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    
           <item
               android:state_selected="false"
               android:state_pressed="false"
               android:drawable="@drawable/item_state_normal" />
    
           <item android:state_pressed="true"
               android:drawable="@drawable/item_state_pressed" />
    
           <item android:state_selected="true"
               android:state_pressed="false"
               android:drawable="@drawable/item_state_selected" />
    
    
    </selector>
    Sét đặt ListSelector cho GridView:
    <GridView
         ...
         android:listSelector="@drawable/list_selector" />
    activity_main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <GridView
            android:id="@+id/gridView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginBottom="8dp"
            android:numColumns="2"
            android:stretchMode="columnWidth"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:listSelector="@drawable/list_selector" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    Chạy lại ứng dụng của bạn.

    Các hướng dẫn lập trình Android

    Show More