betacode

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

View more Tutorials:

Сайт бесплатного изучения языков:
Следуйте за нами на нашей фан-странице, чтобы получать уведомления каждый раз, когда появляются новые статьи. Facebook

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

GridView это viewgroup, который показывает элеметы в двумерной сетке.

1.1- GridItem

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

1.2- Adapter

Android Adapter (Адаптер) это мост соединяющий View и базовые данные этого ViewAdapter контролирует данные и адаптирует данные к отдельным ячейкам (GridItems) view.

Вы можете привязать Adapter к GridView используя метод setAdapter. Теперь, пoсмотрим как работает Adapter с помощью следующих изображений.

1.3- GridView Selector

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

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

2.1- ArrayAdapter

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

Если вы хотите GridView со более сложным GridItem, вы можете сами создать кастомизированный Adapter.

2.2- Пример 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();
            }
        });
    }

}
Запуск примера:

2.3- Готовые Layout для работы с ArrayAdapter

Android создал некоторые Layout (для GridItem, ListItem,..) которые могут работать с ArrayAdapter.
android.R.layout.simple_list_item_1
  • Это простой layout GridItem, созданный единственным 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.

3.1- Пример кастомизированного 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;
    }

}
Запуск приложения:

3.2- Пример кастомизираванного 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>
Перезапустить приложение.

View more Tutorials: