Освой Android играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

GridView

Знакомьтесь - GridView
Базовый пример
GridView с картинками
GridView с картинками и пояснительным текстом
Убрать вертикальную прокрутку
Галерея
Загружаем картинки из внешнего накопителя

Знакомьтесь - GridView

Компонент GridView представляет собой плоскую таблицу. Для GridView можно использовать собственные поля для отображения элементов данных, создав класс, производный от класса ArrayAdapter или BaseAdapter и т.п, и переопределив его метод getView().

В старых версиях студии находился в разделе Containers, сейчас находится в Legacy и считается устаревшим.

Число столбцов для GridView чаще задаётся статически. Число строк в элементе определяется динамически на основании числа элементов, которые предоставляет адаптер.

Свойства

  • android:numColumns — определяет количество столбцов. Если поставлено значение auto_fit, то система вычислит количество столбцов, основанное на доступном пространстве
  • android:verticalSpacing — устанавливает размер пустого пространства между ячейками таблицы
  • android:columnWidth — устанавливает ширину столбцов
  • android:stretchMode — указывает, куда распределяется остаток свободного пространства для таблицы с установленным значением android:numColumns="auto_fit". Принимает значения columnWidth для paспределения остатка свободного пространства между ячейками столбцов для их увеличения или spacingWidth — для увеличения пространства между ячейками

Базовый пример

Если поместить GridView на форму, то увидим следующую картину.

GridView

Внесём небольшие правки


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/info"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <GridView
        android:id="@+id/gridView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:columnWidth="100dp"
        android:gravity="center"
        android:horizontalSpacing="5dp"
        android:numColumns="auto_fit"
        android:stretchMode="columnWidth"
        android:verticalSpacing="35dp" >
    </GridView>

</LinearLayout>

В коде реализуем наполнение таблицы через адаптер. Создадим новый файл DataAdapter.java:


package ru.alexanderklimov.gridview;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class DataAdapter extends ArrayAdapter<String> {

	private static final String[] mContacts = { "Рыжик", "Барсик", "Мурзик",
			"Мурка", "Васька", "Полосатик", "Матроскин", "Лизка", "Томосина",
			"Бегемот", "Чеширский", "Дивуар", "Тигра", "Лаура" };

	Context mContext;

	// Конструктор
	public DataAdapter(Context context, int textViewResourceId) {
		super(context, textViewResourceId, mContacts);
		// TODO Auto-generated constructor stub
		this.mContext = context;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub

		TextView label = (TextView) convertView;

		if (convertView == null) {
			convertView = new TextView(mContext);
			label = (TextView) convertView;
		}
		label.setText(mContacts[position]);
		return (convertView);
	}

	// возвращает содержимое выделенного элемента списка
	public String getItem(int position) {
		return mContacts[position];
	}

}

Теперь напишем код для основного окна приложения. Как и у ListView, нам нужно использовать метод setAdapter(), а также методы setOnItemSelectedListener(), onItemSelected(), onNothingSelected().


package ru.alexanderklimov.gridview;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.TextView;

public class GridViewDemoActivity extends Activity implements
		AdapterView.OnItemSelectedListener {

	private TextView mSelectText;
	private DataAdapter mAdapter;

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

		mSelectText = (TextView) findViewById(R.id.info);
		final GridView g = (GridView) findViewById(R.id.gridView1);
		mAdapter = new DataAdapter(getApplicationContext(),
				android.R.layout.simple_list_item_1);
		g.setAdapter(mAdapter);
		g.setOnItemSelectedListener(this);
		g.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View v,
					int position, long id) {
				// TODO Auto-generated method stub
				mSelectText.setText("Выбранный элемент: "
						+ mAdapter.getItem(position));
			}
		});
	}

	@Override
	public void onItemSelected(AdapterView<?> parent, View v, int position,
			long id) {
		mSelectText.setText("Выбранный элемент: " + mAdapter.getItem(position));
	}

	@Override
	public void onNothingSelected(AdapterView<?> parent) {
		mSelectText.setText("Выбранный элемент: ничего");
	}
}

Запустите проект и начинайте выбирать любой элемент - его название отобразится в текстовой метке в верхней части экрана. Я обратил внимание, что в эмуляторе с помощью джойстика можно выбрать нужный элемент, но в современных телефонах джойстика нет, поэтому я позже добавил метод setOnItemClickListener(), чтобы можно было щёлкать по элементам в GridView и выводить их названия в метке.

GridView с картинками

Вместо текста можно использовать и картинки. Немного модифицируем проект. В шаблоне разметки изменим GridView:


<GridView
    android:id="@+id/gridView1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:columnWidth="90dp"
    android:gravity="center"
    android:horizontalSpacing="10dp"
    android:numColumns="auto_fit"
    android:stretchMode="columnWidth"
    android:verticalSpacing="10dp" >
</GridView>

Создадим новый адаптер ImageAdapter.java, в котором будет возможность подключать картинки


package ru.alexanderklimov.gridview;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;

public class ImageAdapter extends BaseAdapter {
	private Context mContext;

	public ImageAdapter(Context c) {
		mContext = c;
	}

	public int getCount() {
		return mThumbIds.length;
	}

	public Object getItem(int position) {
		return mThumbIds[position];
	}

	public long getItemId(int position) {
		return position;
	}

	// create a new ImageView for each item referenced by the Adapter
	public View getView(int position, View convertView, ViewGroup parent) {
		ImageView imageView;
		if (convertView == null) {
			// if it's not recycled, initialize some attributes
			imageView = new ImageView(mContext);
			imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
			imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
			imageView.setPadding(8, 8, 8, 8);
		} else {
			imageView = (ImageView) convertView;
		}

		imageView.setImageResource(mThumbIds[position]);
		return imageView;
	}

	// references to our images
	public	Integer[] mThumbIds = { R.drawable.card1, R.drawable.card2,
			R.drawable.card3, R.drawable.card4, R.drawable.card5,
			R.drawable.card6, R.drawable.card7, R.drawable.card8,
			R.drawable.card9, R.drawable.card10, R.drawable.card11,
			R.drawable.card12, R.drawable.card13, R.drawable.card14,
			R.drawable.card15, R.drawable.card16, R.drawable.card17,
			R.drawable.card18, R.drawable.card19, R.drawable.card20,
			R.drawable.card21 };
}

Теперь код в основной активности:


package ru.alexanderklimov.gridview;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.TextView;

public class GridViewDemoActivity extends Activity {

	private TextView mSelectText;

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

		mSelectText = (TextView) findViewById(R.id.info);
		GridView gridview = (GridView) findViewById(R.id.gridView1);
		gridview.setAdapter(new ImageAdapter(this));

		gridview.setOnItemClickListener(gridviewOnItemClickListener);
	}

	private GridView.OnItemClickListener gridviewOnItemClickListener = new GridView.OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> parent, View v, int position,
				long id) {
			// выводим номер позиции
			mSelectText.setText(String.valueOf(position));
		}
	};
}

Результат ниже

GridView

Зная номер позиции можно доработать программу, чтобы при щелчке на картинке, она открывалась на весь экран. Давайте так и сделаем. Создадим новый XML-файл разметки в папке res/layout под именем full_image.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="match_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/full_image_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

Создадим новую активность, в которой будет выводиться изображение на весь экран (файл FullImageActivity.java):


package ru.alexanderklimov.gridview;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ImageView;

public class FullImageActivity extends Activity {
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.full_image);

		// get intent data
		Intent intent = getIntent();

		// Selected image id
		int position = intent.getExtras().getInt("id");
		ImageAdapter imageAdapter = new ImageAdapter(this);

		ImageView imageView = (ImageView) findViewById(R.id.full_image_view);
		imageView.setImageResource(imageAdapter.mThumbIds[position]);
	}
}

Класс получает от намерения номер позиции и выводит по этому номеру изображение из ресурсов.

Теперь в основной активности модифицируем код для щелчка


private GridView.OnItemClickListener gridviewOnItemClickListener = new GridView.OnItemClickListener() {
	@Override
	public void onItemClick(AdapterView<?> parent, View v, int position,
			long id) {
	
		// Sending image id to FullScreenActivity
		Intent i = new Intent(getApplicationContext(),
				FullImageActivity.class);
		// passing array index
		i.putExtra("id", position);
		startActivity(i);
	}
};

Осталось добавить в манифест новую активность:


<activity android:name=".FullImageActivity"></activity>

У нас получилась галерея с просмотром отдельной картинки.

GridView с картинками и пояснительным текстом

Модифицируем предыдущий пример и создадим сетку, состоящую из картинок с сопроводительным текстом внизу.

Можно было оставить предыдущую разметку для активности, но я решил чуть её изменить, убрав лишние элементы


<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/gridview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:columnWidth="90dp"
    android:gravity="center"
    android:horizontalSpacing="10dp"
    android:numColumns="auto_fit"
    android:stretchMode="columnWidth"
    android:verticalSpacing="10dp" />

Теперь создадим разметку для отдельной ячейки сетки - нам нужны ImageView и TextView:

res/layout/cellgrid.xml


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

    <ImageView
        android:id="@+id/imagepart"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

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

</LinearLayout>

Создадим новый класс ImageTextAdapter. Он практически не отличается от класса ImageAdapter, поменялся только метод getView(), разницу в коде я закоментировал для сравнения


package ru.alexanderklimov.gridview;

import ...

public class ImageTextAdapter extends BaseAdapter {
	private Context mContext;

	public ImageTextAdapter(Context c) {
		mContext = c;
	}

	public int getCount() {
		return mThumbIds.length;
	}

	public Object getItem(int position) {
		return mThumbIds[position];
	}

	public long getItemId(int position) {
		return position;
	}

	// create a new ImageView for each item referenced by the Adapter
	// public View getView(int position, View convertView, ViewGroup parent) {
	// ImageView imageView;
	// if (convertView == null) {
	// // if it's not recycled, initialize some attributes
	// imageView = new ImageView(mContext);
	// imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
	// imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
	// imageView.setPadding(8, 8, 8, 8);
	// } else {
	// imageView = (ImageView) convertView;
	// }
	//
	// imageView.setImageResource(mThumbIds[position]);
	// return imageView;
	// }

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub

		View grid;

		if (convertView == null) {
			grid = new View(mContext);
			//LayoutInflater inflater = getLayoutInflater();
			LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
			grid = inflater.inflate(R.layout.cellgrid, parent, false);
		} else {
			grid = (View) convertView;
		}

		ImageView imageView = (ImageView) grid.findViewById(R.id.imagepart);
		TextView textView = (TextView) grid.findViewById(R.id.textpart);
		imageView.setImageResource(mThumbIds[position]);
		textView.setText("Картинка " + String.valueOf(position));

		return grid;
	}

	// references to our images
	public Integer[] mThumbIds = { R.drawable.card1, R.drawable.card2,
			R.drawable.card3, R.drawable.card4, R.drawable.card5,
			R.drawable.card6, R.drawable.card7, R.drawable.card8,
			R.drawable.card9, R.drawable.card10, R.drawable.card11,
			R.drawable.card12, R.drawable.card13, R.drawable.card14,
			R.drawable.card15, R.drawable.card16, R.drawable.card17,
			R.drawable.card18, R.drawable.card19, R.drawable.card20,
			R.drawable.card21 };
}

Осталось вызвать нужный адаптер в активности:


package ru.alexanderklimov.gridview;

import ...

public class GridViewDemoActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		GridView gridview = (GridView) findViewById(R.id.gridview);
		gridview.setAdapter(new ImageTextAdapter(this));

		gridview.setOnItemClickListener(gridviewOnItemClickListener);
	}

	private GridView.OnItemClickListener gridviewOnItemClickListener = new GridView.OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> parent, View v, int position,
				long id) {
			// TODO Auto-generated method stub
			
			// Sending image id to FullScreenActivity
			Intent i = new Intent(getApplicationContext(),
					FullImageActivity.class);
			// passing array index
			i.putExtra("id", position);
			startActivity(i);
		}
	};
}

Получим результат:

GridView

Убрать вертикальную прокрутку

Прочитал заметку про убирание вертикальной прокрутки, которая возникает при движении пальцем вверх. Может пригодится кому-то:


gridview.setOnTouchListener(new OnTouchListener(){
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_MOVE){
            return true;
        }
        return false;
    }
});

Галерея

Рассмотрим вариант создания галереи на основе GridView.

Создаём новый проект. Также нужно подготовить фотографии для галереи, которые следует поместить в папку res/drawable-hdpi.

Поместим на главном экране приложения GridView:


<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/grid_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:columnWidth="90dp"
    android:gravity="center"
    android:horizontalSpacing="10dp"
    android:numColumns="auto_fit"
    android:stretchMode="columnWidth"
    android:verticalSpacing="10dp" >

</GridView>

Создадим новый класс ImageAdapter.java, наследующий от BaseAdapter, для размещения изображений в сетке GridView через собственный адаптер.


package ru.alexanderklimov.gridview;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;

public class ImageAdapter extends BaseAdapter {

	private Context mContext;

	// Keep all Images in array
	public Integer[] mThumbIds = { R.drawable.photo1, R.drawable.photo2,
			R.drawable.photo3, R.drawable.photo4, R.drawable.photo5,
			R.drawable.photo6, R.drawable.photo7, R.drawable.photo8,
			R.drawable.photo9, R.drawable.photo10, R.drawable.photo11,
			R.drawable.photo12, R.drawable.photo13, R.drawable.photo14,
			R.drawable.photo15 };

	// Constructor
	public ImageAdapter(Context c) {
		mContext = c;
	}

	@Override
	public int getCount() {
		return mThumbIds.length; // длина массива
	}

	@Override
	public Object getItem(int position) {
		return mThumbIds[position];
	}

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

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ImageView imageView = new ImageView(mContext);
		imageView.setImageResource(mThumbIds[position]);
		imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
		imageView.setLayoutParams(new GridView.LayoutParams(120, 110));
		return imageView;
	}
}

Открываем основной класс приложения и связываем через созданный адаптер изображения с GridView:


package ru.alexanderklimov.gridview;

import android.app.Activity;
import android.os.Bundle;
import android.widget.GridView;

public class GridLayoutDemoActivity extends Activity {
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

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

		// устанавливаем адаптер через экземпляр класса ImageAdapter
		gridView.setAdapter(new ImageAdapter(this));
	}
}

Запустим проект и проверим, что всё отображается нормально.

Галерея

Не обращайте внимания, что картинки на скриншоте повторяются, просто было лень готовить пятнадцать разных фотографий.

На этом урок можно было закончить, но давайте доработаем приложение, чтобы выбранная картинка отображалась в полном размере на весь экран. Для этого нужно передать идентификатор выбранного изображения новой активности.

Создадим в папке layout файл разметки full_image.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="match_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/full_image_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

Создадим новый класс FullImageActivity.java для активности, которая будет отображать картинку на весь экран. Активность через намерение будет получать идентификатор картинки и выводить её на экран.


package ru.alexanderklimov.gridlayout;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ImageView;

public class FullImageActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.full_image);

		// get intent data
		Intent intent = getIntent();

		// Selected image id
		int position = intent.getExtras().getInt("id");
		ImageAdapter imageAdapter = new ImageAdapter(this);

		ImageView imageView = (ImageView) findViewById(R.id.full_image_view);
		imageView.setImageResource(imageAdapter.mThumbIds[position]);
	}
}

Не забываем прописать новый класс в манифесте проекта.

Возвращаемся к главной активности и добавляем обработчик щелчков на сетке:


package ru.alexanderklimov.gridlayout;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.view.View;

public class GridLayoutDemoActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

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

		// устанавливаем адаптер через экземпляр класса ImageAdapter
		gridView.setAdapter(new ImageAdapter(this));

		gridView.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> parent, View v,
					int position, long id) {

				// посылаем идентификатор картинки в FullScreenActivity
				Intent i = new Intent(getApplicationContext(),
						FullImageActivity.class);
				// передаем индекс массива
				i.putExtra("id", position);
				startActivity(i);
			}
		});
	}
}

Снова запускаем проект и щёлкаем по любой миниатюре - должен запуститься новый экран с картинкой во весь рост. Теперь можно разглядеть кота получше.

Галерея Галерея

Загружаем картинки из внешнего накопителя

Попробуем загрузить картинки с внешнего накопителя в GridView. Пример писался под Android 2.3, возможно сейчас уже не заработает.

Разметка основного экрана состоит из одного компонента GridView:


<?xml version="1.0" encoding="utf-8"?>
<GridView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/gridView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000"
    android:gravity="center"
    android:horizontalSpacing="10dp"
    android:numColumns="auto_fit"
    android:stretchMode="columnWidth"
    android:verticalSpacing="10dp" >

</GridView>

Для данного компонента нужен адаптер. Создадим новый класс ImageAdapter.

ImageAdapter.java


package ru.alexanderklimov.test;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;

public class ImageAdapter extends BaseAdapter {
	private Context mContext;
	ArrayList<String> itemList = new ArrayList<String>();

	public ImageAdapter(Context context) {
		mContext = context;
	}

	void add(String path) {
		itemList.add(path);
	}

	@Override
	public int getCount() {
		return itemList.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return itemList.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ImageView imageView;
		if (convertView == null) { // if it's not recycled, initialize some
									// attributes
			imageView = new ImageView(mContext);
			imageView.setLayoutParams(new GridView.LayoutParams(220, 220));
			imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
			imageView.setPadding(8, 8, 8, 8);
		} else {
			imageView = (ImageView) convertView;
		}

		Bitmap bm = decodeSampledBitmapFromUri(itemList.get(position), 220,
				220);

		imageView.setImageBitmap(bm);
		return imageView;
	}

	public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth,
			int reqHeight) {
		Bitmap bm = null;
		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(path, options);

		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth,
				reqHeight);

		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;
		bm = BitmapFactory.decodeFile(path, options);

		return bm;
	}

	public int calculateInSampleSize(BitmapFactory.Options options,
			int reqWidth, int reqHeight) {
		// Raw height and width of image
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {
			if (width > height) {
				inSampleSize = Math.round((float) height
						/ (float) reqHeight);
			} else {
				inSampleSize = Math.round((float) width / (float) reqWidth);
			}
		}
		return inSampleSize;
	}
}

Код для главной активности:


package ru.alexanderklimov.test;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.util.TypedValue;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.Toast;

public class MainActivity extends Activity {

	// Путь к картинкам на внешнем накопителе
	private static final String PHOTO_ALBUM = "Cats";
	// Число колонок в GridView
	public static final int NUM_OF_COLUMNS = 3;
	// Отступы между картинками
	public static final int GRID_PADDING = 8; // dp

	// Поддерживаемые форматы файлов
	public static final List<String> FILE_EXTN = Arrays.asList("jpg", "jpeg",
			"png");

	ImageAdapter mImageAdapter;

	GridView gridView;

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

		gridView = findViewById(R.id.gridView);
		initilizeGridLayout();
		
		mImageAdapter = new ImageAdapter(this);
		gridView.setAdapter(mImageAdapter);

		String ExternalStorageDirectoryPath = Environment
				.getExternalStorageDirectory().getAbsolutePath();

		String targetPath = ExternalStorageDirectoryPath + File.separator
				+ PHOTO_ALBUM;

		File targetDirectory = new File(targetPath);

		// Проверяем, что это каталог
		if (targetDirectory.isDirectory()) {
			// получаем имена файлов в папке
			File[] listFiles = targetDirectory.listFiles();

			// Check for count
			if (listFiles.length > 0) {
				// проходим в цикле через все файлы
				for (int i = 0; i < listFiles.length; i++) {

					// получаем путь к файлу
					String filePath = listFiles[i].getAbsolutePath();

					// проверяем на формат файлов
					if (isSupportedFile(filePath)) {
						// если картинка, то добавляем в список
						// filePaths.add(filePath);
						mImageAdapter.add(filePath);
					}
				}
			} else {
				// Если указанная папка пуста
				Toast.makeText(
						getApplicationContext(),
						PHOTO_ALBUM
								+ " пуста. Загрузите сначала картинки котов в эту папку!",
						Toast.LENGTH_LONG).show();
			}

		} else {
			AlertDialog.Builder alert = new AlertDialog.Builder(this);
			alert.setTitle("Error!");
			alert.setMessage(PHOTO_ALBUM + " - такой папки нет!");
			alert.setPositiveButton("OK", null);
			alert.show();
		}
		gridView.setOnItemClickListener(myOnItemClickListener);
	}

	// Проверка на поддержку форматов файлов
	private boolean isSupportedFile(String filePath) {
		String ext = filePath.substring((filePath.lastIndexOf(".") + 1),
				filePath.length());

		if (FILE_EXTN.contains(ext.toLowerCase(Locale.getDefault())))
			return true;
		else
			return false;
	}

	/*
	 * Получаем ширину экрана
	 */
	private int getScreenWidth() {
		int columnWidth;
		WindowManager wm = (WindowManager) this
				.getSystemService(Context.WINDOW_SERVICE);
		Display display = wm.getDefaultDisplay();

		final Point point = new Point();
		display.getSize(point);

		columnWidth = point.x;
		return columnWidth;
	}

	// Настраиваем GridView программно
	private void initilizeGridLayout() {
		Resources r = getResources();
		float padding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
				GRID_PADDING, r.getDisplayMetrics());

		int columnWidth = (int) ((getScreenWidth() - ((NUM_OF_COLUMNS + 1) * padding)) / NUM_OF_COLUMNS);

		gridView.setNumColumns(NUM_OF_COLUMNS);
		gridView.setColumnWidth(columnWidth);
		gridView.setStretchMode(GridView.NO_STRETCH);
		gridView.setPadding((int) padding, (int) padding, (int) padding,
				(int) padding);
		gridView.setHorizontalSpacing((int) padding);
		gridView.setVerticalSpacing((int) padding);
	}
	
	OnItemClickListener myOnItemClickListener = new OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position,
				long id) {
			String prompt = (String) parent.getItemAtPosition(position);
			Toast.makeText(getApplicationContext(), prompt, Toast.LENGTH_LONG)
					.show();
		}
	};
}

В этом примере при щелчке выводится всплывающее сообщение. Вы можете запустить новую активность с показом выбранной картинки.

Дополнительное чтение

Загружаем картинки из MediaStore через свой SimpleCursorAdapter

Реклама