kopilkaurokov.ru - сайт для учителей

Создайте Ваш сайт учителя Курсы ПК и ППК Видеоуроки Олимпиады Вебинары для учителей

"Обучение программированию под Android". Урок 2-15.

Нажмите, чтобы узнать подробности

Эти уроки предназначены как для опытных программистов, так и для начинающих. Данные уроки позволят начать с нуля и быстро начать составлять готовые программы. Также в этой части уроков я покажу как устанановить среду и создать своё первое приложение. Также мы пройдём первые шаги по созданию независимого приложения и первые базовые основы для программирования под мобильную операционную систему Андроид. Желаю успехов!

Вы уже знаете о суперспособностях современного учителя?
Тратить минимум сил на подготовку и проведение уроков.
Быстро и объективно проверять знания учащихся.
Сделать изучение нового материала максимально понятным.
Избавить себя от подбора заданий и их проверки после уроков.
Наладить дисциплину на своих уроках.
Получить возможность работать творчески.

Просмотр содержимого документа
«"Обучение программированию под Android". Урок 2-15. »

Урок 2. Установка и настройка среды разработки Eclipse и SDK Tools

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

плагином Android Development Tools (ADT). В этом уроке мы подробно рассмотрим, как установить и настроить эту среду

разработки.

Я буду описывать установку применимо к операционной системе Windows 7.

Использую этот мануал по установке - http://developer.android.com/sdk/installing.html

Системные требования - http://developer.android.com/sdk/requirements.html

Перед прочтением рекомендую посмотреть:

SDK - http://ru.wikipedia.org/wiki/SDK

В этой статье много скринш отов и инструкций. Учитывайте, что версии ПО постоянно меняются и у вас все может выглядеть по-

другому и версии могут быть другими.

О том, как обновить компоненты, есть отдельная статья.

1. Java SDK - JDK

Т.к. разработка приложений ведется на Java, нам нужно скачать и установить соответствующее SDK, называемое еще JDK (если,

конечно, оно уже не установлено).

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

рекомендую скачать проверенную ш естую версию В разделе Java Platform, Standard Edition жмете JDK Download, ставите галку,

что принимаете лицензионное соглаш ение и скачиваете файл соответственно Ваш ей операционной системе. С установкой

проблем возникнуть не должно. После этого желательно перезагрузиться.

2. Android SDK

Android SDK включает в себя инструменты, необходимые для разработки Android-приложений. Содержимое можно посмотреть

здесь, а скачать здесь. Рекомендуется скачивать EXE-ш ник, но я предлагаю скачать ZIP-версию и самим распаковать в какой-нить

удобный для вас каталог.

Учтите, что это должен быть каталог "на векА". И лучш е его не перемещать никуда, иначе придется перенастраивать среду

разработки. Предлагаю где-нибудь создать каталог Android. Крайне желательно, чтобы путь к нему был коротким. Идеально -

:\android (у меня это будет f:\android). Для себя запомним этот каталог под псевдонимом . И в него

распакуем наш архив SDK, получим \android-sdk-windows.

3. Eclipse

Симпатичная и удобная среда разработки, где мы и будем творить и созидать ). Ее мы будем брать здесь. Гугл рекомендует нам

версию Eclipse Classic. Согласимся с ним и скачаем именно эту версию. Распаковываем архив в , получаем

\eclipse.

4.ADT

По умолчанию Eclipse не особо годится для разработки Android-приложений. ADT - плагин, который настраивает среду

разработки для использования Android SDK и добавляет возможность удобной разработки.

Запускаем Eclipse (\eclipse\eclipse.exe). При первом запуске он попросит указать ему рабочий каталог, где он будет

хранить информацию о проектах. Предлагаю опять же не ходить далеко и создать каталог \workspace и указать этот

каталог.

Итак Eclipse запущен. Скачаем ADT плагин.

В меню запускаем Help Install New Software...

Жмем кнопку Add в правом верхнем углу

Вводим "ADT Plugin" в поле Name

URL адрес: https://dl-ssl.google.com/android/eclipse/ - в поле Location

Жмем OK и ждем, пока появится Developer Tools (Если возникают проблемы, используйте http вместо https)

Ставим галку на Developer Tools и жмем Next

Видим компоненты, которые будут установлены, жмем снова Next

Читаем и принимаем лицензионное соглаш ение и жмем Finish

Начинается закачка компонентов. Если выскочит Security warning о том, что the authenticity or validity of the software can't be

established, жмите OK.

У меня процесс занял около минуты.

После заверш ения надо перезапустить Eclipse - Restart Now

После перезапуска Eclipse выдаст такой диалог:

Первый пункт нужен для тех, кто по каким то причинам не скачал и не распаковал SDK на втором ш аге данной инструкции. Eclipse

сможет сделать это сам. И дополнительно сразу же скачает последнюю Android-платформу. Также он предлагает скачать

платформу версии 2.1, как наиболее поддерживаемую кучей устройств.

Нам интересен второй пункт - он позволяет указать, куда мы распаковали SDK в ш аге 2. У нас это - \android-sdkwindows.

Жмем Next.

И в появивш емся окне выбираете, отправлять статистику в гугл или не отправлять. На работу это никак не повлияет.

Выбираете, жмете Finish.

Далее нам сообщают, что наш е скачанное SDK не содержит компонент и предлагают пройти в SDK Manager и срочно закачать.

Жмем OK.

5. Платформы Android

И проваливаемся в SDK Manager.

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

он уже или нет. Итак, что будем качать?

Обязательно нужно докачать неустановленное еще содержимое папки Tools. Также в папке Extras (в конце списка) найдите пункт

Android Support Library и отметьте его, если он есть.

Для платформ 4.Х выбираем SDK Platform (сама платформа) и ARM EABI v7a System Image (для работы эмулятора).

Для остальных, необходимых вам версий Android выбираете только SDK Platform. Учитывайте, что каждая платформа может

весить до 150 метров!!! На работе особо не покачаеш ь, админы потом придут за вами :) Для первых уроков потребуется только

платформа 2.3.3 (API 10). Можете скачать пока только ее.

Если же трафика не жалко, то добавляйте для каждой плафтормы пункты:

Samples for SDK - исходники примеров приложений

Google APIs by Google Inc. - нужно если собираетесь работать с гугл-приложениями (Map, Navigation и пр.)

Если трафика не жалко вообще - ставьте все галки. Но ждать придется долго. И займет все это дело не один гиг.

Когда все выбрали - жмем кнопку Install X packages справа снизу.

В новом окне подтверждаем, что согласны все это скачать - Accept All. Заодно здесь можно и размер посмотреть и отказаться от

чего-либо.

Жмете Install - побежал индикатор и открылся лог - началась закачка. При моем выборе компонентов, я ждал минут 20. После

этого в окош ках появилась фраза: Done loading packages.

Установка заверш ена. Закрываем лог и SDK Manager.

Для информации - у меня новые компоненты заняли 1,5 гига.

Далее перезапускаете Eclipse и все. После выполнения этих ш агов мы получили среду разработки, с помощью которой можно

кодить Android-приложения. Возможно эти действия покажутся мутными и скучными, но без них, к сожалению, никак. Дальш е

дело пойдет веселей. Если что-то не получается или выдает ош ибку - попробуйте погуглить, наверняка вы не первый

сталкиваетесь с такой проблемой и в сети уже есть описание реш ения. Ну или пиш ите в форум.

На следующем уроке мы в Eclipse настроим Android Virtual Device (AVD), создадим наше первое приложение и запустим его. AVD

– это эмулятор смартфона с операционной системой Android, на котором можно запускать и тестировать приложения. Не

подключать же свой смартфон каждый раз ) Также мы рассмотрим структуру проекта приложения.

P.S. Если у вас не появилось это окно

или вы его нечаянно закрыли - ничего страш ного. Путь к SDK из ш ага 2 можно указать вручную.

В Eclipse меню Windows Preferences

Слева выбираем Android, жмем Browse

Указываем каталог, куда распаковали SDK - \android-sdk-windows. Жмем Apply.

Нам говорят, что отсутствует компонент - закрываем это сообщение и жмем OK

У меня еще выскочило такое окош ко:

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

это всегда можно поменять в настройках. Я галку оставил, мне не жалко )

После этого можно идти в SDK Manager (в Eclipse меню Window Android SDK Manager) и скачивать платформы.

Урок 3. Создание AVD. Первое приложение. Структура Android-проекта.

Для того, чтобы тестировать приложения, нам понадобится Android Virtual Device (AVD). Это эмулятор Android-смартфона,

на который Eclipse сможет устанавливать, созданные нами приложения, и запускать их там. Давайте его создадим.

Запускаем Eclipse

Идем в меню Windows Android SDK and AVD Manager (в более свежих версиях - Android AVD Manager)

Слева выбираем Virtual Devices

Жмем кнопку New

В списке Target представлены платформы Android различных версий. Мы их закачали на прош лом уроке последним

ш агом. Разницу между ними можно посмотреть здесь. Слева выбираете нужную версию и смотрите информацию по ней.

Вернемся в Eclipse. Давайте выберем из списка платформу 2.3.3 (API Level 10). Соответственно имя зададим - AVD_233.

Также укажем размер SDCard = 100 и режим экрана HVGA.

Жмем Create AVD, и закрываем AVD Manager.

Теперь наконец-то мы можем создать наш е первое приложение и посмотреть как оно работает.

UPD от 10.07.2012 - этот урок был написан давно. На днях гугл существенно обновил визард нового проекта.

Здесь вы можете посмотреть подробно, какие возможности дает новый визард. Я же покажу, как создать простой

проект.

Итак, сначала будут скрины для нового варианта визарда. Если же вы давно не обновлялись, то пролистайте чуть дальш е -

там будут скрины для старого визарда.

Новый вариант.

В Eclipse идем в меню File New Project

Выбираем тип проекта - Android Android Application Project, жмем Next

Появилось окно создания проекта.

Давайте заполнять.

Начнем с Project Name – это имя проекта, которое будет видно в общем списке проектов слева. Т.к. проектов у нас будет

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

структурированы.

Префикс может быть таким: P . На номер урока выделим три цифры, на

номер проекта – одну. Добавим к префиксу некое смысловое название (OurFirstProject) и получим имя наш его первого

проекта в третьем уроке - P0031_OurFirstProject.

Application name – непосредственно имя программы, которое будет отображаться в списке приложений в смартфоне.

Можно брать имя проекта без префикса

Package name – это понятие из Java, подробно можно посмотреть здесь. Вкратце – это префикс для имени классов наш его

приложения. Я буду использовать ru.startandroid.develop.

Build SDK определяет, возможности какой версии Android будет использовать приложение. Выберем ту же, что и при

создании AVD – т.е. 2.3.3.

Minimum Required SDK определяет минимальную версию Android, на которой запустится приложение. Можно сделать ее

равной Build SDK - 2.3.3.

Из галок оставляете только Create Project in Workspace. Проект будет создан и сохранен в дефолтном Workspace.

Жмем Next.

Открывается экран создания Activity.

Здесь выбираем BlankActivity и жмем Next.

Здесь убедимся, что в поле Activity Name указано MainActivity, а в поле Layout Name укажем main. Остальные поля не

трогаем.

Жмем Finish.

Проект создан.

Старый вариант.

В Eclipse идем в меню File New Project

Выбираем тип проекта - Android Android Project, жмем Next

Появилось окно создания проекта. (В последующих версиях это окно разделено на три разных окна)

Давайте заполнять.

Project Name – имя проекта, которое будет видно в общем списке проектов слева. Т.к. проектов у нас будет много,

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

структурированы.

Префикс может быть таким: P . На номер урока выделим три цифры, на

номер проекта – одну. Добавим к префиксу некое смысловое название (OurFirstProject) и получим имя наш его первого

проекта в третьем уроке - P0031_OurFirstProject.

Build Target определяет возможности какой версии Android будет использовать приложение. Выберем ту же, что и при

создании AVD – т.е. 2.3.3.

Application name – непосредственно имя программы, которое будет отображаться в списке приложений в смартфоне.

Можно брать имя проекта без префикса

Package name – это понятие из Java, подробно можно посмотреть здесь. Вкратце – это префикс для имени классов наш его

приложения. Я буду использовать ru.startandroid.develop.

Create Activity – имя класса для Activity (окна программы). Укажем, например - MainActivity.

Все остальное оставляем как есть. Жмем Finish.

Проект создан.

Дальнейш ие скрины для разных версий могут отличаться, но незначительно.

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

src – все, написанные нами исходные коды, будут в этой папке

gen – генерируемые средой файлы, необходимые для приложения. Здесь лучш е ничего не трогать . (Если этой папки нет -

что-нибудь измените в проекте и нажмите кнопку сохранить).

Android 2.3.3 – необходимые для приложения Android-библиотеки

assets и res – папки для файлов-ресурсов различного типа

AndroidManifest.xml – манифест или конфиг-файл приложения

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

Давайте выделим имя проекта слева:

и запустим его - нажмем CTRL+F11, далее выбираем Android Application,

жмем OK. Запустится эмулятор, советую в это время ничего особо не трогать и не нажимать, т.к. это глючная и капризная

ш тука. Время запуска - около минуты. Дожидаемся, пока в консоли Eclipse появятся подобные строки.

Приложение закачано на эмулятор, установлено и запущено. Снимаем блокировку экрана в эмуляторе (если она есть) и

наблюдаем наш е приложение:

Видно название приложения и название Activity. Мы создали и запустили первое приложение.

Если не получилось запустить и Eclipse вывел в консоль подобное сообщение: "emulator-5554 disconnected! Cancelling

'ru.startandroid.develop.OurFirstProject.MainAct activity launch'!" - то закройте эмулятор, и попробуйте снова. Если снова не

получилось. перезапустите Eclipse. Если опять нет - ребутнитесь. Если и сейчас не работает, удалите AVD и создайте

новый. В итоге должно заработать, пусть и не с первой попытки.

Главное - после запуска приложения (CTRL+F11) старайтесь соверш ать как можно меньше движений на компе. Я

заметил четкую тенденцию - если во время запуска переключаться между различными окнами, то эмулятор запускается

криво. А если просто посидеть и подождать минутку - то все ок. Ну и надо чтоб при этом не было включено какое-нить

кодирование видео или прочие, нагружающие систему процедуры.

Подробнее про эмулятор можно почитать здесь.

P.S.

Если у вас имя пользователя русскими буквами, то будут небольш ие проблемы. Как их реш ить, можно прочесть на

форуме в ветке этого урока.

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

Урок 4. Элементы экрана и их свойства

Давайте посмотрим, как в Андроид приложениях формируется то, что мы видим на экране.

Если проводить аналогию с Windows, то приложение состоит из окон, называемых Activity. В конкретный момент

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

качестве примера можно рассмотреть почтовое приложение. В нем одно Activity – список писем, другое – просмотр

письма, третье – настройки ящика. При работе вы перемещаетесь по ним.

Содержимое Activity формируется из различных компонентов, называемых View. Самые распространенные View -

это кнопка, поле ввода, чекбокс и т.д.

Примерно это можно изобразить так:

Необходимо заметить, что View обычно размещаются в ViewGroup. Самый распространенный пример ViewGroup –

это Layout. Layout бывает различных типов и отвечает за то, как будут расположены его дочерние View на экране

(таблицей, строкой, столбцом …)

Подробней об этом можно почитать в хелпе: User Interface и Common Layout Objects.

Наверно уже запутал новыми словами и терминами, давайте посмотрим это все на практике. Создадим проект со

следующими свойствами:

Project name: P0041_BasicViews

Build Target: Android 2.3.3

Application name: BasicViews

Package name: ru.startandroid.develop.BasicViews

Create Activity: MainActivity

Если у вас свежая версия визарда создания проекта, то Build Target - это то же самое, что и Build SDK. А в экране

создания Activity не забывайте указывать main в поле Layout Name.

В наш ем проекте нам интересен файл: res layout main.xml

Это layout-файл, в нем мы определяем набор и расположение элементов View, которые хотим видеть на экране. При

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

посмотрим, какой набор View он содержит по умолчанию.

Слева видим список View, разделенный на группы. Здесь отображены все View-элементы, которые вы можете

использовать в своих приложениях.

Возможно, у вас он будет немного другого вида. Это регулируется в меню Palette, чуть выш е.

Обратим внимание на белый экран. Мы видим, что на экране сейчас присутствует элемент с текстом Hello

world! Чтобы узнать, что это за View нажмите на этот текст. Справа во вкладке Outline вы видите все элементы,

которые описаны в main.xml.

Видим, что выделенный нами элемент – это TextView. Обратите внимание, что он вложен в элемент RelativeLayout

– это ViewGroup, про которые я писал выш е.

Добавим еще элементов на экран, пусть это будут Button и CheckBox. Для этого просто перетащите их из списка

слева на белый экран ваш его будущего приложения. Также можно перетащить их на RelativeLayout во вкладке

Outline, результат будет почти тот же. Кроме Button и CheckBox, добавим еще на экран Plain Text из группы Text

Fields.

В Outline они появятся под названиями button1, checkBox1 и editText1. Это ID, которые им были присвоены

автоматически. Пока оставим их такими, позднее научимся их менять и будем делать более осмысленными.

Теперь на наш ем экране несколько элементов. Давайте изменим надписи на них. Во вкладке Outline жмем на

TextView. Теперь нам нужна вкладка Properties. Она отображает свойства выделенного в Outline или на экране View-

элемента. Располагается она обычно сразу под Outline.

Найдем в Properties свойство Text. Сейчас там стоит ссылка на текстовую константу. Где создаются эти константы мы

рассмотрим в следующих уроках, а пока просто давайте напиш ем сюда свой текст: «Какой-то текст»

Аналогично изменим свойство Text для элементов button1, checkBox1 и editText1 на произвольные тексты. Все эти

изменения пиш утся в main.xml. Сохраним все CTRL+SHIFT+S и запустим CTRL+F11.

Приложение отображает нам MainActivity, а оно в свою очередь читает файл main.xml и отображает все View,

которые мы создавали и настраивали.

На этом уроке мы:

узнали, что выводится на экран в Android-приложении

научились формировать layout-файл – добавлять View и настраивать их свойства

На следующем уроке мы:

рассмотрим layout-файл с другого ракурса - XML

разберем, откуда Activity знает, какой layout-файл надо читать и попробуем настроить на чтение другого файла

узнаем, какой layout-файл используется при смене ориентации экрана (горизонтальная/вертикальная)

Урок 5. Layout-файл в Activity. XML представление. Смена ориентации экрана.

Какой layout-файл используется в Activity

На прош лом уроке мы выяснили, что Activity читает layout-файл и отображает то, что в нем сконфигурировано. Теперь выясним, откуда

Activity знает, какой именно layout-файл читать. А еще в этом уроке находится подсказка, как зарегиться на наш ем форуме ;)

Создадим новый проект:

Project name: P0051_LayoutFiles

Build Target: Android 2.3.3

Application name: LayoutFiles

Package name: ru.startandroid.develop.LayoutFiles

Create Activity: MainActivity

При разработке каждому Activity сопоставляется одноименный java-класс (наследник класса android.app.Activity). При запуске приложения,

когда система должна показать Activity и в дальнейш ем работать с ним, она будет вызывать методы этого класса. И от того, что мы в этих

методах накодим, зависит поведение Activity.

При создании проекта мы указывали, что надо создать Activity с именем MainActivity

При использовании старого визарда это выглядело так:

В новом визарде - чуть по другому. На одном экране галка, на другом - имя:

Мы попросили создать Activity и Eclipse создал нам соответствующий класс (в дальнейш ем мы научимся их создавать самостоятельно).

Давайте посмотрим этот класс: откроем двойным кликом файл src/ru.startandroid.develop.LayoutFiles/MainActivity.java

В наш ем классе мы видим, что реализован метод onCreate – он вызывается, когда приложение создает и отображает Activity (на

onCreateOptionsMenu пока не обращаем внимания). Посмотрим код реализации.

Первая строка:

super.onCreate(savedInstanceState); – конструктор родительского класса, выполняющий необходимые процедуры, его мы не трогаем.

Нас интересует этот код:

setContentView(R.layout.main);

Метод setContentView(int) – устанавливает содержимое Activity из layout-файла. Но в качестве аргумента мы указываем не путь к наш ему

layout-файлу (res/layout/main.xml), а константу, которая является ID файла. Это константа генерируется автоматически здесь

gen/ru.startandroid.develop.LayoutFiles/R.java.

Этот файл можно открыть и посмотреть, но менять его не стоит. В R классе будут храниться сгенерированные ID для всех ресурсов проекта

(из папки res/*), чтобы мы могли к ним обращаться. Имена этих ID-констант совпадают с именами файлов ресурсов (без расш ирений).

Откроем res/layout/main.xml, посмотрим, что там

Запустим приложение и посмотрим что оно нам покажет

Все верно - Activity отобразил то, что прописано в main.xml.

Попробуем отобразить содержимое другого файла. Создадим еще один layout-файл, например myscreen.xml. Для этого выделим папку

res/layout в наш ем проекте и нажмем кнопку создания нового файла

Откроется визард

В поле File вводим имя файла: myscreen.xml и жмем Finish.

Новый layout-файл должен сразу открыться. Добавим TextView и через Properties изменим его текст на: «Этот экран описан не в main.xml, а

в myscreen.xml».

При этом Eclipse будет подчеркивать этот текст желтым цветом и ругаться примерно так: [I18N] Hardcoded string "...", should use @string

resource. Это он возмущен хардкодом, который мы тут устроили. Он хочет, чтобы использовали файлы ресурсов для всех надписей. Но пока

что мы это не умеем, так что игнорируем эти предупреждения.

Обязательно сохраняем. Чтобы в R.java появилась новая константа для этого файла - R.layout.myscreen.

Теперь настроим так, чтобы Activity использовало новый файл myscreen.xml, а не main.xml. Откроем MainActivity.java и поменяем аргумент

метода setContentView. Замените «R.layout.main», на «R.layout.myscreen» (ID нового layout-файла). Должно получиться так:

Сохраняем, запускаем приложение. Видим, что теперь оно отображает содержимое из myscreen.xml, т.к. мы явно ему это указали в методе

setContentView, который выполняется при создании (onCreate) Activity

Layout-файл в виде XML

Открыв файл main.xml, вы видите его визуальное представление. Т.е. некий предпросмотр, как это будет выглядеть на экране. Снизу вы

можете видеть две вкладки – Graphical Layout и main.xml. Откройте main.xml

Мы видим достаточно читабельное xml-описание всех View наш его layout-файла. Названия xml-элементов - это классы View-элементов,

xml-атрибуты - это параметры View-элементов, т.е. все те параметры, что мы меняем через вкладку Properties. Также вы можете вносить

изменения прямо сюда и изменения будут отображаться в Graphical Layout. Например изменим текст у TextView. Вместо ссылки на

константу, вставим свой текст «Какой-то текст»

Сохраняем. Открываем Graphical Layout и наблюдаем изменения.

Обычно авторы учебников дают содержание layout-файлов именно в xml виде. Это удобно – вы можете просто скопировать фрагмент и

использовать, и не надо вручную добавлять View-элементы, бегать по Properties и настраивать все руками. Я буду делать в своих проектах

также.

Layout-файл при смене ориентации экрана

По умолчанию мы настраиваем layout-файл под вертикальную ориентацию экрана. Но что будет если мы повернем смартфон и

включится горизонтальная ориентация? Давайте смотреть.

Изменим myscreen.xml. Добавим вертикальный ряд кнопок и изменим надпись.

xml-код (вы можете скопировать его и вставить в ваш файл):

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Вертикальная ориентация экрана"

android:layout_height="wrap_content"

android:layout_width="match_parent"

android:id="@+id/linearLayout1"

android:orientation="vertical"

android:text="Button1"

android:id="@+id/button1"

android:layout_height="100dp"

android:layout_width="100dp"

android:text="Button2"

android:id="@+id/button2"

android:layout_height="100dp"

android:layout_width="100dp"

android:text="Button3"

android:id="@+id/button3"

android:layout_height="100dp"

android:layout_width="100dp"

android:text="Button4"

android:id="@+id/button4"

android:layout_height="100dp"

android:layout_width="100dp"

Обратите внимание - я добавил вертикальный LinearLayout и поместил в него 4 кнопки. Подробнее обсудим это на следующем уроке.

Запустим приложение. В вертикальной ориентации все ок.

Нажмем в эмуляторе CTRL+F12, ориентация сменилась на горизонтальную и наш и кнопки уже не влезают в экран (у меня, кстати, эмулятор

глючит и смена ориентации срабатывает не всегда)

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

горизонтально.

Но как дать знать Activity, что она в вертикальной ориентации должна использовать один layout-файл, а в горизонтальной – другой? Об этом

за нас уже подумали создатели Андроид. Необходимо создать папку res/layout-land, а в ней создать layout файл с тем же именем, что и

основной. Этот файл будет использован в горизонтальной ориентации.

Создаем папку: правой кнопкой на res, New Folder, Folder name = layout-land, жмем Finish.

Далее создадим файл res/layout-land/myscreen.xml и настроим его под горизонтальную ориентацию. Аналогично, как и в первый раз, жмем

кнопку создания файла. Откроется визард.

Вводим имя файла: myscreen.xml

Визард может ругнуться, что есть уже такой файл - The destination file already exists. Это он углядел ранее созданный файл

res/layout/myscreen.xml. Нам надо ему сообщить, что новый файл предназначен для папки res/layout-land, а не res/layout. Жмем Next

А здесь уже руками внизу допиш ите приставку -land, чтобы получилось res/layout-land

Как вариант, можно было руками не дописывать, а добавить из левого столбца в правый атрибут Orientation и указать ему значение

Landscape. Визард все понял бы и сам дописал к пути приставку -land.

А мы сами дописали путь и визард сам добавил атрибут направо.

Жмем Finish и получаем готовый файл.

Поместите этот xml-код в файл и сохраните файл, чтобы получить такую же картинку, как выш е:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Горизонтальная ориентация экрана"

android:layout_height="wrap_content"

android:layout_width="match_parent"

android:id="@+id/linearLayout1"

android:orientation="horizontal"

android:text="Button1"

android:id="@+id/button1"

android:layout_height="100dp"

android:layout_width="100dp"

android:text="Button2"

android:id="@+id/button2"

android:layout_height="100dp"

android:layout_width="100dp"

android:text="Button3"

android:id="@+id/button3"

android:layout_height="100dp"

android:layout_width="100dp"

android:text="Button4"

android:id="@+id/button4"

android:layout_height="100dp"

android:layout_width="100dp"

Запустим приложение. Activity читает layout-файл, который мы указывали в методе setContentView, т.е. myscreen.xml и отображает его

содержимое. Переключим ориентацию CTRL+F12. Activity понимает, что находится в горизонтальной ориентации, ищет в папке layout-land

файл myscreen.xml и использует уже его.

В этом уроке мы:

разобрали, откуда Activity знает, какой layout-файл надо читать и настроили его на чтение другого файла

рассмотрели layout-файл с другого ракурса – XML

узнали, какой layout-файл используется при смене ориентации экрана (горизонтальная/вертикальная)

В следующем уроке:

изучим основные виды layout: LinearLayout, TableLayout, RelativeLayout, AbsoluteLayout

Урок 6. Виды Layouts. Ключевые отличия и свойства.

Расположение View-элементов на экране зависит от ViewGroup (Layout), в которой они находятся. В этом уроке мы

рассмотрим основные виды Layout.

LinearLayout – отображает View-элементы в виде одной строки (если он Horizontal) или одного столбца (если он

Vertical). Я использовал это на прош лом уроке, когда демонстрировал использование layout-файлов при смене

ориентации.

TableLayout – отображает элементы в виде таблицы, по строкам и столбцам.

RelativeLayout – для каждого элемента настраивается его положение относительно других элементов.

AbsoluteLayout – для каждого элемента указывается явная позиция на экране в системе координат (x,y)

Рассмотрим эти виды

LinearLayout (LL)

Этот вид ViewGroup по умолчанию предлагается при создании новых layout-файлов. Он действительно удобен и

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

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

Сделаем простой и наглядный пример.

Создайте проект:

Project name: P0061_Layouts

Build Target: Android 2.3.3

Application name: Layouts

Package name: ru.startandroid.develop.layouts

Create Activity: MainActivity

Откроем layout-файл main.xml, и поместите в него следующий код:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

Теперь корневой элемент у нас LinearLayout с вертикальной ориентацией.

Перетащите слева в корневой LinearLayout три кнопки. Они выстроились вертикально.

Теперь в Properties меняем для LL свойство Orientation на horizontal и сохраняем (CTRL+SHIFT+S) – кнопки

выстроились горизонтально.

GroupView можно вкладывать друг в друга. Вложим в один LL два других. Удалите в main.xml все элементы (три

кнопки) кроме корневого LL. Ориентацию корневого LL укажем вертикальную и добавим в него два новых

горизонтальных LL. В списке элементов слева они находятся в разделе Layouts. Напоминаю, что вы можете

перетаскивать элементы из списка не только на экран, но и на конкретный элемент на вкладке Outline.

В каждый горизонтальный LL добавим по три кнопки. Получилось два горизонтальных ряда кнопок.

TableLayout (TL)

TL состоит из строк TableRow (TR). Каждая TR в свою очередь содержит View-элементы, формирующие столбцы. Т.е.

кол-во View в TR - это кол-во столбцов. Но кол-во столбцов в таблице должно быть равным для всех строк. Поэтому,

если в разных TR разное кол-во View-элементов (столбцов), то общее кол-во определяется по TR с максимальным

кол-вом. Рассмотрим на примере.

Создадим layout-файл tlayout.xml. с корневым элементом TableLayout

Добавим в корневой TableLayout три TableRow-строки (из раздела Layouts слева) и в каждую строку добавим по две

кнопки. Результат: наш а таблица имеет три строки и два столбца.

Добавим в первую строку еще пару кнопок. Кол-во столбцов для всех строк теперь равно 4, т.к. оно определяется по

строке с максимальным кол-вом элементов, т.е. по первой строке. Для второй и третьей строки третий и четвертый

столбцы просто ничем не заполнены.

Во вторую строку добавим TextView и Button, и текст в добавленном TextView сделаем пустым. В третьей строке

сделаем тоже самое. Мы видим, что эти элементы легли в третий и четвертый столбец. И т.к. TextView у нас без

текста и на экране не виден, кажется что третий столбец во второй и третьей строке пустой.

Ширина столбца определяется по самому ш ирокому элементу из этого столбца. Введем текст в один из TextView и

видим, что он расш ирил столбец.

Я уберу элементы четвертого столбца и построю такой экран. Попробуйте сами сделать так же в качестве

упражнения.

TL может содержать не только TR, но и обычные View. Добавьте, например, Button прямо в TL, а не в TR и увидите,

что она растянулась на ш ирину всей таблицы.

RelativeLayout (RL)

В этом виде Layout каждый View-элемент может быть расположен определенным образом относительно указанного

View-элемента.

Виды отнош ений:

1) слева, справа, сверху, снизу указанного элемента (layout_toLeftOf, layout_toRightOf, layout_above, layout_below)

2) выравненным по левому, правому, верхнему, нижнему краю указанного элемента (layout_alignLeft,

layout_alignRight, layout_alignTop, layout_alignBottom)

3) выравненным по левому, правому, верхнему, нижнему краю родителя (layout_alignParentLeft,

layout_alignParentRight, layout_alignParentTop, layout_alignParentBottom)

4) выравненным по центру вертикально, по центру горизонтально, по центру вертикально и горизонтально

относительно родителя (layout_centerVertical, layout_centerHorizontal, layout_centerInParent)

Подробно можно почитать в хелпе.

Создадим rlayout.xml и скопируем туда такой xml-код:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:id="@+id/label"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="Type here:"

android:id="@+id/entry"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_below="@+id/label"

android:background="@android:drawable/editbox_background"

android:id="@+id/ok"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignParentRight="true"

android:layout_below="@+id/entry"

android:layout_marginLeft="10dip"

android:text="OK"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignTop="@+id/ok"

android:layout_toLeftOf="@+id/ok"

android:text="Cancel"

Здесь у нас корневой элемент - RelativeLayout.

Получился такой экран:

Нам интересен xml-код. Сразу кратко опиш у незнакомые атрибуты и их значения:

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:id="@+id/entry"

- слово android в названии каждого аттрибута – это namespace, я его буду опускать при объяснениях.

- id – это ID элемента,

- layout_width (ш ирина элемента) и layout_height (высота элемента) могут задаваться в асболютных значениях, а

могут быть следующими: fill_parent (максимально возможная ш ирина или высота в пределах родителя) и

wrap_content (ш ирина или высота определяется по содержимому элемента). В хелпе указывается, что есть еще

match_parent. Это тоже самое, что и fill_parent. По каким-то причинам, разработчики системы реш или, что название

match_parent удобнее, и от fill_parent постепенно будут отказываться. А пока его оставили для совместимости. Так что

запомните, что match_parent = fill_parent и в дальнейш ем будем стараться использовать match_parent. Позже мы

еще остановимся на этом и разберем подробнее.

Сейчас вернемся к наш им элементам. В примере мы видим TextView, EditText и два Button – OK и Cancel. Давайте

подробно разберем интересующие нас атрибуты.

TextView

android:id="@+id/label" - ID

android:layout_width="match_parent" - занимает всю доступную ему ш ирину (хоть это и не видно на экране);

android:layout_height="wrap_content" - высота по содержимому;

ни к чему никак не относится

EditText

android:id="@+id/entry" - ID

android:layout_width="match_parent" - вся доступная ему ш ирина

android:layout_height="wrap_content" - высота по содержимому

android:layout_below="@id/label" - расположен ниже TextView (ссылка по ID)

Button_OK

android:id="@+id/ok" – ID

android:layout_width="wrap_content" - ш ирина по содержимому

android:layout_height="wrap_content" – высота по содержимому

android:layout_below="@id/entry" - расположен ниже EditText

android:layout_alignParentRight="true" - выравнен по правому краю родителя

android:layout_marginLeft="10dip" – имеет отступ слева (чтобы Button_Cancel был не впритык)

Button_Cancel

android:layout_width="wrap_content" - ш ирина по содержимому

android:layout_height="wrap_content" – высота по содержимому

android:layout_toLeftOf="@id/ok" - расположен слева от Button_OK

android:layout_alignTop="@id/ok" - выравнен по верхнему краю Button_OK

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

Обратите внимание, что у View-элемента может не быть ID (android:id). Например, для TextView он обычно не нужен,

т.к. они чаще всего статичны и мы к ним почти не обращаемся при работе приложения. Другое дело EditText – мы

работаем с содержимым текстового поля, и Button – нам надо обрабатывать нажатия и соответственно знать, какая

именно кнопка нажата. В будущем мы увидим еще одну необходимость задания ID для View-элемента.

AbsoluteLayout (AL)

Обеспечивает абсолютное позиционирование элементов на экране. Вы указываете координаты для левого верхнего

угла компонента.

Создадим alayout.xml с корневым AbsoluteLayout

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

LinearLayout или TableLayout, а ложатся там, куда вы их перетащили. Т.е. это абсолютное позиционирование.

Открываем xml-код и видим, что для задания координат используются layout_x и layout_y.

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:id="@+id/button1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_x="42dp"

android:layout_y="62dp"

android:text="Button"

android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_x="142dp"

android:layout_y="131dp"

android:text="TextView"

android:id="@+id/checkBox1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_x="55dp"

android:layout_y="212dp"

android:text="CheckBox"

android:id="@+id/radioButton1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_x="171dp"

android:layout_y="318dp"

android:text="RadioButton"

Поначалу кажется, что это наиболее удобный и интуитивно понятный способ расположения элементов на экране -

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

разреш ением. Если открыть такое приложение на другом экране, все элементы сместятся и получится не так, как вы

планировали. Поэтому этот Layout не рекомендуется использовать. И его совместимость с будущими версиями

Android не гарантируется.

Есть еще много видов ViewGroup, и мы постепенно будем их осваивать. А пока нам хватит этих.

В этом уроке мы:

Рассмотрели основные виды Layout: LinearLayout, TableLayout, RelativeLayout, AbsoluteLayout

На следующем уроке:

рассмотрим подробно некоторые Layout-свойства View-элементов, которые позволяют настраивать их

расположение в ViewGroup.

Урок 7. Layout параметры для View-элементов.

На этом уроке мы:

- разбираемся в характеристиках экрана

- рассматриваем layout параметры (высота, ш ирина, отступ, гравитация, вес)

Экраны

Для начала немного теории по экранам. Экран имеет такие физические характеристики как диагональ и разреш ение.

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

кол-во точек по горизонтали и вертикали, которое экран способен отобразить, измеряется в пикселах.

Возьмем в качестве примера экран смартфона HTC Desire. Диагональ = 3,7 дюйма, разреш ение = 800х480 пикселов.

Кол-во пикселов в одном дюйме называется dpi (dot per inch). Узнаем чему равно dpi в данном случае, вспомнив

классику: c2 = a2 + b2, где с – кол-во пикселей по диагонали, т.е. вмещаемое в 3,7 дюйма. a и b – стороны экрана.

c = 3,7 * dpi

(3,7 * dpi)2 = 4802 + 8002

dpi2 = 870400 / 13,69 = 63579

dpi = 252. Т.е. в одном дюйме экрана помещается ряд из 252 пикселов.

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

Layout width и Layout height

Про ш ирину (layout_width) и высоту (layout_height) мы уже немного говорили на прош лом уроке. Мы можем

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

АБСОЛЮТНЫЕ ЗНАЧЕНИЯ:

Используются следующие единицы измерения (ЕИ):

dp или dip - Density-independent Pixels. Абстрактная ЕИ, позволяющая приложениям выглядеть одинаково на

различных экранах и разреш ениях.

sp - Scale-independent Pixels. То же, что и dp, только используется для размеров ш рифта в View элементах

pt - 1/72 дюйма, определяется по физическому размеру экрана. Эта ЕИ из типографии.

px – пиксел, не рекомендуется использовать т.к. на разных экранах приложение будет выглядеть по-разному.

mm – миллиметр, определяется по физическому размеру экрана

in – дюйм, определяется по физическому размеру экрана

Подробней о различиях и соотнош ениях между этими ЕИ вы можете прочесть в этом материале сайта.

КОНСТАНТЫ

match_parent (fill_parent) – означает, что элемент займет всю доступную ему в родительском элементе ш ирину/

высоту.

wrap_content – ш ирна/высота элемента будет определяться его содержимым

Создадим проект:

Project name: P0072_LayoutProp

Build Target: Android 2.3.3

Application name: LayoutProp

Package name: ru.startandroid.develop.layoutprop

Create Activity: MainActivity

Открываем main.xml. Настроим корневой LinearLayout на горизонтальную ориентацию, удалим TextView, и

добавим Button с ш ириной и высотой равной wrap_content. Она отображается на экране и ее ш ирина соответствует

тексту на ней.

Изменим текст с «Button» на «Button with text», сохраним и посмотрим на экран.

Кнопка стала ш ире, т.к. ш ирина определяется по содержимому. Если же мы сейчас явно укажем ей ш ирину 250 dp,

то кнопка растянется независимо от содержимого.

Теперь сделаем ш ирину равной match_parent. Кнопка растянулась на всю ширину родителя, т.е. LinearLayout. А

LinearLayout в свою очередь занимет всю ш ирину экрана.

Если у нас родитель содержит несколько элементов и мы хотим, чтобы они заняли все пространство необходимо

использовать параметр Layout weight – вес. Свободное пространство распределяется между элементами

пропорционально их weight-значениям.

Изменим текст наш ей кнопки на B1 и добавим ей соседа по LinearLayout – вторую кнопку с текстом B2. Ширину для

обоих поставьте wrap_content

Займемся дележом. Если мы хотим, чтобы кнопки поделили пространство родителя поровну – то для обеих укажем

weight = 1. В этом случае кнопки равны по ш ирине.

Обратите внимание, что не используются единицы измерения, указываются просто числа.

Если нужно, чтобы B1 занимала четверть, а B2 три четверти свободного пространства, то проставляем weight = 1 для

B1 и weight = 3 для B2.

Кол-во элементов может быть любым. Добавим еще кнопку с текстом B3, weight = 2 и width = wrap_content.

xml-код получивш егося экрана:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="horizontal"

android:id="@+id/button1"

android:layout_height="wrap_content"

android:layout_width="wrap_content"

android:text="B1"

android:layout_weight="1"

android:id="@+id/button2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="B2"

android:layout_weight="3"

android:layout_height="wrap_content"

android:layout_width="wrap_content"

android:id="@+id/button3"

android:text="B3"

android:layout_weight="2"

Теперь для B2 и B3 укажите weight = 0. Они больш е не претендуют на свободное пространство и занимают ш ирину

по содержимому, а B1 забирает все себе.

Разумеется, все выш е сказанное применимо и для параметра высоты - height.

При использовании weigth вы можете указать значение height или width = 0dp. В этом случае не будет учитываться

содержимое элементов и результат будет более соответствующий коэффициентам веса.

Layout gravity

Параметр layout_gravity аналогичен выравниванию из Word или Excel. Удобнее всего продемонстрировать его с

использованием FrameLayout. Я не описывал этот Layout на прош лом уроке, т.к. он совсем простой. Все

помещаемые в него элементы он по умолчанию помещает в левый верхний угол и никак их не выстраивает. Нам это

очень подходит для демонстрации настроек выравнивания.

Создадим grlayout.xml:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:id="@+id/frameLayout1"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:id="@+id/button1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="top|left"

android:text="gravity = top left"

android:id="@+id/button2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="top|right"

android:text="gravity = top right"

android:id="@+id/button3"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="bottom|left"

android:text="gravity = bottom left"

android:id="@+id/button4"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="bottom|right"

android:text="gravity = bottom right"

android:id="@+id/button5"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:text="gravity = center"

На экране видим:

Для наглядности текст кнопки отображает ее свойства. Все очевидно и несложно.

Я честно пытался понять зачем нужны значения gravity fill_* и clip_*, но так и не понял. То, что написано про них в

хелпе у меня не работает. Если у вас есть сведения по этому поводу – пиш ите в каменты.

Layout margin

Параметры margin полностью аналогичны margin из html. Это отступ. Он может быть со всех сторон сразу, либо

только с необходимых сторон. Продемонстрируем это на примере TableLayout. Создадим marginlayout.xml и

нарисуем таблицу три на три с кнопками.

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_height="wrap_content"

android:layout_width="match_parent"

android:id="@+id/tableLayout1"

android:id="@+id/tableRow1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Button"

android:id="@+id/button1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Button"

android:id="@+id/button2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Button"

android:id="@+id/button3"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/tableRow2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Button"

android:id="@+id/button4"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Margin"

android:id="@+id/button5"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Button"

android:id="@+id/button6"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/tableRow3"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Button"

android:id="@+id/button7"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Button"

android:id="@+id/button8"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Button"

android:id="@+id/button9"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

И на кнопке в центре будем экспериментировать.

margin = 50 dp

Вокруг кнопки со всех сторон образовался отступ = 50 dp.

margin left = 10 dp

margin top = 20 dp

Отступ слева и сверху.

margin right = 30 dp

margin bottom = 40 dp

Отступ справа и снизу.

Урок получился больш ой, но полезный. Думаю, это был последний урок дизайна, моделирования и верстки и

дальш е мы уже начнем кодить.

Стили

Если кто использовал HTML, то наверняка слыш али про каскадные стили - CSS. Стили позволяют вам группировать

атрибуты элементов (кнопок, таблиц, параграфов и т.д.). Далее вы просто применяете к элементам стили, и элемент

рисуется с учетом всех атрибутов стиля. И нет необходимости повторять несколько раз один и тот же код для

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

меняете один раз стиль и все элементы с этим стилем меняются.

В Android тоже есть стили и они имеют точно такое же назначение. Если у вас есть несколько элементов и вам надо,

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

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

тем кому это интересно прямо сейчас - прош у в эту ветку наш его форума. Пользователь icamys на примере

подробно разъясняет как использовать стили.

На следующем уроке:

- научимся обращаться к View-элементам из кода и менять их свойства

Единицы измерения. Чем отличается dp (dip) от px. Screen Density.

Для указания ш ирины, высоты и отступов View-элементов используются различные единицы измерения (ЕИ):

dp или dip - Density-independent Pixels. Абстрактная ЕИ, позволяющая приложениям выглядеть одинаково на различных экранах и

разреш ениях.

sp - Scale-independent Pixels. То же, что и dp, только используется для размеров ш рифта в View элементах

pt - 1/72 дюйма, определяется по физическому размеру экрана. Эта ЕИ из типографии.

px – пиксел, не рекомендуется использовать т.к. на разных экранах приложение будет выглядеть по-разному.

mm – миллиметр, определяется по физическому размеру экрана

in – дюйм, определяется по физическому размеру экрана

Давайте разбираться, чем они отличаются друг от друга.

in, mm и pt – неизменны относительно друг друга. Всегда 1 in = 25,4 mm и 1 in = 72 pt. Это классические единицы измерения. Т.е. задаете,

например, кнопке ш ирину = 1 in и она должна отобразиться ш ириной в один дюйм, независимо от разреш ения и диагонали экрана.

Что такое px, думаю, тоже понятно. Если у вас есть устройство с экраном ш ириной 480 px и вы создали кнопку ш ириной 240 px, то эта кнопка

займет в ш ирину ровно пол-экрана. Но если вы откроете ваш е приложение на устройстве с экраном с меньш им разреш ением, то

соотнош ение изменится, например:

- если разреш ение 320х240, ш ирина экрана = 240 px. Кнопка займет уже не пол-экрана в ш ирину, а весь экран

- если же разреш ение 1280х800, ш ирина = 800 px. Кнопка опять же будет занимать в ш ирину не пол-экрана, а чуть меньш е трети

А ведь экран приложения – это обычно не одна кнопка, а набор из многих элементов и все они будут расползаться или сжиматься на разных

разреш ениях. Поэтому использовать px при разработке НЕ рекомендуется.

Для того, чтобы избежать таких ситуаций на разных разреш ениях рекомендуется использовать dp (и sp). Его можно определить, как

масш табируемый px. За степень масш табируемости отвечает Screen Density. Это коэффициент, который используется системой для

вычисления значения dp. На текущий момент есть 5 значений этого коэффициента:

- low (ldpi) = 0,75

- medium (mdpi) = 1

- tv (tvdpi) = 1,33

- high (hdpi) = 1,5

- extra high (xhdpi) = 2

Т.е. когда для экрана стоит режим mdpi, то 1 dp = 1 px. Т.е. кнопка ш ириной 100 dp будет выглядеть также как и кнопка ш ириной 100 px.

Если, например, у нас экран с низким разреш ением, то используется режим ldpi. В этом случае 1 dp = 0,75 px. Т.е. кнопка ш ириной 100 dp

будет выглядеть так же как кнопка ш ириной 75 px.

Если у нас экран с высоким разреш ением, то используется режим hdpi или xhdpi. 1 dp = 1, 5 px или 2 px. И кнопка ш ириной 100 dp будет

выглядеть так же как кнопка ш ириной 150 px или 200 px.

Т.е. при различных разреш ениях используются различные Density режимы, которые позволяют приложениям масш табироваться и

выглядеть если не одинаково, то, по крайне мере, похоже на всех экранах.

Рассмотрим пример. Предположим у нас есть три устройства (характеристики реальны и взяты из спецификаций):

HTC Wildfire S: 3,2 inch, 480x320 px, 180 dpi

HTC Desire: 3,7 inch, 800x480 px, 252 dpi

HTC Flyer: 7 inch, 1280x800 px, 170 dpi

Я создам такой экран:

Это несколько кнопок, в которых ш ирина и размер ш рифта определены с использованием разных единиц измерения. На каждой кнопке для

наглядности я написал ее ш ирину (layout_width) и размер ш рифта (textSize) через запятую. Обратите внимание, что ш ирина всех кнопок

кроме последней одинакова. Так происходит потому, что 1 in = 72 pt = 25,4 mm в любом случае, а для данного экрана также 1 in = 252 px =

252 dp. Шрифты также везде одинаковы, т.к. размер ш рифта по умолчанию равен 14 sp и в данном случае равен 14 px.

xml-код:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:id="@+id/button1"

android:layout_height="wrap_content"

android:layout_width="1in"

android:text="1 inch, default"

android:id="@+id/button2"

android:layout_height="wrap_content"

android:layout_width="72pt"

android:text="72 pt, default"

android:id="@+id/button3"

android:layout_height="wrap_content"

android:layout_width="25.4mm"

android:text="25.4 mm, default"

android:id="@+id/button4"

android:layout_height="wrap_content"

android:layout_width="252px"

android:text="252 px, 14 px"

android:textSize="14px"

android:id="@+id/button5"

android:layout_height="wrap_content"

android:layout_width="252dp"

android:textSize="14sp"

android:text="252 dp, 14 sp"

android:id="@+id/button6"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="wrap_content, default"

Посмотрим, как это будет выглядеть на экранах других устройств:

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

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

устройствах.

Мы видим, что на всех экранах 1 px остался равен 1 dp (т.к. режим mdpi). И in, pt и mm сохранили свои пропорции (1; 72; 25,4) относительно

друг друга. Но обратите внимание, что 1 in уже не равен 252 px на экранах Wildfire и Flyer. Это потому, что у этих устройств другое

соотнош ение диагонали экрана и разреш ения:

- у Wildfire экран с dpi = 180, т.е. 1 in = 180 px, поэтому первая кнопка (с ш ириной = 1 inch) теперь короче, чем кнопка с ш ириной 252 px.

- для Flyer, соответственно, dpi = 170.

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

Но он есть и давайте смотреть, чем он полезен. Я включу режим ldpi для Wildfire и xhdpi для Flyer. Desire оставляю в mdpi.

Ширина кнопок указанная в in, mm, pt неизменна, на эти единицы измерения режимы Density влияния не имеют. Нам интересны четвертая и

пятая кнопки. Видим, что на экранах Wildfire и Flyer отличаются размеры px и dp, т.к. мы сменили mdpi на ldpi и xhdpi. Для Wildfire 1 dp стал

равен 0,75 px, а для Flyer 1 dp = 2 px. Также видим, что изменился ш рифт на кнопках, где размер ш рифта был указан по умолчанию или в sp-

единицах. Он так же, как и dp смасш табировался благодаря Density режимам. А ш рифт, размер которого был указан в px (четвертая кнопка)

оставался неизменным и на Wildfire выглядит крупным, а на Flyer – мелким.

Отлично видно, что адекватнее всего перенос на другие экраны перенесли пятая и ш естая кнопки. Для пятой кнопки используются dp и sp.

Для ш естой кнопки – ш ирина = wrap_content и размер ш рифта по умолчанию. А кнопки с in, mm, pt и px статичны и на разных экранах

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

использовать dp (для ш ирины, высоты и т.д.) и sp (для размера ш рифта).

Конечно Density не дает масш табирования абсолютно пропорциального разнице в разреш ениях экрана. Погреш ность есть, но она невелика

и является вполне приемлемой платой за способность приложения «сохранять форму» на разных устройствах.

Кем именно устанавливаются Density режимы для различных экранов – я не знаю. Но подозреваю, что производителями устройств/экранов.

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

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

Вы наверно обратили внимание, что в папке Андроид-проекта в Eclipse есть папки drawable c суффиксами hdpi, ldpi, mdpi:

Папка drawable используется для хранения изображений, а суффиксы дают понять системе из какой именно drawable использовать картинки

при текущем Density режиме. Подробнее об этом можно почитать в хелпе. Кстати, там же вы найдете уже изученный нами –land, который

связан с горизонтальной ориентацией экрана. Будем по мере изучения Андроид знакомиться с остальными.

Урок 8. Работаем с элементами экрана из кода

В этом уроке мы:

- научимся обращаться из кода к View-элементам на экране и менять их свойства

Создадим проект:

Project name: P0081_ViewById

Build Target: Android 2.3.3

Application name: ViewById

Package name: ru.startandroid.develop.viewbyid

Create Activity: MainActivity

Чтобы обратиться к элементу экрана из кода, нам нужен его ID. Он прописывается либо в Properties, либо в layout-файлах, как вам удобнее.

Для ID существует четкий формат - @+id/name, где + означает, что это новый ресурс и он должен добавиться в R.java класс, если он там еще

не существует.

Давайте откроем main.xml, для TextView укажем ID = @+id/myText и сохраним

Теперь откроем R.java и видим, что для класса id появилась константа myText. Т.е. чтобы к ней обратиться, надо написать R.id.myText.

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

метод findViewById. Он по ID возвращает View. Давайте напиш ем вызов этого метода. Напомню, что пока мы пиш ем наш код в методе

onCreate. Это метод, который вызывается при создании Activity. Если вдруг непонятно, куда писать, можно подсмотреть в конец урока, там я

выложил код.

Откроем MainActivity.java и после строки с вызовом метода setContentView напиш ем:

View myTextView = findViewById(R.id.myText);

Если View подчеркнуто красным, то скорей всего этот класс не добавлен в секцию import. Нажмите CTRL+SHIFT+O для автоматического

обновления импорта.

Теперь myTextView (типа View) – это наш TextView на экране. Но тип View – это предок для TextView (и остальных View-элементов). И он нам

не подходит, если мы хотим проделывать операции соответствующие TextView. Поэтому нам необходимо преобразование View в TextView.

Изменим наш код на следующий:

TextView myTextView = (TextView) findViewById(R.id.myText);

Теперь myTextView имеет тип TextView, а результат метода findViewById мы преобразуем из View в TextView. Теперь мы можем применять к

myTextView методы класса TextView. Для примера возьмем метод setText. Сейчас отображаемый текст = Hello World, MainActivity!. Мы его

программно поменяем на New text in TextView

myTextView.setText("New text in TextView");

Сохраняем, запускаем (CTRL+F11) и видим, что текст изменился

Добавим на экран кнопку (Button), Id = @+id/myBtn, текст оставим по умолчанию. Сохраняем - CTRL+SHIFT+S (если не сохранить, то в R.java

не появится ID).

Пиш ем код:

Button myBtn = (Button) findViewById(R.id.myBtn);

Обратите внимание, что у меня совпадает имя объекта и ID

Они друг другу не меш ают и так делать даже логичнее. Это остается на ваш е усмотрение. Так, кнопку мы наш ли, теперь давайте изменим ее

текст:

myBtn.setText("My button");

Запустим приложение. Текст на кнопке поменялся, на кнопку можно понажимать, но ничего происходить не будет. Т.к. мы нигде не

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

myBtn.setEnabled(false);

Мы поменяли параметр Enabled. Теперь на кнопку нельзя нажать. Сохраним, запустим и убедимся.

Добавим CheckBox, id = @+id/myChb. По умолчанию галочка не стоит. Давайте поставим ее программно, для этого используется метод

setChecked, который меняет параметр Checked.

CheckBox myChb = (CheckBox) findViewById(R.id.myChb);

myChb.setChecked(true);

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

Как видите – все несложно. Используем метод findViewById, чтобы по ID получить объект соответствующий какому-либо View-элементу

(Button, TextView, CheckBox) и далее вызываем необходимые методы объектов (setText, setEnabled, setChecked).

В итоге должен получиться такой код:

package ru.startandroid.develop.viewbyid;

import android.app.Activity;

import android.os.Bundle;

import android.widget.Button;

import android.widget.CheckBox;

import android.widget.TextView;

public class MainActivity extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

TextView myTextView = (TextView) findViewById(R.id.myText);

myTextView.setText("New text in TextView");

Button myBtn = (Button) findViewById(R.id.myBtn);

myBtn.setText("My button");

myBtn.setEnabled(false);

CheckBox myChb = (CheckBox) findViewById(R.id.myChb);

myChb.setChecked(true);

}

}

На следующем уроке:

- научимся обрабатывать нажатие кнопки

Урок 9. Обработчики событий на примере Button.

В этом уроке мы:

- научимся обрабатывать нажатие кнопки и узнаем, что такое обработчик

Создадим проект:

Project name: P0091_OnClickButtons

Build Target: Android 2.3.3

Application name: OnClickButtons

Package name: ru.startandroid.develop.onclickbuttons

Create Activity: MainActivity

В layout-файл main.xml напиш ем следующее и сохраним:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="horizontal"

android:id="@+id/linearLayout1"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_margin="30dp"

android:orientation="vertical"

android:id="@+id/tvOut"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:layout_marginBottom="50dp"

android:text="TextView"

android:id="@+id/btnOk"

android:layout_width="100dp"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:text="OK"

android:id="@+id/btnCancel"

android:layout_width="100dp"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:text="Cancel"

У нас есть TextView с текстом и две кнопки: OK и Cancel. Мы сделаем так, чтобы по нажатию кнопки менялось содержимое

TextView. По нажатию кнопки OK – будем выводить текст: «Нажата кнопка ОК», по нажатию Cancel – «Нажата кнопка Cancel».

Открываем MainActivity.java. Описание объектов вынесем за пределы метода onCreate. Это сделано для того, чтобы мы

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

метода findViewById. В итоге должен получиться такой код:

public class MainActivity extends Activity {

TextView tvOut;

Button btnOk;

Button btnCancel;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// найдем View-элементы

tvOut = (TextView) findViewById(R.id.tvOut);

btnOk = (Button) findViewById(R.id.btnOk);

btnCancel = (Button) findViewById(R.id.btnCancel);

}

}

Обновляем секцию import (CTRL+SHIFT+O). Объекты tvOut, btnOk и btnCancel соответствуют View-элементам экрана и мы

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

(View.OnClickListener l). На вход подается объект с интерфейсом View.OnClickListener. Именно этому объекту кнопка поручит

обрабатывать нажатия. Давайте создадим такой объект. Код продолжаем писать в onCreate:

OnClickListener oclBtnOk = new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

}

};

Eclipse подчеркивает OnClickListener красной линией

т.к. пока не знает его. Необходимо обновить секцию import. Жмем CTRL+SHIFT+O, Eclipse показывает нам, что он знает два

интерфейса с именем onClickListener и предлагает выбрать. Нам нужен View.OnClickListener, т.к. метод кнопки

setOnClickListener принимает на вход именно его.

Итак, мы создали объект oclBtnOk, который реализует интерфейс View.OnClickListener. Объект содержит метод onClick – это

как раз то, что нам нужно. Именно этот метод будет вызван при нажатии кнопки. Мы реш или, что по нажатию будем

выводить текст: «Нажата кнопка ОК» в TextView (tvOut). Реализуем это.

В методе onClick пиш ем:

tvOut.setText("Нажата кнопка ОК");

Обработчик нажатия готов. Осталось «скормить» его кнопке с помощью метода setOnClickListener.

btnOk.setOnClickListener(oclBtnOk);

В итоге должен получится такой код:

public class MainActivity extends Activity {

TextView tvOut;

Button btnOk;

Button btnCancel;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// найдем View-элементы

tvOut = (TextView) findViewById(R.id.tvOut);

btnOk = (Button) findViewById(R.id.btnOk);

btnCancel = (Button) findViewById(R.id.btnCancel);

// создаем обработчик нажатия

OnClickListener oclBtnOk = new OnClickListener() {

@Override

public void onClick(View v) {

// Меняем текст в TextView (tvOut)

tvOut.setText("Нажата кнопка ОК");

}

};

// присвоим обработчик кнопке OK (btnOk)

btnOk.setOnClickListener(oclBtnOk);

}

}

Все сохраняем и запускаем. Жмем на кнопку ОК и видим. Что текст изменился

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

аналогично, как для кнопки OK. Сначала мы создаем обработчик:

OnClickListener oclBtnCancel = new OnClickListener() {

@Override

public void onClick(View v) {

// Меняем текст в TextView (tvOut)

tvOut.setText("Нажата кнопка Cancel");

}

};

Потом присваиваем его кнопке:

btnCancel.setOnClickListener(oclBtnCancel);

Сохраняем, запускаем, проверяем. Обе кнопки теперь умеют обрабатывать нажатия.

Давайте еще раз проговорим механизм обработки событий на примере нажатия кнопки. Сама кнопка обрабатывать

нажатия не умеет, ей нужен обработчик (его также называют слуш ателем - listener), который присваивается с помощью

метода setOnClickListener. Когда на кнопку нажимают, обработчик реагирует и выполняет код из метода onClick. Это можно

изобразить так:

Соответственно для реализации необходимо выполнить следующие ш аги:

- создаем обработчик

- заполняем метод onClick

- присваиваем обработчик кнопке

и система обработки событий готова.

На следующем уроке:

- научимся использовать один обработчик для нескольких View-элементов

- научим Activity выступать в качестве обработчика

Урок 10. Оптимизируем реализацию обработчиков.

В этом уроке мы:

- научимся использовать один обработчик для нескольких View-элементов

- научим Activity выступать в качестве обработчика

Создадим проект:

Project name: P0101_Listener

Build Target: Android 2.3.3

Application name: Listener

Package name: ru.startandroid.develop.listener

Create Activity: MainActivity

Будем работать с теми же View, что и в предыдущем уроке. Код для main.xml:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_height="match_parent"

android:layout_width="match_parent"

android:orientation="horizontal"

android:id="@+id/linearLayout1"

android:layout_height="match_parent"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_margin="30dp"

android:layout_width="wrap_content"

android:text="TextView"

android:layout_height="wrap_content"

android:id="@+id/tvOut"

android:layout_gravity="center_horizontal"

android:layout_marginBottom="50dp"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:id="@+id/btnOk"

android:text="OK"

android:layout_width="100dp"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:id="@+id/btnCancel"

android:text="Cancel"

android:layout_width="100dp"

Один обработчик для двух кнопок

Итак, у нас есть TextView с текстом и две кнопки. Как и на прош лом уроке, мы сделаем так, чтобы по нажатию кнопки

менялось содержимое TextView. По нажатию кнопки OK – будем выводить текст: «Нажата кнопка ОК», по нажатию

Cancel – «Нажата кнопка Cancel». Но сейчас мы сделаем это с помощью одного обработчика, который будет

обрабатывать нажатия для обеих кнопок.

Напомню механизм обработки событий на примере нажатия кнопки. Сама кнопка обрабатывать нажатия не умеет,

ей нужен обработчик (listener), который присваивается с помощью метода setOnClickListener. Когда на кнопку

нажимают, обработчик реагирует и выполняет код из метода onClick.

Соответственно для реализации необходимо выполнить следующие ш аги:

- создаем обработчик

- заполняем метод onClick

- присваиваем обработчик кнопке

В наш ем случае мы будем присваивать один обработчик обеим кнопкам, а внутри обработчика надо будет

определять, какая именно кнопка была нажата.

Подготовим объекты и создадим обработчик:

public class MainActivity extends Activity {

TextView tvOut;

Button btnOk;

Button btnCancel;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// найдем View-элементы

tvOut = (TextView) findViewById(R.id.tvOut);

btnOk = (Button) findViewById(R.id.btnOk);

btnCancel = (Button) findViewById(R.id.btnCancel);

// создание обработчика

OnClickListener oclBtn = new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

}

};

}

}

Давайте заполнять метод onClick. На вход ему подается объект класса View, это как раз то, что нам нужно. Это View на

которой произош ло нажатие и которая вызвала обработчик. Т.е. в наш ем случае это будет либо кнопка OK либо

Cancel. Нам осталось узнать ID этой View и сравнить его с наш ими R.id.btnOk и R.id.btnCancel, чтобы определить

какая именно это кнопка. Чтобы получить ID какой-либо View, используется метод getId. Для перебора результатов

используем java-оператор switch.

Реализация метода onClick:

public void onClick(View v) {

// по id определеяем кнопку, вызвавшую этот обработчик

switch (v.getId()) {

case R.id.btnOk:

// кнопка ОК

tvOut.setText("Нажата кнопка ОК");

break;

case R.id.btnCancel:

// кнопка Cancel

tvOut.setText("Нажата кнопка Cancel");

break;

}

}

Если сейчас запустить приложение и проверить, то ничего не произойдет. Обработчик то мы создали, но не

присвоили его кнопкам. Обеим кнопкам присваиваем один и тот же обработчик:

btnOk.setOnClickListener(oclBtn);

btnCancel.setOnClickListener(oclBtn);

Вот теперь можем запускать и проверять, все должно работать.

Как вы понимаете, один обработчик может быть присвоен не двум, а любому количеству кнопок. И не только

кнопкам. У остальных View-элементов тоже есть различные события, которые нуждаются в обработчиках. В

дальнейш ем мы еще будем с ними работать. А сейчас важно понять схему, как происходит обработка событий.

Отличие способа реализации на этом уроке от прош лого урока в том, что сейчас мы создали один объект-

обработчик для обеих кнопок, а на прош лом уроке - два объекта, по одному каждой кнопке. Есть правило – чем

меньш е объектов вы создаете, тем лучш е, т.к. под каждый объект выделяется память, а это достаточно

ограниченный ресурс, особенно для телефонов. Поэтому создавать один обработчик для нескольких View это

правильнее с точки зрения оптимизации. К тому же кода становится меньш е и читать его удобнее.

Есть еще один способ создания обработчика, который вовсе не потребует создания объектов. Будет использоваться

уже созданный объект – Activity

Activity, как обработчик

Кнопка присваивает себе обработчика с помощью метода setOnClickListener (View.OnClickListener l). Т.е. подойдет

любой объект с интерфейсом View.OnClickListener. Почему бы классу Activity не быть таким объектом? Мы просто

укажем, что Activity-класс реализует интерфейс View.OnClickListener и заполним метод onCreate.

Создадим для этого новый проект:

Project name: P0102_ActivityListener

Build Target: Android 2.3.3

Application name: ActivityListener

Package name: ru.startandroid.develop.activitylistener

Create Activity: MainActivity

Экран снова возьмем тот же самый:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_height="match_parent"

android:layout_width="match_parent"

android:orientation="horizontal"

android:id="@+id/linearLayout1"

android:layout_height="match_parent"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_margin="30dp"

android:layout_width="wrap_content"

android:text="TextView"

android:layout_height="wrap_content"

android:id="@+id/tvOut"

android:layout_gravity="center_horizontal"

android:layout_marginBottom="50dp"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:id="@+id/btnOk"

android:text="OK"

android:layout_width="100dp"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:id="@+id/btnCancel"

android:text="Cancel"

android:layout_width="100dp"

Подготовим объекты и добавим реализацию интерфейса (implements onClickListener)

public class MainActivity extends Activity implements OnClickListener {

TextView tvOut;

Button btnOk;

Button btnCancel;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// найдем View-элементы

tvOut = (TextView) findViewById(R.id.tvOut);

btnOk = (Button) findViewById(R.id.btnOk);

btnCancel = (Button) findViewById(R.id.btnCancel);

}

}

OnClickListener подчеркнут красным, т.к. его нет в импорте. Поэтому CTRL+SHIFT+O и выбираем View.OnClickListener.

Теперь Eclipse ругается на класс MainActivity. Это происходит потому, что для класса прописан интерфейс, но нет

реализации методов этого интерфейса. Исправим это с помощью Eclipse. Наведите курсор на MainAcivity и

выберите Add unimplemented methods

Eclipse добавит знакомый нам метод onClick. Только теперь этот метод будет реализован в Activity, а не в отдельном

объекте-обработчике. Соответственно Activity и будет выступать обработчиком.

Заполним метод точно так же как и раньш е. Ничего не изменилось. Ему на вход так же подается View (на которой

произош ло событие), по Id мы определим, какая именно эта View и выполним соответствующие действия:

public void onClick(View v) {

// по id определеяем кнопку, вызвавшую этот обработчик

switch (v.getId()) {

case R.id.btnOk:

// кнопка ОК

tvOut.setText("Нажата кнопка ОК");

break;

case R.id.btnCancel:

// кнопка Cancel

tvOut.setText("Нажата кнопка Cancel");

break;

}

}

Осталось в методе onCreate присвоить обработчик кнопкам. Это будет объект this, т.е. текущий объект MainActivity.

btnOk.setOnClickListener(this);

btnCancel.setOnClickListener(this);

При такой реализации мы не создали ни одного лиш него объекта (Activity создается в любом случае) и затраты

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

особенно если мало опыта в объектно-ориентированном программировании. В таком случае используйте ту

реализацию, которая вам понятна и удобна. А со временем и опытом понимание обязательно придет.

Полный код:

public class MainActivity extends Activity implements OnClickListener {

TextView tvOut;

Button btnOk;

Button btnCancel;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// найдем View-элементы

tvOut = (TextView) findViewById(R.id.tvOut);

btnOk = (Button) findViewById(R.id.btnOk);

btnCancel = (Button) findViewById(R.id.btnCancel);

// присваиваем обработчик кнопкам

btnOk.setOnClickListener(this);

btnCancel.setOnClickListener(this);

}

@Override

public void onClick(View v) {

// по id определеяем кнопку, вызвавшую этот обработчик

switch (v.getId()) {

case R.id.btnOk:

// кнопка ОК

tvOut.setText("Нажата кнопка ОК");

break;

case R.id.btnCancel:

// кнопка Cancel

tvOut.setText("Нажата кнопка Cancel");

break;

}

}

}

Самая простая реализация обработчика

Есть еще один способ реализации. В layout-файле (main.xml) при описании кнопки пиш ем:

version="1.0" encoding="utf-8"?

android:id="@+id/btnStart"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="onClickStart"

android:text="start"

Т.е. используем атрибут onClick. В нем указываем имя метода из Activity. Этот метод и сработает при нажатии на

кнопку.

Далее, добавляем этот метод в Activity (MainActivity.java). Требования к методу: public, void и на вход принимает View:

public void onClickStart(View v) {

// действия при нажати на кнопку

}

В методе прописываете необходимые вам действия, и они будут выполнены при нажатии кнопки.

Урок 11. Папка res/values. Используем ресурсы приложения.

В этом уроке мы:

- узнаем, зачем нужна папка res/values, что в ней можно хранить и как использовать

В подпапках res хранятся различные ресурсы приложения. Мы уже отлично знаем про layout-файлы в папке res/layout. Я упоминал про

папку res/drawable с density-суффиксами – в ней хранятся картинки. Теперь обратим внимание на папку res/values. Она предназначена для

хранения ресурсов (констант) различных типов. Мы рассмотрим типы String и Color.

Создадим проект:

Project name: P0111_ResValues

Build Target: Android 2.3.3

Application name: ResValues

Package name: ru.startandroid.develop.resvalues

Create Activity: MainActivity

Откроем файл res/values/strings.xml

Мы видим два элемента типа String:

hello – по умолчанию он использован в свойстве Text в TextView в main.xml. И соответственно TextView отображает значение этого элемента.

app_name – по умолчанию используется как заголовок для приложения и Activity. Это указывается в манифест-файле, который мы еще не

разбирали.

На эти элементы можно кликнуть и увидеть справа, что они собой представляют: имя (Name) и значение (Value)

Name – это ID. Оно должно быть уникальным, и для него в R.java создается константа, чтобы мы могли иметь доступ к этому String-элементу.

Если мы посмотрим XML-содержимое файла strings.xml (вкладка снизу – аналогично как для main.xml), то видим, что там все прозрачно и

просто. Попробуем и мы использовать ресурсы.

Для начала создадим такой экран в main.xml:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_height="match_parent"

android:layout_width="match_parent"

android:orientation="vertical"

android:layout_width="match_parent"

android:id="@+id/llTop"

android:orientation="vertical"

android:layout_weight="1"

android:layout_height="match_parent"

android:text="TextView"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:id="@+id/tvTop"

android:layout_marginTop="30dp"

android:text="Button"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:id="@+id/btnTop"

android:layout_width="wrap_content"

android:layout_width="match_parent"

android:id="@+id/llBottom"

android:orientation="vertical"

android:layout_weight="1"

android:layout_height="match_parent"

android:text="TextView"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:id="@+id/tvBottom"

android:layout_marginTop="30dp"

android:text="Button"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:id="@+id/btnBottom"

Экран разделен на две одинаковые половины, содержащие LinearLayout, Button и TextView. Для LinearLayout мы укажем фоновый цвет, а для

TextView и Button – изменим текст. Реализуем это с помощью ресурсов. Причем View-элементы верхней части мы будем настраивать

вручную через properties, а нижнюю часть попробуем настроить программно.

Давайте создадим свой файл с ресурсами в папке values, название пусть будет myres.


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

Создадим 4 String-элемента и 2 Color-элемента:

version="1.0" encoding="utf-8"?

name="tvTopText"Верхний текст

name="btnTopText"Верхняя кнопка

name="tvBottomText"Нижний текст

name="btnBottomText"Нижняя кнопка

name="llTopColor"#336699

name="llBottomColor"#339966

Для практики можете создать вручную, а можете просто вставить этот текст в содержимое myres.xml. Не забудьте сохранить. Заглянем в

R.java, убедимся, что здесь все появилось:

Ок, ресурсы созданы, настроим View-элементы на их использование. Сначала верхние:

llTop – в Properties находим свойство Background, жмем кнопку выбора (три точки), в ветке Color выделяем llTopColor и жмем OK

tvTop – для свойства Text откройте окно выбора и найдите там tvTopText.

btnTop - для свойства Text откройте окно выбора и найдите там btnTopText.

Цвет верхней части изменился и тексты поменялись на те, что мы указывали в myres.xml.

Чтобы изменить нижнюю часть, будем кодить. Сначала находим элементы, потом присваиваем им значения.

public class MainActivity extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

LinearLayout llBottom = (LinearLayout) findViewById(R.id.llBottom);

TextView tvBottom = (TextView) findViewById(R.id.tvBottom);

Button btnBottom = (Button) findViewById(R.id.btnBottom);

llBottom.setBackgroundResource(R.color.llBottomColor);

tvBottom.setText(R.string.tvBottomText);

btnBottom.setText(R.string.btnBottomText);

}

}

Обратите внимание на то, что для смены текста используется метод setText. Только это не тот же setText, что мы использовали, когда

задавали текст напрямую. Этот на вход принимает ID и мы используем R.java, который хранит ID всех наш их ресурсов. Т.е. методы

называются одинаково, но на вход принимают разные параметры. Это нормальное явление в Java.

Сохраняем, запускаем и проверяем. Теперь тексты и цвета взяты из файла ресурсов. Вы можете изменить содержимое myres.xml (например

текст для верхней кнопки), сохранить, запустить приложение и увидите изменения.

Иногда необходимо в коде получить не ID ресурса, а его значение. Это делается следующим образом:

getResources().getString(R.string.tvBottomText);

Выражение вернет текст «Нижний текст», соответствующий String-ресурсу с name = tvBottomText.

Напоследок скажу пару слов об организации файлов для хранения ресурсов. Мы сейчас создали String и Color ресурсы в одном файле

myres.xml, но рекомендуется их разделять по разным файлам (например strings.xml, colors.xml ...), и в дальнейш ем я буду следовать этой

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

Имена ресурсов сквозные для всех файлов в папке res/values. Т.е. вы не можете в разных файлах создать ресурс с одним именем и типом.

Имена файлов ресурсов могут быть произвольными и файлов можно создавать сколько угодно. В R.java попадут все ресурсы из этих файлов.

На следующем уроке:

- рассмотрим логи приложения и всплывающие сообщения

Урок 12. Логи и всплывающие сообщения

В этом уроке мы:

- рассмотрим логи приложения и всплывающие сообщения

Создадим проект:

Project name: P0121_LogAndMess

Build Target: Android 2.3.3

Application name: LogAndMess

Package name: ru.startandroid.develop.logandmess

Create Activity: MainActivity

Создадим в main.xml экран, знакомый нам по прош лым урокам про обработчики:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_height="match_parent"

android:layout_width="match_parent"

android:orientation="horizontal"

android:id="@+id/linearLayout1"

android:layout_height="match_parent"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_margin="30dp"

android:layout_width="wrap_content"

android:text="TextView"

android:layout_height="wrap_content"

android:id="@+id/tvOut"

android:layout_gravity="center_horizontal"

android:layout_marginBottom="50dp"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:id="@+id/btnOk"

android:text="OK"

android:layout_width="100dp"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:id="@+id/btnCancel"

android:text="Cancel"

android:layout_width="100dp"

Алгоритм приложения будет тот же. По нажатию кнопок меняется текст. Обработчик - Activity.

public class MainActivity extends Activity implements OnClickListener {

TextView tvOut;

Button btnOk;

Button btnCancel;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// найдем View-элементы

tvOut = (TextView) findViewById(R.id.tvOut);

btnOk = (Button) findViewById(R.id.btnOk);

btnCancel = (Button) findViewById(R.id.btnCancel);

// присваиваем обработчик кнопкам

btnOk.setOnClickListener(this);

btnCancel.setOnClickListener(this);

}

@Override

public void onClick(View v) {

// по id определеяем кнопку, вызвавшую этот обработчик

switch (v.getId()) {

case R.id.btnOk:

// кнопка ОК

tvOut.setText("Нажата кнопка ОК");

break;

case R.id.btnCancel:

// кнопка Cancel

tvOut.setText("Нажата кнопка Cancel");

break;

}

}

}

Сохраним, запустим. Убедимся, что все работает.

Логи приложения

Когда вы тестируете работу приложения, вы можете видеть логи работы. Они отображаются в окне LogCat. Чтобы отобразить окно откройте

меню Window Show View Other … В появивш емся окне выберите Android LogCat

Должна появится вкладка LogCat

Рассмотрим эту вкладку подробней. Логи имеют разные уровни важности: ERROR, WARN, INFO, DEBUG, VERBOSE (по убыванию). Кнопки V

D I W E (в кружках) – это фильтры и соответствуют типам логов. Опробуйте их и обратите внимание, что фильтр показывает логи не только

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

рассмотрим чуть дальш е.

Давайте смотреть, как самим писать логи. Делается это совсем несложно с помощью класса Log и его методов Log.v() Log.d() Log.i() Log.w()

and Log.e(). Названия методов соответствуют уровню логов, которые они запиш ут.

Изменим код MainActivity.java. Возьмем все каменты из кода и добавим в DEBUG-логи с помощью метода Log.d. Метод требует на вход тэг и

текст сообщения. Тэг – это что-то типа метки, чтобы легче было потом в куче системных логов найти именно наш е сообщение. Добавим

описание тега (TAG) и запиш ем все тексты каментов в лог.

public class MainActivity extends Activity implements OnClickListener {

TextView tvOut;

Button btnOk;

Button btnCancel;

private static final String TAG = "myLogs";

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// найдем View-элементы

Log.d(TAG, "найдем View-элементы");

tvOut = (TextView) findViewById(R.id.tvOut);

btnOk = (Button) findViewById(R.id.btnOk);

btnCancel = (Button) findViewById(R.id.btnCancel);

// присваиваем обработчик кнопкам

Log.d(TAG, "присваиваем обработчик кнопкам");

btnOk.setOnClickListener(this);

btnCancel.setOnClickListener(this);

}

@Override

public void onClick(View v) {

// по id определеяем кнопку, вызвавшую этот обработчик

Log.d(TAG, "по id определеяем кнопку, вызвавшую этот обработчик");

switch (v.getId()) {

case R.id.btnOk:

// кнопка ОК

Log.d(TAG, "кнопка ОК");

tvOut.setText("Нажата кнопка ОК");

break;

case R.id.btnCancel:

// кнопка Cancel

Log.d(TAG, "кнопка Cancel");

tvOut.setText("Нажата кнопка Cancel");

break;

}

}

}

Eclipse ругнется, что не знает класс Log. Обновите импорт (CTRL+SHIFT+O) и, если спросит, выберите android.util.Log. Запустим приложение,

понажимаем кнопки и посмотрим логи

Видно, что все отлично записалось. Чтобы сделать просмотр удобней, создадим свой фильтр. Жмем значок +

Имя фильтра произвольное, например, «My logs». Log Tag – это как раз значение константы TAG, которая описан в наш ем коде и

использовалась в методе Log.d, т.е. - "myLogs". Pid оставляем пустым, это id процесса. Уровень поставим Debug

и жмем OK. Появилась новая вкладка My logs, на которой отображаются логи, соответствующие только что созданному фильтру.

Мы помещали в лог текст, но разумеется, вы можете писать, например, значения интересующих вас переменных (приведенные к типу String).

Иногда бывает, что логи не отображаются во вкладке LogCat, хотя AVD запущен, приложение работает без проблем. В таком случае должно

помочь следующее: в Eclipse идем в меню Window Open Perspective Other DDMS. Откроется немного другой набор окон чем обычно.

Там найдите вкладку Devices и в ней должно быть видно ваш е AVD-устройство, кликните на него и логи должны появиться. Чтобы вернуться в

разработку: Window Open Perspective Java.

Всплывающие сообщения

Приложение может показывать всплывающие сообщения с помощью класса Toast. Давайте подредактируем метод onClick. Сделаем так,

чтобы всплывало сообщение о том, какая кнопка была нажата.

public void onClick(View v) {

// по id определеяем кнопку, вызвавшую этот обработчик

Log.d(TAG, "по id определеяем кнопку, вызвавшую этот обработчик");

switch (v.getId()) {

case R.id.btnOk:

// кнопка ОК

Log.d(TAG, "кнопка ОК");

tvOut.setText("Нажата кнопка ОК");

Toast.makeText(this, "Нажата кнопка ОК", Toast.LENGTH_LONG).show();

break;

case R.id.btnCancel:

// кнопка Cancel

Log.d(TAG, "кнопка Cancel");

tvOut.setText("Нажата кнопка Cancel");

Toast.makeText(this, "Нажата кнопка Cancel", Toast.LENGTH_LONG).show();

break;

}

}

Разберем синтаксис вызова. Статический метод makeText создает View-элемент Toast. Параметры метода:

- context – пока не будем вдаваться в подробности, что это такое и используем текущую Activity, т.е. this.

- text – текст, который надо показать

- duration – продолжительность показа (Toast.LENGTH_LONG - длинная, Toast.LENGTH_SHORT - короткая)

Toast создан и чтобы он отобразился на экране, вызывается метод show(). Сохраняем, запускаем, проверяем.

Если у вас есть Андроид-смартфон, я думаю вы уже видели подобные сообщения. Теперь вы знаете, как это делается )

На следующем уроке:

- создаем пункты меню

Урок 13. Создание простого меню

В этом уроке мы:

- создаем пункты меню

Что такое меню, думаю, нет смысла рассказывать. Оно отображается при нажатии кнопки Menu. Давайте создадим

свое.

Создаем проект:

Project name: P0131_MenuSimple

Build Target: Android 2.3.3

Application name: MenuSimple

Package name: ru.startandroid.develop.menusimple

Create Activity: MainActivity

Откроем MainActivity.java. За создание меню отвечает метод onCreateOptionsMenu. На вход ему подается объект

типа Menu, в который мы и будем добавлять свои пункты. Добавляются они просто, методом add. На вход методу

подается текст пункта меню. Добавим 4 пункта.

public boolean onCreateOptionsMenu(Menu menu) {

// TODO Auto-generated method stub

menu.add("menu1");

menu.add("menu2");

menu.add("menu3");

menu.add("menu4");

return super.onCreateOptionsMenu(menu);

}

Метод onCreateOptionsMenu должен вернуть результат типа boolean. True – меню показывать, False – не показывать.

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

передавая False. Пока нам это не нужно, поэтому поручаем этот выбор конструктору суперкласса, по умолчанию он

возвращает True.

Сохраним все, запустим приложение и нажмем кнопку меню на эмуляторе.

Появилось 4 пункта меню. Нажатие на них ни к чему не приводит, т.к. не реализован обработчик. Обработчиком

является Activity, а метод зовется onOptionsItemSelected. На вход ему передается пункт меню, который был нажат –

MenuItem. Определить, какое именно меню было нажато можно по методу getTitle. Давайте выводить всплывающее

сообщение с текстом нажатого пункта меню. На выходе метода надо возвращать boolean. И мы снова предоставляем

это суперклассу.

public boolean onOptionsItemSelected(MenuItem item) {

// TODO Auto-generated method stub

Toast.makeText(this, item.getTitle(), Toast.LENGTH_SHORT).show();

return super.onOptionsItemSelected(item);

}

Полный код:

public class MainActivity extends Activity {

/** 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) {

// TODO Auto-generated method stub

menu.add("menu1");

menu.add("menu2");

menu.add("menu3");

menu.add("menu4");

return super.onCreateOptionsMenu(menu);

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

// TODO Auto-generated method stub

Toast.makeText(this, item.getTitle(), Toast.LENGTH_SHORT).show();

return super.onOptionsItemSelected(item);

}

}

Определять нажатый пункт меню по тексту – это не самый лучш ий вариант. Далее будем делать это по ID. Но для

этого надо немного по другому создавать меню.

На следующем уроке:

- создаем пункты меню с ID

- группируем и сортируем пункты меню

Урок 14. Меню, группы, порядок. MenuInflater и xml-меню.

В этом уроке мы:

- создаем пункты меню c ID

- группируем и сортируем пункты меню

На прош лом уроке мы рассмотрели простейш ий способ создания меню методом add(CharSequence title), на вход

мы подавали только текст. Рассмотрим другую реализацию этого метода - add(int groupId, int itemId, int order,

CharSequence title). У этого метода 4 параметра на вход:

- groupId - идентификатор группы, частью которой является пункт меню

- itemId - ID пункта меню

- order - для задания последовательности показа пунктов меню

- title - текст, который будет отображен

Чтоб показать как используются все эти параметры, создадим приложение. На экране будет TextView и CheckBox:

- TextView будет отображать какой пункт меню был выбран

- CheckBox будет определять показывать обычное меню или расш иренное. Это будет реализовано с помощью групп

меню.

Сразу уточню, понятия "обычное" и "расш иренное" - это не Андроид-понятия, а просто мои названия. Т.е. когда

запущено приложение и пользователь жмет кнопку меню, он видит "обычное" меню. Если же он включит CheckBox,

то будет отображаться "расш иренное" меню, в котором больш е пунктов.

Создаем проект:

Project name: P0141_MenuAdv

Build Target: Android 2.3.3

Application name: MenuAdv

Package name: ru.startandroid.develop.menuadv

Create Activity: MainActivity

Откроем main.xml, присвоим ID существующему TextView, сотрем его текст и создадим CheckBox. Код:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/chbExtMenu"

android:text="расширенное меню"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:id="@+id/textView"

Открываем MainActivity.java и класс MainActivity заполняем следующим кодом:

public class MainActivity extends Activity {

// Элементы экрана

TextView tv;

CheckBox chb;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// находим эдементы

tv = (TextView) findViewById(R.id.textView);

chb = (CheckBox) findViewById(R.id.chbExtMenu);

}

// создание меню

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// TODO Auto-generated method stub

// добавляем пункты меню

menu.add(0, 1, 0, "add");

menu.add(0, 2, 0, "edit");

menu.add(0, 3, 3, "delete");

menu.add(1, 4, 1, "copy");

menu.add(1, 5, 2, "paste");

menu.add(1, 6, 4, "exit");

return super.onCreateOptionsMenu(menu);

}

// обновление меню

@Override

public boolean onPrepareOptionsMenu(Menu menu) {

// TODO Auto-generated method stub

// пункты меню с ID группы = 1 видны, если в CheckBox стоит галка

menu.setGroupVisible(1, chb.isChecked());

return super.onPrepareOptionsMenu(menu);

}

// обработка нажатий

@Override

public boolean onOptionsItemSelected(MenuItem item) {

// TODO Auto-generated method stub

StringBuilder sb = new StringBuilder();

// Выведем в TextView информацию о нажатом пункте меню

sb.append("Item Menu");

sb.append("\r\n groupId: " + String.valueOf(item.getGroupId()));

sb.append("\r\n itemId: " + String.valueOf(item.getItemId()));

sb.append("\r\n order: " + String.valueOf(item.getOrder()));

sb.append("\r\n title: " + item.getTitle());

tv.setText(sb.toString());

return super.onOptionsItemSelected(item);

}

}

Не забудьте обновить импорт (CTRL+SHIFT+O).

Давайте разбирать написанное. Мы используем следующие методы:

onCreateOptionsMenu - вызывается только при первом показе меню. Создает меню и более не используется. Здесь

мы добавляем к меню пункты.

onPrepareOptionsMenu - вызывается каждый раз перед отображением меню. Здесь мы вносим изменения в уже

созданное меню, если это необходимо

onOptionsItemSelected - вызывается при нажатии пункта меню. Здесь мы определяем какой пункт меню был нажат.

В методе onCreateOptionsMenu мы добавляем 6 пунктов меню. Обратим внимание на параметры метода Add.

Первый параметр – ID группы. В первых трех пунктах он равен нулю, в оставш ихся трех – 1. Т.е. пункты меню copy,

paste и exit объединены в группу с ID = 1. Визуально это никак не проявляется - они не отличаются цветом или еще

чем-либо. ID группы мы будем использовать в реализации onPrepareOptionsMenu.

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

Будем использовать его в onOptionsItemSelected.

Третий параметр – определяет позицию пункта меню. Этот параметр используется для определения порядка

пунктов при отображении меню. Используется сортировка по возрастанию, т.е. от меньш его order к больш ему.

Четвертый параметр – текст, который будет отображаться на пункте меню. Тут все понятно.

В метод onPrepareOptionsMenu передается объект Menu и мы можем работать с ним. В данном примере вызываем

setGroupVisible. Этот метод позволяет скрывать\отображать пункты меню. На вход подается два параметра – ID

группы и boolean-значение. В качестве ID группы мы пиш ем – 1 (та самая группа с ID = 1, в которой находятся

пункты copy, paste и exit), а в качестве boolean параметра используем состояние CheckBox. Если он включен, то

пункты меню (из группы с ID = 1) будут отображаться, если выключен – не будут.

Сохраним все и запустим приложение.

"Обычное" меню:

"Расширенное" меню

В зависимости от состояния CheckBox в меню видно 3 или 6 пунктов.

Обратите внимание на порядок пунктов. Они отсортированы по параметру order по возрастанию. Если order у

нескольких пунктов совпадает, то эти пункты размещаются в порядке их создания в методе onCreateOptionsMenu.

При нажатии на какой-либо пункт меню срабатывает метод onOptionsItemSelected. В нем мы выводим в TextView

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

Все параметры должны совпадать. Порядок, для удобства, я сделал такой же как и в методе add: groupId, itemId,

order, title.

Попробуйте добавить еще несколько пунктов в меню, чтобы их стало больше шести. И обратите внимание, как они

отобразятся.

Для упрощения кода я использовал напрямую цифры для ID групп и ID пунктов меню. А вообще рекомендуется

использовать константы, в дальнейш ем буду использовать их.

XML-меню

Есть еще один, более удобный и предпочтительный способ создания меню - с использованием xml-файлов,

аналогично layout-файлам при создании экрана. Чтобы получить меню, которые мы создавали программно на этом

уроке, надо создать в папке res/menu файл mymenu.xml:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/menu_add"

android:title="add"

android:id="@+id/menu_edit"

android:title="edit"

android:id="@+id/menu_delete"

android:orderInCategory="3"

android:title="delete"

android:id="@+id/group1"

android:id="@+id/menu_copy"

android:orderInCategory="1"

android:title="copy"

android:id="@+id/menu_paste"

android:orderInCategory="2"

android:title="paste"

android:id="@+id/menu_exit"

android:orderInCategory="4"

android:title="exit"

item - это пункт меню, group - группа. В атрибутах ID используем ту же схему, что и в ID экранных компонентов, т.е.

пиш ем @+id/ и Eclipse сам создаст эти ID в R.java. Атрибут orderInCategory - это порядок пунктов, а title -

текст.

В методе onCreateOptionsMenu нам теперь не надо вручную кодить создание каждого пункта, мы просто свяжем

menu, который нам дается на вход и наш xml-файл.

public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.mymenu, menu);

return super.onCreateOptionsMenu(menu);

}

С помощью метода getMenuInflater мы получаем MenuInflater и вызываем его метод inflate. На вход передаем наш

файл mymenu.xml из папки res/menu и объект menu. MenuInflater берет объект menu и наполняет его пунктами

согласно файлу mymenu.xml.

Если захотите скрыть группу, выполняете тот же метод setGroupVisible и передаете туда R.id.group1 в качестве ID

группы.

Подробно атрибуты для xml-файла меню можно посмотреть здесь.

Я вам рекомендую опробовать и потестить оба способа созданию меню. Программное создание гибче, а xml

сокращает код.

На следующем уроке:

- создадим контекстное меню

Урок 15. Контекстное меню

В этом уроке мы:

- создадим контекстное меню

Контекстное меню вызывается в Андроид длительным нажатием на каком-либо экранном компоненте. Обычно оно

используется в списках. Когда на экран выводится список однородных объектов (например письма в почт.ящике) и,

чтобы выполнить действие с одним из этих объектов, мы вызываем контекстное меню для него. Но т.к. списки мы

еще не проходили, сделаем пример попроще и будем вызывать контекстное меню для TextView.

Создадим проект:

Project name: P0151_ContextMenu

Build Target: Android 2.3.3

Application name: ContextMenu

Package name: ru.startandroid.develop.contextmenu

Create Activity: MainActivity

Откроем main.xml и нарисуем там два TextView:

version="1.0" encoding="utf-8"?

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_height="wrap_content"

android:textSize="26sp"

android:layout_width="wrap_content"

android:id="@+id/tvColor"

android:layout_marginBottom="50dp"

android:layout_marginTop="50dp"

android:text="Text color"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:textSize="22sp"

android:id="@+id/tvSize"

android:text="Text size"

Для первого TextView мы сделаем контекстное меню, с помощью которого будем менять цвет текста. Для второго –

будем менять размер текста.

Принцип создания контекстного меню похож на создание обычного меню. Но есть и отличия.

Метод создания onCreateContextMenu вызывается каждый раз перед показом меню. На вход ему передается:

- ContextMenu, в который мы будем добавлять пункты

- View - элемент экрана, для которого вызвано контекстное меню

- ContextMenu.ContextMenuInfo – содержит доп.информацию, когда контекстное меню вызвано для элемента

списка. Пока мы это не используем, но когда будем изучать списки увидим, что ш тука полезная.

Метод обработки onContextItemSelected аналогичный методу onOptionsItemSelected для обычного меню. На вход

передается MenuItem – пункт меню, который был нажат.

Также нам понадобится третий метод registerForContextMenu. На вход ему передается View и это означает, что для

этой View необходимо создавать контекстное меню. Если не выполнить этот метод, контекстное меню для View

создаваться не будет.

Давайте кодить, открываем MainActivity.java. Опиш ем и найдем TextView и укажем, что необходимо создавать для

них контекстное меню.

TextView tvColor, tvSize;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

tvColor = (TextView) findViewById(R.id.tvColor);

tvSize = (TextView) findViewById(R.id.tvSize);

// для tvColor и tvSize необходимо создавать контекстное меню

registerForContextMenu(tvColor);

registerForContextMenu(tvSize);

}

Теперь опиш ем создание контекстных меню. Используем константы для хранения ID пунктов меню.

final int MENU_COLOR_RED = 1;

final int MENU_COLOR_GREEN = 2;

final int MENU_COLOR_BLUE = 3;

final int MENU_SIZE_22 = 4;

final int MENU_SIZE_26 = 5;

final int MENU_SIZE_30 = 6;

И создаем

@Override

public void onCreateContextMenu(ContextMenu menu, View v,

ContextMenuInfo menuInfo) {

// TODO Auto-generated method stub

switch (v.getId()) {

case R.id.tvColor:

menu.add(0, MENU_COLOR_RED, 0, "Red");

menu.add(0, MENU_COLOR_GREEN, 0, "Green");

menu.add(0, MENU_COLOR_BLUE, 0, "Blue");

break;

case R.id.tvSize:

menu.add(0, MENU_SIZE_22, 0, "22");

menu.add(0, MENU_SIZE_26, 0, "26");

menu.add(0, MENU_SIZE_30, 0, "30");

break;

}

}

Обратите внимание, что мы по ID определяем View, для которого вызвано контекстное меню и в зависимости от

этого создаем определенное меню. Т.е. если контекстное меню вызвано для tvColor, то мы создаем меню с

перечислением цветов, а если для tvSize – с размерами шрифта.

В качестве ID пунктов мы использовали константы. Группировку и сортировку не используем, поэтому используем

нули в качестве соответствующих параметров.

Можно все сохранить и запустить. При долгом нажатии на TextView должны появляться контекстные меню.

Но нажатие на них ничего не дает, т.к. не мы не прописали обработку в методе onContextItemSelected. Давайте

пропиш ем:

@Override

public boolean onContextItemSelected(MenuItem item) {

// TODO Auto-generated method stub

switch (item.getItemId()) {

// пункты меню для tvColor

case MENU_COLOR_RED:

tvColor.setTextColor(Color.RED);

tvColor.setText("Text color = red");

break;

case MENU_COLOR_GREEN:

tvColor.setTextColor(Color.GREEN);

tvColor.setText("Text color = green");

break;

case MENU_COLOR_BLUE:

tvColor.setTextColor(Color.BLUE);

tvColor.setText("Text color = blue");

break;

// пункты меню для tvSize

case MENU_SIZE_22:

tvSize.setTextSize(22);

tvSize.setText("Text size = 22");

break;

case MENU_SIZE_26:

tvSize.setTextSize(26);

tvSize.setText("Text size = 26");

break;

case MENU_SIZE_30:

tvSize.setTextSize(30);

tvSize.setText("Text size = 30");

break;

}

return super.onContextItemSelected(item);

}

В этом методе мы определяем по ID, какой пункт меню был нажат. И выполняем соответствующие действия: меняем

цвет текста для tvColor или размер ш рифта для tvSize. Сохраняем, запускаем и проверяем, что контекстные меню

теперь реагируют на нажатия и делают то, что от них требуется.

Для расш ирения кругозора я хотел бы еще кое-что написать по этой теме. Возможно, это покажется пока

сложноватым, так что если вдруг будет непонятно, ничего страш ного. Итак, мысли вслух.

Мы использовали метод registerForContextMenu (View view) для включения контекстного меню для определенного

View. Этот метод принадлежит классу Activity. Я посмотрел исходники этого метода, там написано следующее:

public void registerForContextMenu(View view) {

view.setOnCreateContextMenuListener(this);

}

Вспоминаем наш урок по обработчикам и смотрим хелп по методу setOnCreateContextMenuListener

(View.OnCreateContextMenuListener l). Получается, что View в качестве обработчика создания контекстного меню

использует объект this. В данном случае, этот код в Activity, значит this – это Activity и есть. Т.е. когда View хочет

показать контекстное меню, оно обращается к обработчику (Activity), а он уже выполняет свой метод

onCreateContextMenu. Т.е. тот же самый принцип, что и при обычном нажатии (Click).

И строка в MainActivity.java:

registerForContextMenu(tvColor);

абсолютно равнозначна этой строке:

tvColor.setOnCreateContextMenuListener(this);

Вообще мы можем создать свой объект, реализующий интерфейс View.OnCreateContextMenuListener и использовать

его вместо Activity в качестве обработчика создания контекстного меню.

Не забывайте, что для контекстного меню вы также можете использовать XML-способ, который был рассмотрен в

конце прош лого урока. Попробуйте сделать этот же урок, но уже с использованием XML-меню.

Полный код урока:

public class MainActivity extends Activity {

final int MENU_COLOR_RED = 1;

final int MENU_COLOR_GREEN = 2;

final int MENU_COLOR_BLUE = 3;

final int MENU_SIZE_22 = 4;

final int MENU_SIZE_26 = 5;

final int MENU_SIZE_30 = 6;

TextView tvColor, tvSize;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

tvColor = (TextView) findViewById(R.id.tvColor);

tvSize = (TextView) findViewById(R.id.tvSize);

// для tvColor и tvSize необходимо создавать контекстное меню

registerForContextMenu(tvColor);

registerForContextMenu(tvSize);

}

@Override

public void onCreateContextMenu(ContextMenu menu, View v,

ContextMenuInfo menuInfo) {

// TODO Auto-generated method stub

switch (v.getId()) {

case R.id.tvColor:

menu.add(0, MENU_COLOR_RED, 0, "Red");

menu.add(0, MENU_COLOR_GREEN, 0, "Green");

menu.add(0, MENU_COLOR_BLUE, 0, "Blue");

break;

case R.id.tvSize:

menu.add(0, MENU_SIZE_22, 0, "22");

menu.add(0, MENU_SIZE_26, 0, "26");

menu.add(0, MENU_SIZE_30, 0, "30");

break;

}

}

@Override

public boolean onContextItemSelected(MenuItem item) {

// TODO Auto-generated method stub

switch (item.getItemId()) {

// пункты меню для tvColor

case MENU_COLOR_RED:

tvColor.setTextColor(Color.RED);

tvColor.setText("Text color = red");

break;

case MENU_COLOR_GREEN:

tvColor.setTextColor(Color.GREEN);

tvColor.setText("Text color = green");

break;

case MENU_COLOR_BLUE:

tvColor.setTextColor(Color.BLUE);

tvColor.setText("Text color = blue");

break;

// пункты меню для tvSize

case MENU_SIZE_22:

tvSize.setTextSize(22);

tvSize.setText("Text size = 22");

break;

case MENU_SIZE_26:

tvSize.setTextSize(26);

tvSize.setText("Text size = 26");

break;

case MENU_SIZE_30:

tvSize.setTextSize(30);

tvSize.setText("Text size = 30");

break;

}

return super.onContextItemSelected(item);

}

}

На следующем уроке:

- рисуем экран программно, а не через layout-файл


Получите в подарок сайт учителя

Предмет: Информатика

Категория: Уроки

Целевая аудитория: Прочее.
Урок соответствует ФГОС

Скачать
"Обучение программированию под Android". Урок 2-15.

Автор: Темиров Артур Сергеевич

Дата: 11.06.2014

Номер свидетельства: 102552

Похожие файлы

object(ArrayObject)#852 (1) {
  ["storage":"ArrayObject":private] => array(6) {
    ["title"] => string(80) ""Обучение программированию под Android". Урок 1. "
    ["seo_title"] => string(49) "obuchieniie-proghrammirovaniiu-pod-android-urok-1"
    ["file_id"] => string(6) "101610"
    ["category_seo"] => string(11) "informatika"
    ["subcategory_seo"] => string(5) "uroki"
    ["date"] => string(10) "1402423684"
  }
}


Получите в подарок сайт учителя

Видеоуроки для учителей

Курсы для учителей

ПОЛУЧИТЕ СВИДЕТЕЛЬСТВО МГНОВЕННО

Добавить свою работу

* Свидетельство о публикации выдается БЕСПЛАТНО, СРАЗУ же после добавления Вами Вашей работы на сайт

Удобный поиск материалов для учителей

Проверка свидетельства