Денис Колисниченко



Pdf просмотр
страница5/8
Дата05.11.2016
Размер5.05 Kb.
Просмотров1917
Скачиваний0
1   2   3   4   5   6   7   8

, или методом setImageResource(int)
В файле разметки элемент

описывается так:

Работа с такой кнопкой осуществляется так же, как и с обычной кнопкой. Первым делом нужно подключить необходимый пакет, объявить переменную и найти сам элемент в файле разметки: import android.widget.ImageButton;
ImageButton button; button = (ImageButton)findViewById(R.id.button); button.setImageResource(R.drawable.play);
Последние два оператора находят кнопку
ImageButton и устанавливают для нее изо- бражение с именем play
, которое находится в папке res/drawable или res/drawable-*
(имя зависит от разрешения экрана — для более новых платформ Android). Лучше всего использовать файлы в формате PNG. В нашем случае (ресурс
R.drawable. play
) в каталоге res/drawable должен быть файл play.png
Обработчик нажатия кнопки устанавливается так же, как и для обычной кнопки
Button
5.2.3. Индикатор ProgressBar
Сейчас мы рассмотрим довольно интересный виджет —
ProgressBar
, представляю- щий собой индикатор (шкалу) процесса.
Начнем с разметки (листинг 5.16). Наша деятельность будет содержать два поля ввода, кнопку и, конечно же,
ProgressBar
. Редактор разметки для нашего приложе- ния показан на рис. 5.24.
Листинг 5.16. Разметка для ProgressBar


Глава 5. Разработка интерфейса пользователя
121
Рис. 5.24. Редактор разметки для деятельности настройки ProgressBar android:layout_width="match_parent" android:layout_height="match_parent"
>




122
Часть II. Базовое программирование для Android



Прежде чем приступать к написанию Java-кода, нужно разобраться, как станет ра- ботать наше приложение. Максимальное значение для
ProgressBar устанавливается в поле Maximum Value, шаг (величина, на которую изменяется значение
ProgressBar каждые полсекунды, или 500 мс) задается значением, указанным в поле
Increment by
. При нажатии кнопки Start появится диалоговое окно, в котором и будет отображен наш индикатор
ProgressBar
. Увеличение значения
ProgressBar производится в потоке каждые 500 мс. Понимаю, что с диалоговыми окнами мы еще пока не работали, но они будут рассмотрены уже в следующей главе.
Полный исходный Java-код представлен в листинге 5.17.
Листинг 5.17. Полный Java-код приложения package com.samples.test5; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.app.ProgressDialog; public class Test5Activity extends Activity implements OnClickListener {
ProgressDialog dialog; int increment;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test5);
Button startbtn = (Button) findViewById(R.id.startbtn); startbtn.setOnClickListener(this);
}

Глава 5. Разработка интерфейса пользователя
123 public void onClick(View view) {
// получаем шаг инкремента из текстового поля
EditText et = (EditText) findViewById(R.id.increment);
// конвертируем строку в число increment = Integer.parseInt(et.getText().toString());

// создаем новое диалоговое окно dialog = new ProgressDialog(this); dialog.setCancelable(true); dialog.setMessage("Loading...");
// шкала должна быть горизонтальной dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// значение шкалы по умолчанию — 0 dialog.setProgress(0);
// получаем максимальное значение
EditText max = (EditText) findViewById(R.id.maximum);
// конвертируем строку в число int maximum = Integer.parseInt(max.getText().toString());
// устанавливаем максимальное значение dialog.setMax(maximum);
// отображаем диалоговое окно dialog.show();
// создаем поток для обновления шкалы
Thread background = new Thread (new Runnable() { public void run() { try {
// увеличиваем значение шкалы каждые 500 мс,
// пока не будет достигнуто максимальное значение while (dialog.getProgress()<= dialog.getMax()) {
// ждем 500 мс
Thread.sleep(500);
// активируем обработчик обновления progressHandler.sendMessage(progressHandler.obtainMessage());
}
} catch (java.lang.InterruptedException e) {
}
}
});
// запускаем фоновый поток background.start();
}

124
Часть II. Базовое программирование для Android
// обработчик для фонового обновления
Handler progressHandler = new Handler() { public void handleMessage(Message msg) {
// увеличиваем значение шкалы dialog.incrementProgressBy(increment);
}
};
}
Запустите приложение, установите параметры (рис. 5.25) и нажмите кнопку
Start
— вы увидите диалоговое окно и работающий в нем
ProgressBar
(рис. 5.26).

Рис. 5.25. Установка параметров
ProgressBar
5.2.4. Средства отображения графики
Отображение графики осуществляется с помощью базового виджета
ImageView
. Для загрузки изображения в классе
ImageView существует несколько методов: setImageResource(int resId)
— загружает изображение из ресурса; setImageURI(Uri uri)
— загружает изображение по его URI; setImageBitmap(Bitmap bitmap)
— загружает растровое изображение.

Глава 5. Разработка интерфейса пользователя
125

Рис. 5.26. Шкала в действии
Для изменения размера изображения служат следующие методы: setMaxHeight()
— устанавливает максимальную высоту; setMaxWidth()
— устанавливает максимальную ширину.
Если вы хотите загрузить изображение из файла разметки, то воспользуйтесь атри- бутом android:src
. При добавлении
ImageView с помощью редактора разметки от- кроется окно, позволяющее выбрать изображение из списка ресурсов проекта или системных ресурсов (рис. 5.27).
В файле разметки виджет
ImageView определяется так:


126
Часть II. Базовое программирование для Android
Рис. 5.27. Выбор ресурса
После этого в Java-коде работа с виджетом производится так: final ImageView image = (ImageView)findViewById(R.id.imageView1);
// загружаем изображение из ресурса image.setImageResource(R.drawable.icon);
5.2.5. Виджеты AnalogClock и DigitalClock
Виджеты
AnalogClock
(аналоговые часы) и
DigitalClock
(цифровые часы) исполь- зуются для отображения системного времени.
Добавьте в проект оба виджета — они находятся на вкладке Time & Date редактора разметки, там же вы найдете средства не только отображения, но и выбора даты и времени.
Разметка приложения приведена в листинге 5.18. Сами виджеты в действии показа- ны на рис. 5.28.
Листинг 5.18. Разметка приложения с часами


Глава 5. Разработка интерфейса пользователя
127




Рис. 5.28. Виджеты AnalogClock и DigitalClock
5.2.6. Использование компонента DatePicker
В секции Time & Date есть два очень важных компонента: TimePicker и
DatePicker
. Оба компонента используются аналогично, поэтому далее будет рас- смотрен только DatePicker.

128
Часть II. Базовое программирование для Android
Стоит отметить, что этот компонент требует минимального уровня API 11 (Android
3.0), поэтому если в файле
AndroidManifest.xml у вас указан минимальный уровень
API 8, то это нужно исправить:

Далее надо расположить компоненты на форме, как показано на рис. 5.29. В лис- тинге 5.19 приведена разметка этого приложения.
Рис. 5.29. Использование компонента DatePicker
Листинг 5.19. Файл разметки приложения выбора даты


Глава 5. Разработка интерфейса пользователя
129

130
Часть II. Базовое программирование для Android public void onDateChanged(DatePicker view, int year, int monthOfYear,int dayOfMonth) {

CurDateTv2.setText(new StringBuilder()

// нумерация месяцев начинается с 0, поэтому нужно увеличить
// значение month на 1

.append(dayOfMonth).append("/").append(monthOfYear + 1)
.append("/").append(year).append(" "));

}
});
Обработчик события не делает ничего сверхъестественного, а просто устанавливает дату, которую выбрал пользователь, в качестве значения textView
Компоненты TimePicker и DatePicker редко кто использует в качестве виджетов.
Как правило, в этих целях создаются диалоговые окна выбора времени и даты, с которыми мы познакомимся в следующей главе.
Итак, здесь мы рассмотрели основные виджеты. С остальными виджетами вы можете познакомиться, прочитав руководство разработчика Android: http://developer.android.com/reference/android/package-summary.html




ГЛ А В А
6

Уведомления, диалоговые окна и меню
6.1. Уведомления
Приложения могут отображать два типа уведомлений: краткие всплывающие со- общения (Toast Notification) и постоянные напоминания (Status Bar Notification).
Первые отображаются на экране мобильного устройства какое-то время и не тре- буют внимания пользователя. Как правило, это не критические информационные сообщения. Вторые постоянно отображаются в строке состояния и требуют реак- ции пользователя.
Например, приложение требует подключения к вашему серверу. Если соединение успешно установлено, можно отобразить краткое уведомление, а вот если подклю- читься не получилось, тогда отображается постоянное уведомление, чтобы пользо- ватель сразу мог понять, почему приложение не работает.
Чтобы отобразить всплывающее сообщение, используйте класс
Toast и его методы makeText
(создает текст уведомления) и show
(отображает уведомление):
Context context = getApplicationContext();
Toast toast = Toast.makeText(context, "This is notification",

Toast.LENGTH_LONG); toast.show();
Первый параметр метода makeText()
— это контекст приложения, который можно получить с помощью вызова getApplicationContext()
. Второй параметр — текст уведомления. Третий — задает продолжительность отображения уведомления:
LENGTH_SHORT
— небольшая продолжительность (1–2 секунды) отображения тек- стового уведомления;
LENGTH_LONG
— показывает уведомление в течение более длительного периода времени (примерно 4 секунды).
По умолчанию всплывающее уведомление появится в нижней части экрана. Чтобы отобразить уведомление в другом месте, можно воспользоваться методом setGravity()
, который нужно вызвать до метода show()
: toast.setGravity(Gravity.CENTER, 0, 0);


132
Часть II. Базовое программирование для Android
Первый параметр задает размещение в пределах большего контейнера — например,
GRAVITY.CENTER
,
GRAVITY.TOP
и т. д. Второй параметр — это смещение по оси
X, тре- тий — смещение по оси
Y.
В нашем примере уведомление будет отображено по центру окна.
Теперь немного практики. Создайте новый проект (пусть он называется
Test6
— для совместимости с моим кодом), разметку можете не изменять, а можете вообще удалить все элементы деятельности. Наше приложение отобразит при запуске уве- домление (рис. 6.1).
Рис. 6.1. Всплывающее уведомление
Java-код приложения представлен в листинге 6.1.
Листинг 6.1. Отображение всплывающего уведомления package com.samples.test6; import android.app.Activity; import android.os.Bundle;

Глава 6. Уведомления, диалоговые окна и меню
133 import android.widget.Toast; import android.content.Context; import android.view.Gravity; public class Test6Activity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
Context context = getApplicationContext();
Toast toast = Toast.makeText(context, "Это уведомление",
Toast.LENGTH_SHORT); toast.setGravity(Gravity.CENTER, 0, 0); toast.show();
}
}
Создать уведомление в строке состояния немного сложнее. И тем более в совре- менных версиях Android. Ведь раньше для создания таких уведомлений использо- вались классы
Notification и
NotificationManager
. В Android 4 и 5 вместо класса
Notification нужно использовать класс
Notification.Builder
. В листинге 6.2, а приводится старая версия кода, а в листинге 6.2, б — новая (чтобы вы могли срав- нить).
Листинг 6.2, а. Старая версия кода
(классы Notification и NotificationManager) int NOTIFY_ID = 101;
Context context = getApplicationContext();
NotificationManager Mgr =
(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); int icon = R.drawable.icon;
CharSequence cText = "Ошибка!"; long t = System.currentTimeMillis();
Notification notify = new Notification(icon, cText, t);
CharSequence nTitle = "Ошибка";
CharSequence nText = "Не могу подключиться к серверу";
Intent intent = new Intent(this, Test6Activity.class);
PendingIntent cIntent = PendingIntent.getActivity(this, 0, intent, 0); notify.setLatestEventInfo(context, nTitle, nText, cIntent);
Mgr.notify(NOTIFY_ID, notify);

134
Часть II. Базовое программирование для Android
Листинг 6.2, б. Новая версия кода для Android 4 и 5
(класс Notification.Builder) package com.glava.glava6; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.content.Context; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Intent; import android.content.res.*; public class MainActivity extends ActionBarActivity {
private static final int NOTIFY_ID = 101;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
Context context = getApplicationContext();

Intent notificationIntent = new Intent(context, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(context,

0, notificationIntent,

PendingIntent.FLAG_CANCEL_CURRENT);

NotificationManager nm = (NotificationManager) context

.getSystemService(Context.NOTIFICATION_SERVICE);


Resources res = context.getResources();
Notification.Builder builder = new Notification.Builder(context); builder.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_launcher)
// большая картинка
//
.setLargeIcon(R.drawable.ic_launcher)

//.setTicker(res.getString(R.string.warning)) // текст в строке состояния
.setTicker("Ошибка!")
.setWhen(System.currentTimeMillis()
.setAutoCancel(true)

Глава 6. Уведомления, диалоговые окна и меню
135
//
Заголовок уведомления
.setContentTitle("Ошибка!")
// Текст уведомления

.setContentText("Не могу подключиться к серверу");
Notification n
= builder.getNotification();
//Notification n
= builder.build(); nm.notify(NOTIFY_ID, n);
}
}
Как вы могли заметить, в листинге 6.2, б приводится полный код приложения, а не его фрагмент. Код хоть и хорошо закомментирован, но есть некоторые нюансы, которые вам следует знать. Метод setSmallIcon()
формирует маленькую картинку уведомления, а setLargeIcon()
— большую. Я большую не указал, поскольку мне для демо-проекта ее готовить не захотелось. Однако в реальном приложении вы этот метод будете использовать часто. Метод setTicker()
устанавливает в строке состояния текст сообщения, которое исчезнет, как только вы его просмотрите, — останется только картинка, заданная с помощью setSmallIcon()
. Методы setContentTitle()
и setContentText()
задают, соответственно, заголовок и текст уведомления.
Метод getNotification()
считается уже устаревшим, и на смену ему пришел метод build()
. Однако метод build()
можно использовать, если только в настройках про- екта установлен минимальный уровень API 16 (Android 4.1.2). Поэтому, если вы пишете приложение для самых современных версий Android, устанавливайте ми- нимальный уровень API 16 или выше и используйте метод build()
. Если же вам нужно написать приложение, которое должно работать пусть не в самых древних версиях (та же 4.0 — это API 15), используйте метод getNotification()
и не обра- щайте внимания на предупреждение об устаревшем коде. Приложения с этим ме- тодом будут нормально выполняться и на более новых версиях Android.
Результат наших стараний приведен на рис. 6.2.
Но это еще не все. Вы можете отменить собственные уведомления, когда в них пропадает необходимость (например, ваша программа уже может установить со- единение с сервером, а уведомление об ошибке все еще продолжает «висеть» в строке уведомления): nm.cancel(NOTIFY_ID); // nm - экземпляр класса NotificationManager
Если нужно в уведомлении выводить индикатор процесса (вы видели такой при установке программ из Play Маркет), используйте метод setProgress()
: setProgress(100, 75, false);
При появлении уведомления можно заставить смартфон звучать (
SOUND
), вибриро- вать (
VIBRATE
), а также мерцать (
LIGHT
). Для всего этого используются следующие константы:

136
Часть II. Базовое программирование для Android
Notification.DEFAULT_SOUND
;

Notification.DEFAULT_VIBRATE
;

Notification.DEFAULT_LIGHTS

Нужное поведение задается так: notification.defaults = Notification.DEFAULT_SOUND |
Notification.DEFAULT_VIBRATE;
Рис. 6.2. Уведомление в строке состояния (Android 4.4)
Если вам нужно все и сразу, используйте константу
Notification.DEFAULT_ALL
Только не забудьте для доступа к виброзвонку в файл манифеста добавить строчку:

6.2. Диалоговые окна
В предыдущей главе мы познакомились с диалоговым окном
ProgressDialog
, ото- бражающим индикатор
ProgressBar
, поэтому этот тип диалогового окна мы рас- сматривать не станем. Но кроме
ProgressDialog
, в Android предусмотрены диалого- вые окна следующих типов:
AlertDialog
— диалоговое окно с кнопками;
DatePickerDialog
— диалоговое окно выбора даты;
TimePickerDialog
— диалоговое окно выбора времени.

Глава 6. Уведомления, диалоговые окна и меню
137 6.2.1. AlertDialog
Самый частый вариант применения диалогового окна
AlertDialog
— это классиче- ское диалоговое окно вопроса с кнопками Да и Нет. Вот сейчас мы и займемся его разработкой. После запуска наше приложение отобразит диалоговое окно (рис. 6.3), в котором при нажатии кнопки Нет не будет произведено никаких действий — бу- дет вызван метод cancel()
. А вот действие при нажатии кнопки Да вы запрограм- мируете сами — но позже, когда научитесь устанавливать интернет-соединения.
Код приложения, отображающего это диалоговое окно, представлен в листинге 6.3.
Рис. 6.3. Диалоговое окно типа
AlertDialog
Листинг 6.3. Отображение диалогового окна типа AlertDialog package com.sample.dialog; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.content.DialogInterface; import android.app.AlertDialog; public class MainActivity extends ActionBarActivity {
@Override

138
Часть II. Базовое программирование для Android protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
AlertDialog.Builder alt_bld = new AlertDialog.Builder(this);
// Сообщение диалога alt_bld.setMessage("Подключиться к dkws.org.ua ?")
.setCancelable(false)
.setPositiveButton("Да", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) {
// Действие для кнопки Да
}
})
.setNegativeButton("Нет", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) {
// Действие для кнопки Нет dialog.cancel();
}
});
AlertDialog alert = alt_bld.create();
// Title for AlertDialog alert.setTitle("Соединение");
// Icon for AlertDialog alert.setIcon(R.drawable.ic_launcher); alert.show();
}
}
Далее мы рассмотрим диалоговые окна выбора даты и времени.
6.2.2. DatePickerDialog
Диалоговые окна выбора даты и времени весьма «многострадальные». С ними веч- но все не так. Мало того, что код вызова таких диалоговых окон довольно непро- стой, так еще и меняется из версии в версию API. Так, для показа диалогового окна ранее использовался метод
ShowDialog()
, который сейчас применять не рекоменду- ется. Вместо него нужно задействовать вот такую конструкцию, вовлекающую ме- тод show()
:
DatePickerDialog dpg = new DatePickerDialog(this, mDateSetListener, mYear, mMonth, mDay); dpg.show();
А что, если нужно, чтобы программа была максимально совместима со всеми версиями? Тогда следует использовать
ShowDialog() и в то же время обеспечить,

Глава 6. Уведомления, диалоговые окна и меню
139 чтобы среда разрешила компиляцию. Для этого нужно добавить директиву
@SuppressWarnings("deprecation")
. Да, решение не очень хорошее, но зато работает от API 8 (2.
x) до API 21 (5.0).
Я старался максимально упростить приводимый здесь код. Вы можете сравнить приведенный далее код с кодом (и решением) из руководства разработчика: http://developer.android.com/guide/topics/ui/controls/pickers.html
Само приложение тоже очень простое. Оно содержит только надпись с призывом выбрать дату (рис. 6.4). При щелчке по надписи открывается диалоговое окно вы- бора даты (рис. 6.5), а после выбора даты и нажатия кнопки Done выбранная поль- зователем дата отображается в надписи (рис. 6.6).

Рис. 6.4. Щелкните по надписи для выбора даты
Рис. 6.5. Диалоговое окно выбора даты
Разметка приложения приведена в листинге 6.4, а Java-код приложения — в лис- тинге 6.5.
Листинг 6.4. Разметка приложения



140
Часть II. Базовое программирование для Android




Рис. 6.6. Выбранная дата отображена в текстовой надписи
Листинг 6.5. Выбор даты package com.sample.selectdatedlg; import android.app.Activity; import android.app.DatePickerDialog; import android.app.DatePickerDialog.OnDateSetListener; import android.app.Dialog; import android.os.Bundle; import android.view.View; import android.widget.DatePicker; import android.widget.TextView;

Глава 6. Уведомления, диалоговые окна и меню
141 public class MainActivity extends Activity { int DIALOG_DATE = 1;
// Дата для инициализации (можно получить через Calendar текущую, но
// я старался сделать код как можно проще). int myYear = 2014; int myMonth = 10; // ноябрь, нумерация месяцев начинается с 0! int myDay = 03;
TextView tvDate; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvDate = (TextView) findViewById(R.id.tvDate);
}
// Добавил директиву, чтобы среда не "ругалась" на старый код
@SuppressWarnings("deprecation") public void onclick(View view) { showDialog(DIALOG_DATE);
}

@SuppressWarnings("deprecation") protected Dialog onCreateDialog(int id) { if (id == DIALOG_DATE) {
DatePickerDialog tpd = new DatePickerDialog(this, myCallBack, myYear, myMonth, myDay); return tpd;
} return super.onCreateDialog(id);
}
OnDateSetListener myCallBack = new OnDateSetListener() { public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { myYear = year;
// увеличиваем полученный месяц для отображения myMonth = monthOfYear + 1; myDay = dayOfMonth; tvDate.setText("Дата " + myDay + "/" + myMonth + "/" + myYear);
}
};
}

142
Часть II. Базовое программирование для Android
6.2.3. TimePickerDialog
Сейчас мы напишем приложение выбора времени, но оно будет немного отличать- ся от предыдущего примера. Вместо надписи у нас будет кнопка, вызывающая диа- логовое окно выбора времени (рис. 6.7), а само выбранное время будет отображено в качестве уведомления (рис. 6.8). Разметка приложения приведена в листин- ге 6.6, а, а полный код приложения — в листинге 6.6, б.

Рис. 6.7. Диалоговое окно выбора времени
Рис. 6.8. Выбранное пользователем время
Листинг 6.6, а. Выбор времени: разметка приложения

>



Глава 6. Уведомления, диалоговые окна и меню
143
Листинг 6.6, б. Выбор времени: код приложения package com.sample.timeselect; import android.app.Activity; import android.os.Bundle; import android.app.Dialog; import android.app.TimePickerDialog; import android.widget.Button; import android.widget.TimePicker; import android.widget.Toast; import android.view.View; public class MainActivity extends Activity { private Button b1; static final int TIME_DIALOG_ID = 0;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
//
Кнопка
b1 = (Button) findViewById(R.id.button1); b1.setOnClickListener(new
View.OnClickListener()
{

// Обработчик нажатия кнопки — вызываем диалог
@SuppressWarnings("deprecation") public void onClick(View v)
{ showDialog(TIME_DIALOG_ID);

}
});
}
private TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() {
// Обработчик нажатия кнопки Set диалога выбора времени public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// Отображаем уведомление с выбранным пользователем временем
Toast.makeText(MainActivity.this,

"Time is="+hourOfDay+":"+minute,

Toast.LENGTH_LONG).show();
}
};
@Override protected Dialog onCreateDialog(int id) { switch
(id)
{
case
TIME_DIALOG_ID:

144
Часть II. Базовое программирование для Android return new TimePickerDialog(this, mTimeSetListener, 0, 0, false);

} return null;
}
}
6.3. Меню
Уведомление и диалоговые окна — это хорошо, но редко какое приложение обхо- дится без меню.
Операционная система Android предлагает три вида меню:
OptionsMenu
— меню выбора опций, появляется внизу экрана при нажатии кноп- ки Menu на мобильном устройстве;
ContextMenu
— контекстное меню, появляется при долгом касании (две или бо- лее секунды) сенсорного экрана;
Submenu
— подменю, привязывается к конкретному пункту меню (меню выбора опций или контекстного меню). Пункты подменю не поддерживают вложенного меню.
В случае с
OptionsMenu существует два типа меню:
IconMenu
— меню со значками, добавляет значки к тексту в пункты меню. Это единственный тип меню, поддерживающий значки. В
IconMenu может быть мак- симум шесть пунктов;
ExpandedMenu
— расширенное меню, представляет собой вертикальный выпа- дающий список меню с кнопкой More, открывающей это расширенное меню.
Характерно только для старых версий Android, в новых меню просто отобража- ется в виде единого списка команд без кнопки More.
6.3.1. Меню выбора опций
Начнем с создания самого часто использующегося меню — меню выбора опций, которое появляется, когда пользователь нажмет кнопку Menu на мобильном уст- ройстве.
Меню можно создать в файле разметки или с помощью метода add()
. Мы будем использовать второй способ, оставив файл разметки без изменений.
Первым делом нужно определить идентификаторы создаваемых пунктов меню, де- лается это так: public static final int IDM_NEW = 101; public static final int IDM_OPEN = 102; public static final int IDM_SAVE = 103; public static final int IDM_EXIT = 104;

Глава 6. Уведомления, диалоговые окна и меню
145
В нашем меню будет четыре пункта с идентификаторами
IDM_NEW
,
IDM_OPEN
,
IDM_SAVE
,
IDM_EXIT
Далее для каждого пункта меню нужно вызвать метод add()
: menu.add(Menu.NONE, IDM_NEW, Menu.NONE, "Новая игра").setAlphabeticShortcut('n');
В нашем случае мы не только добавляем новый пункт меню, но и устанавливаем для него клавишу быстрого доступа. Если клавиша быстрого доступа не нужна, то оператор добавления нового пункта меню можно записать короче: menu.add(Menu.NONE, IDM_NEW, Menu.NONE, "Новая игра");
Методу add()
нужно передать четыре параметра: идентификатор группы меню — используется для создания сложных меню и позволяет связать новый пункт меню с группой других его пунктов. В нашем случае можно воспользоваться значением
Menu.NONE
, потому что идентификатор группы задавать не нужно; идентификатор меню — позволяет однозначно идентифицировать пункт меню, далее идентификатор поможет определить, какой пункт меню был выбран поль- зователем; порядок расположения пункта в меню — по умолчанию пункты размещаются в меню в порядке их добавления методом add()
, поэтому в качестве значения этого параметра можно тоже указать
Menu.NONE
; заголовок — задает заголовок пункта меню, видимый пользователем. Вы можете задать как текстовую константу, так и указать строковый ресурс.
Теперь создайте новый проект с именем
OptionsMenu
, имя пакета — com.samples. optmenu
. Файл разметки оставьте по умолчанию, только измените строковый ресурс hello и вместо "Hello World!"
установите значение "Нажмите кнопку Меню"
(рис. 6.9). Этим мы установим подсказку для пользователя, чтобы он знал, что нужно нажать кнопку Menu. В нашем случае пользователем являетесь вы, но все равно измените строковый ресурс — вдруг, пока запустится эмулятор, вы забудете, что хотели сделать.
Наше приложение будет работать так. Пользователь при нажатии кнопки Menu ви- дит меню, состоящее из четырех пунктов (рис. 6.10). При выборе пункта меню пользователь видит уведомление, соответствующее выбранному пункту меню
(рис. 6.11). Java-код приложения представлен в листинге 6.7.
Листинг 6.7. Меню опций package com.samples.optmenu; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem;

146
Часть II. Базовое программирование для Android
Рис. 6.9. Редактирование строкового ресурса import android.widget.Toast; import android.view.Gravity; public class OptionsMenuActivity extends Activity {
// Описываем идентификаторы пунктов меню public static final int IDM_NEW = 101; public static final int IDM_OPEN = 102; public static final int IDM_SAVE = 103; public static final int IDM_EXIT = 104;
/** Called when the activity is first created. */
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
}
@Override public boolean onCreateOptionsMenu(Menu menu) {
// Создаем пункты меню menu.add(Menu.NONE, IDM_NEW, Menu.NONE, "Новая игра"); menu.add(Menu.NONE, IDM_OPEN, Menu.NONE, "Открыть игру");

Глава 6. Уведомления, диалоговые окна и меню
147 menu.add(Menu.NONE, IDM_SAVE, Menu.NONE, "Сохранить игру"); menu.add(Menu.NONE, IDM_EXIT, Menu.NONE, "Выход");
return(super.onCreateOptionsMenu(menu));
}
@Override public boolean onOptionsItemSelected(MenuItem item) {
CharSequence t;
// Устанавливаем реакции на выбор пункта меню
// В нашем случае устанавливается текст уведомления switch (item.getItemId()) { case IDM_NEW: t = "Новая игра"; break; case IDM_OPEN: t = "Открыть игру"; break; case IDM_SAVE: t = "Сохранить игру"; break; case IDM_EXIT: t = "Выход"; break; default: return false;
}
Toast toast = Toast.makeText(this, t, Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0);
// Выводим уведомление toast.show(); return true;
}
}
Рис. 6.10. Меню опций

148
Часть II. Базовое программирование для Android
Рис. 6.11. Выбран первый пункт меню
6.3.2. Меню со значками
Меню со значками создается полностью аналогично меню опций. Только при вызо- ве метода add()
нужно еще вызвать метод setIcon()
, подобно вызову метода setAlphabeticShortcut()
: menu.add(Menu.NONE, IDM_NEW, Menu.NONE, "Новая игра").setIcon(R.drawable.new);
При этом в каталоге res/drawable*
должен присутствовать ресурс с именем new
(по- просту говоря, файл с именем new.png
).
6.3.3. Расширенное меню
В старых версиях Android, если количество пунктов меню было более шести, авто- матически появляется расширенное меню — вместо шестого пункта меню выво- дится пункт More, выбрав который пользователь получает доступ к оставшимся пунктам меню. В новых версиях такого нет. Вместо этого вы получите одно боль- шое меню, которое можно листать, если оно не помещается на одном экране. Вы- глядит оно не очень презентабельно, поэтому или сокращайте количество пунктов меню, или используйте подменю (рис. 6.12).

Глава 6. Уведомления, диалоговые окна и меню
149
Рис. 6.12. Когда пункты меню не помещаются на экране
6.3.4. Контекстное меню
Создать контекстное меню чуть сложнее, чем обычное. Ведь нужно не только соз- дать меню, но и привязать его к определенному объекту интерфейса программы, — контекстное меню должно появляться не просто так, а при долгом нажатии на оп- ределенный объект.
Поскольку в нашей простой программе особых объектов нет (если не считать раз- метки и надписи), то меню будет появляться над разметкой (
LinearLayout
). А для этого понадобится изменить файл разметки — чтобы присвоить имя элементу
LinearLayout
. Но обо всем по порядку.
Первым делом нужно подключить дополнительные Java-пакеты. С появлением контекстного меню список импортируемых пакетов увеличился (сравните его с листингом 6.7): import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.Menu; import android.view.MenuItem;

150
Часть II. Базовое программирование для Android import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.widget.Toast; import android.view.Gravity; import android.widget.LinearLayout;
Помимо пакетов, непосредственно относящихся к контекстному меню, нам нужно добавить пакеты, относящиеся к линейной разметке (к ней мы будем привязывать наше меню), и пакет android.view.View
— необходимый при создании меню.
Далее, как обычно, нужно определить идентификаторы нашего контекстного меню
(чтобы не путать элементы контекстного меню с элементами меню опций, иденти- фикаторы начинаются с двойки): public static final int IDM_RESTORE = 201; public static final int IDM_PAUSE = 202;
Далее создаем само контекстное меню:
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) { super.onCreateContextMenu(menu, v, info); menu.add(Menu.NONE, IDM_PAUSE, Menu.NONE, "Пауза"); menu.add(Menu.NONE, IDM_RESTORE, Menu.NONE, "Продолжить");
}
Тип
View требует пакет android.view.View
, поэтому мы его и импортировали. Далее создаем обработчик выбора пункта меню:
@Override public boolean onContextItemSelected(MenuItem item) {
CharSequence t; t = ""; switch(item.getItemId()) { case IDM_PAUSE: t = "Пауза"; break; case IDM_RESTORE: t = "Продолжить"; break; default: super.onContextItemSelected(item);
}
Toast toast = Toast.makeText(this, t, Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); return true;
}
Если сейчас запустить приложение, то наше меню ни при каких условиях не по- явится — ведь мы не привязали его к какому-либо виджету. Для привязки контек- стного меню к нашей разметке используются операторы: final LinearLayout game = (LinearLayout)findViewById(R.id.Main); registerForContextMenu(game);

Глава 6. Уведомления, диалоговые окна и меню
151
Чтобы эти операторы работали, нужно изменить файл разметки main.xml и присво- ить нашей линейной разметке имя main
. Файл main.xml для нашего приложения представлен в листинге 6.8.
Листинг 6.8. Файл разметки приложения с контекстным меню

>
/>

Полный код приложения, содержащего меню опций и контекстное меню для ли- нейной разметки, приведен в листинге 6.9.
Листинг 6.9. Полный код приложения package com.sample.contextmenu; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.Menu; import android.view.ContextMenu; import android.view.MenuItem; import android.widget.Toast; import android.view.Gravity; import android.widget.LinearLayout; import android.view.ContextMenu.ContextMenuInfo; public class MainActivity extends Activity {
public static final int IDM_RESTORE = 201; public static final int IDM_PAUSE = 202;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);

152
Часть II. Базовое программирование для Android final LinearLayout game = (LinearLayout)findViewById(R.id.Main); registerForContextMenu(game);
}
// Создание контекстного меню
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) { super.onCreateContextMenu(menu, v, info); menu.add(Menu.NONE, IDM_PAUSE, Menu.NONE, "Пауза"); menu.add(Menu.NONE, IDM_RESTORE, Menu.NONE, "Возобновить");
}
// Обработка пунктов контекстного меню
@Override public boolean onContextItemSelected(MenuItem item) {
CharSequence t; t = ""; switch(item.getItemId()) { case IDM_PAUSE: t = "Пауза"; break; case IDM_RESTORE: t = "Возобновить"; break; default: super.onContextItemSelected(item);
}
Toast toast = Toast.makeText(this, t, Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); return true;
}
}
Рис. 6.13. Контекстное меню

Глава 6. Уведомления, диалоговые окна и меню
153
Запустите приложение. Если вы запустили его в эмуляторе, для вызова контекст- ного меню нажмите левую кнопку мыши на основной рабочей области прило- жения, подождите 2 секунды и отпустите кнопку мыши. Результат приведен на рис. 6.13.
6.3.5. Подменю
Подменю можно добавить в любое другое меню, кроме самого подменю. Подменю полезно при создании очень сложных приложений, где пользователю доступно много функций.
Рассмотрим, как можно добавить подменю в меню опций. Для создания подменю используется метод addSubMenu()
. Далее мы создадим два подменю в меню опций
File и
Edit
— с соответствующими пунктами меню:
@Override public boolean onCreateOptionsMenu(Menu menu) {
SubMenu subFile = menu.addSubMenu("Файл"); subFile.add(Menu.NONE, IDM_NEW, Menu.NONE, "Создать..."); subFile.add(Menu.NONE, IDM_OPEN, Menu.NONE, "Открыть..."); subFile.add(Menu.NONE, IDM_SAVE, Menu.NONE, "Сохранить"); subFile.add(Menu.NONE, IDM_SAVEAS, Menu.NONE, "Сохранить как..."); subFile.add(Menu.NONE, IDM_EXIT, Menu.NONE, "Выход");
SubMenu subEdit = menu.addSubMenu("Правка"); subEdit.add(Menu.NONE, IDM_COPY, Menu.NONE, "Копировать"); subEdit.add(Menu.NONE, IDM_CUT, Menu.NONE, "Вырезать"); subEdit.add(Menu.NONE, IDM_PASTE, Menu.NONE, "Вставить"); return super.OnCreateOptionsMenu(menu);
}
Обработка команд подменю осуществляется аналогично обработке команд меню опций — разницы никакой нет.
Меню — очень важная часть приложения, и серьезное приложение вряд ли будет существовать без меню. Если у вас что-то не получилось, по следующему адресу вы найдете готовое приложение (которое мы создавали на протяжении разд. 6.3), демонстрирующее создание меню: http://www.dkws.org.ua/mybooks/OptionsMenu.zip
Скачанный архив нужно распаковать в каталог, содержащий рабочее пространство
Eclipse. В моем случае — это
C:\Users\Den\workspace
, у вас в 99 % случаев каталог будет таким же, за исключением собственно имени пользователя.

154
Часть II. Базовое программирование для Android
6.4. Диалоговое окно открытия файла
Android — одна из немногих операционных систем, в которой нет собственного диалогового окна открытия/сохранения файлов. Да, на фоне других операционных систем это кажется весьма странным и неудобным, как с точки зрения пользовате- ля, так и программиста. Программисту приходится каждый раз выдумывать, как создать такое диалоговое окно, а пользователю — каждый раз привыкать к нему.
Именно поэтому мне не хотелось создавать еще одну версию диалогового окна от- крытия файлов, и я принялся искать уже готовые решения. Так и мне будет проще, и пользователям. Пересмотрев несколько уже готовых решений, я выбрал лучшее: http://habrahabr.ru/post/203884/. Можно также использовать и решение Android
File Dialog (https://code.google.com/p/android-file-dialog/), но оно реализовано в виде отдельной деятельности. Если вас такой подход не смущает, то это тоже вполне приемлемый вариант.
Переписывать указанные решения (тем более, что они не мои) в книге я не стану.
По приведенным ссылкам все достаточно подробно расписано (а в первом случае еще и на русском языке). Поэтому, надеюсь, вы разберетесь самостоятельно, а в следующей главе мы поговорим о работе с двумерной графикой в Android-при- ложениях.




ГЛ А В А
7

Графика
В этой главе мы поговорим о создании статической графики путем рисования в объекте
View из разметки или же рисования непосредственно на канве. Анимация будет рассмотрена в следующей части книги — в главе 12.
7.1. Класс Drawable
Для рисования на формах и изображениях используется графическая библиотека android.graphics.drawable
. Класс
Drawable определяет различные виды графики — например:
BitmapDrawable
,
ShapeDrawable
,
LayerDrawable и др.
Существуют два способа определения и инициализации объектов
Drawable
. Первый заключается в использовании ресурсов из каталога res/drawable
, а второй — в созда- нии XML-файла со свойствами объекта
Drawable
В Android-приложения вы можете включать изображения следующих форматов:
PNG — рекомендуемый формат;
JPEG — поддерживаемый формат (тем не менее, лучше использовать PNG);
BMP — поддерживается, но использовать не рекомендуется из-за большого раз- мера файлов этого формата;
GIF — формат поддерживается, но его использование настоятельно не рекомен- дуется. Палитра формата GIF включает всего 256 цветов, чего явно мало для эк- рана современного смартфона. К тому же разработчики Android рекомендуют использовать формат PNG.
О
СОБЕННОСТИ ПРИМЕНЕНИЯ ФОРМАТОВ
Конечно, для каждого формата есть свое применение. Формат PNG отлично подходит для изображений кнопок и других элементов графического интерфейса. Формат JPEG вы будете использовать для работы с фотографиями — от него никуда не денешься.
Формат BMP — это изобретение Microsoft, вот пусть сами его и используют. Только у Microsoft есть столько дискового пространства, чтобы хранить изображения в фор- мате BMP. Формат GIF поддерживает анимацию — это единственное его преимуще- ство, но позже вы узнаете, что анимацию можно создать средствами Android. Поэтому вообще не вижу необходимости в этом формате.


156
Часть II. Базовое программирование для Android
Ресурсы изображений, находящиеся в каталоге res/drawable
, во время компиляции программы оптимизируются утилитой aapt
. Если вам нужно использовать растро- вые изображения без оптимизации, поместите их в каталог res/raw
— при компиля- ции файлы из этого каталога не будут подвержены оптимизации.
Рассмотрим подробнее процесс добавления ресурса в проект. Предположим, что нам нужно добавить в него два файла: p1.jpg и p2.jpg
. Подготовьте три варианта каждого файла: с высоким разрешением, со средним и с низким. Значение разре- шения зависит от выбранной платформы и от самого мобильного устройства
(см. главу 1).
Файлы с высоким разрешением нужно поместить в каталог res/drawable-hdpi
, файлы с низким разрешением — в каталог res/drawable-ldpi
, а со средним — в каталог res/drawable-mdpi
. После этого вернитесь в окно Eclipse, нажмите клавишу и в области Package Explorer вы увидите добавленные файлы (рис. 7.1).
Теперь перейдите на вкладку Images & Media палитры компонентов и добавьте элемент
ImageView
. При его добавлении с помощью графического редактора раз-
Рис. 7.1. Добавленные графические файлы
Рис. 7.2. Выбор ресурса

Глава 7. Графика
157 метки откроется окно, в котором нужно выбрать изображение для отображения в
ImageView
(рис. 7.2).
Выбранное изображение появится в редакторе разметки (рис. 7.3), а в файл activity_main.xml будет добавлен код, приведенный в листинге 7.1 (я только удалил отсюда код текстовой надписи, которая добавляется в проект по умолчанию).

Рис. 7.3. Выбранное изображение
Листинг 7.1. Пример описания элемента ImageView

1   2   3   4   5   6   7   8


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал