betacode

Руководство Android GridView

  1. Что такое GridView?
  2. Базовый GridView используя ArrayAdapter
  3. Кастомизировать GridView используя BaseAdapter

1. Что такое GridView?

GridView это viewgroup, который показывает элеметы в двумерной сетке.
GridItem
GridView создан из списка GridItem. GridItem это отдельная ячейка (cell) в gridview там где будут показаны данные. Любые данные в gridview показываются только через griditem.
GridItem это часть интерфейса, который может быть создан некоторыми View.
Android создает некоторые формы GridItem, они называются предопределенным Layout, я упомяну о них в примерах этой статьи.
Adapter
Android Adapter (Адаптер) это мост соединяющий View и базовые данные этого View. Adapter контролирует данные и адаптирует данные к отдельным ячейкам (GridItems) view.

Вы можете привязать Adapter к GridView используя метод setAdapter. Теперь, пoсмотрим как работает Adapter с помощью следующих изображений.
GridView Selector
Чтобы лучше украсить GridView, вам нужно персонализировать эффекты, такие как изменение фонового цвета GridItem когда курсор переменяется на нет или изменить цвет фона когда выбран GridItem. Можете посмотреть пример персонализации GridView Selector в конце данной статьи.

2. Базовый GridView используя ArrayAdapter

ArrayAdapter
ArrayAdapter используется для отображения GridView с простыми GridItem, GridItem можно создать только из TextView, CheckedTextView, EditText,...

Если вы хотите GridView со более сложным GridItem, вы можете сами создать кастомизированный Adapter.
Пример GridView с ArrayAdapter
Создать Android project с названием SimpleGridView.
  • File > New > New Project > Empty Activity
    • Name: SimpleGridView
    • Package name: org.o7planning.simplegridview
    • Language: Java
Дизайн интерфейса:
Изменить настройки:
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();
            }
        });
    }

}
Запуск примера:
Готовые Layout для работы с ArrayAdapter
Android создал некоторые Layout (для GridItem, ListItem,..) которые могут работать с ArrayAdapter.
android.R.layout.simple_list_item_1
  • Это простой layoutGridItem, созданный единственным TextView (Смотрите примеры выше).
android.R.layout.simple_list_item_checked & android.R.layout.simple_list_item_multiple_choice
  • 2 Layout выше это простые layout чтобы создать GridView с GridItem имеющий checkbox.
  • TODO

    3. Кастомизировать GridView используя BaseAdapter

    Вы можете создать кастомизированный GridViewer. Ваш Adapter нужно расширить из класса BaseAdapter.
    Пример кастомизированного GridView
    Создать "Empty Activity" project с названием CustomGridView.
    • File > New > New Project > Empty Activity
      • Name: CustomGridView
      • Package name: org.o7planning.customgridview
      • Language: Java
    Предварительный просмотр приложения:
    Приготовить несколько изображений:
    Копировать и вставить изображения в папку mipmap:
    vn.png
    us.png
    ru.png
    jp.png
    au.png
    Вам нужно создать layout для Griditem. На Android Studio нажмите на правую мышь на res/layout и выберите:
    • New/Layout resource file
    Ввод:
    • File name: grid_item_layout.xml
    • Root element: androidx.constraintlayout.widget.ConstraintLayout
    Дизайн интерфейса GridItem.
    Slider шаги дизайна интерфейса для 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 это класс расширенный из BaseAdapter, выполняет обязанность отображать данные на 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;
        }
    
    }
    Запуск приложения:
    Пример кастомизираванного Selector
    Чтобы улучшить GridView, вам нужно кастомизировать эффекты, например при изменении цвета фона GridItem при движении курсора или при выборе GridItem. Продолжим с примером.
    Создать конфигурационные файлы:
    • File name: item_state_normal.xml
    • Directory: drawable
    Индентично создайте другие 3 файла:
    • item_state_pressed.xml
    • item_state_selected.xml
    • list_selector.xml
    Когда Grid Item находится в обычном состоянии, стили (style) настроенные в item_state_normal.xml будт применены к 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>
    При нажатии на Grid Item стили настроенные в item_state_pressed.xml будут применены к 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>
    Когда GridItem выбирает style (стили) настройки в item_state_selected.xml будут применены к 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>
    Сопоставить определенные статусы GridItem с вышеуказанными файлами xml.
    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>
    Настроить ListSelector для 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>
    Перезапустить приложение.

    Pуководства Android

    Show More