6.1. Всплывающее уведомление — Toast.

К главе 6
К разделу 2
К оглавлению

Исходный код

Введение

Toast представляет собой всплывающее сообщение, которое позволяет быстро оповестить пользователя о произошедшем событии, например, сохранении настроек программы на SD-карте. Особенность Toast заключается в том, что во время появления сообщения пользователь может взаимодействовать с находящимися за ним Activity, либо с домашним экраном (home screen). Также стоит заметить, что пользователь не может контролировать закрытие Toast с помощью аппаратной кнопки Back или других возможных в случае Activity способов, сообщение плавно появляется, а потом само же плавно исчезает. Время задержки между появлением и исчезновением можно задавать программно. В большинстве случаев Toast представляет собой короткое сообщение, но присутствует возможность задать произвольный внешний вид Toast, например, добавить изображение рядом с текстом. Помимо этого можно управлять расположением Toast на экране. Toast может быть создан из Activity, Service или BroadcastReceiver. В случае создания из сервиса или ресивера Toast появляется поверх Activity, которое имеет фокус, либо поверх домашнего экрана.

Создание стандартного Toast

Создать стандартный Toast можно через статичный метод makeText класса Toast, задав необходимые параметры.

Toast.makeText(getApplicationContext(), R.string.hello_world, Toast.LENGTH_SHORT).show();

В качестве параметров задается контекст приложения, сообщение и задержка между появлением и исчезновением. Сообщение может быть задано непосредственно в виде текста, либо используя текстовый ресурс-строку, например, R.string.hello_world, в котором хранится текст, который необходимо отобразить, в нашем случае «Привет, мир!». Задержка может быть короткой — LENGTH_SHORT, либо длинной — LENGTH_LONG. По умолчанию при создании Toast задается короткая задержка. Программно задержка задается методом setDuration().

Суть метода makeText такова: внутри метода создается объект класса Toast, устанавливается текст сообщения и тип задержки. Далее к объекту может быть либо применен, как в нашем случае, метод show, который отображает созданный Toast, либо заданы дополнительные свойства Toast, например, его расположение на экране или созданный вами внешний вид. Созданный Toast показан на рисунке 1.

Рисунок 1. Стандартный Toast.

Изменение положения Toast

Расположение Toast на экране задается с помощью метода setGravity следующим образом:

Toast toast = Toast.makeText(getApplicationContext(), R.string.hello_world, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();

Первый параметр метода задает выравнивание, вариантов которого довольно много в классе Gravity. Второй и третий параметры задают, на сколько пикселей будет смещен Toast по горизонтали вправо и по вертикали вниз соответственно относительно значения, заданного в первом параметре. Результат приведенного выше кода показан на рисунке 2.

Рисунок 2. Стандартный Toast с заданным расположением.

Добавление изображения в стандартный Toast

Для добавления изображения в стандартный Toast потребуется программно создать объект класса ImageView и задать для него изображение из ресурсов с помощью метода setImageResource. Затем потребуется получить стандартный внешний вид Toast (если посмотреть в отладчике он является LinearLayout) и добавить в него созданный объект ImageView с указанием, в какую позицию добавить изображение, в нашем случае указана нулевая позиция, чтобы изображение было добавлено выше текста. Код для создания этого Toast с изображением представлен ниже.

Toast toast = Toast.makeText(getApplicationContext(), R.string.hello_world, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
LinearLayout toastView = (LinearLayout) toast.getView();
ImageView imageWorld = new ImageView(getApplicationContext());
imageWorld.setImageResource(R.drawable.world);
toastView.addView(imageWorld, 0);
toast.show();

Созданный таким образом Toast выглядит как на рисунке 3.

Рисунок 3. Стандартный Toast с встроенным изображением.

Создание Toast с нестандартным оформлением

Для создания Toast с нестандартным оформлением потребуется создать собственный layout, код которого выглядит следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_height="wrap_content" android:layout_width="wrap_content"
	android:background="@color/white" android:orientation="vertical"
	android:id="@+id/llToast">
	<TextView android:layout_height="wrap_content"
		android:layout_margin="1dip" android:textColor="@color/white"
		android:layout_width="fill_parent" android:gravity="center"
		android:background="@color/dark_gray" android:id="@+id/tvTitleToast">
	</TextView>
	<LinearLayout android:layout_height="wrap_content"
		android:orientation="vertical" android:id="@+id/llToastContent"
		android:layout_marginLeft="1dip" android:layout_marginRight="1dip"
		android:layout_marginBottom="1dip" android:layout_width="wrap_content"
		android:padding="15dip" android:background="@color/gray">
		<ImageView android:layout_height="wrap_content"
			android:layout_gravity="center" android:layout_width="wrap_content"
			android:id="@+id/tvImageToast" />
		<TextView android:layout_height="wrap_content"
			android:paddingRight="10dip" android:paddingLeft="10dip"
			android:layout_width="wrap_content" android:gravity="center"
			android:textColor="@color/black" android:id="@+id/tvTextToast" />
	</LinearLayout>
</LinearLayout>

Toast будет выглядеть в виде диалога с заголовком, внутри которого располагаются изображение и текст. Этот layout нужно прописать для Toast и задать сообщения для заголовка и текста, а также задать изображение. Делается это следующим образом:

LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toast, (ViewGroup) findViewById(R.id.llToast));
ImageView image = (ImageView) layout.findViewById(R.id.tvImageToast);
image.setImageResource(R.drawable.world);
TextView title = (TextView) layout.findViewById(R.id.tvTitleToast);
title.setText(R.string.attention);
TextView text = (TextView) layout.findViewById(R.id.tvTextToast);
text.setText(R.string.hello_world);

Toast toast = new Toast(getApplicationContext());
toast.setGravity(Gravity.RIGHT | Gravity.TOP, 12, 40);
toast.setDuration(Toast.LENGTH_LONG);
toast.setView(layout);
toast.show();

В первых двух строках происходит инициализация объекта View путем наполнения его из xml-файла (для этого используется экземпляр класса LayoutInflater, получаемый с помощью метода getLayoutInflater), созданного ранее. Первый параметр метода inflate задает идентификатор созданного ранее layout – R.layout.toast (в данном случае он соответствует файлу res/layout/toast.xml). Затем получаются ссылки на изображение, заголовок и текст сообщения, и заполняются нужными данными. Далее непосредственно создается Toast, задаются необходимые параметры и в качестве layout прописывается тот layout, который мы инициализировали ранее. Делается это с помощью метода setView. В качестве строковых значений используются ресурсы R.string.attention (“Внимание”) и R.string.hello_world (“Привет, мир!”). В результате всех этих манипуляций у нас получится Toast, представленный на рисунке 4.

Рисунок 4. Toast с отдельно созданным внешним видом.

Вызов Toast из другого потока

Для вызова Toast из другого потока необходимо объявить в вашем классе переменную-член типа Handler следующим образом:

Handler handler = new Handler();

Теперь допустим у вас есть поток, в котором нужно вызвать функцию, отображающую Toast на экране:

new Thread(new Runnable() {
	public void run() {
		showToast();
	}
}).start();

В данном случае функция будет выполняться в отдельно созданном потоке, но Toast может быть отображен только в главном потоке, поэтому в процессе выполнения вы увидите сообщение об ошибке.

Чтобы выполнить действия в главном потоке при вызове из отдельного потока, необходим Handler, который мы объявили ранее. Отобразить Toast из созданного потока можно следующим образом:

public void showToast() {
	handler.post(new Runnable() {
		public void run() {
			Toast.makeText(getApplicationContext(), R.string.hello_world, Toast.LENGTH_SHORT).show();
		}
	});
}

Исходный код

К главе 6
К разделу 2
К оглавлению