Основы создания интерфейса
Введение в создание интерфейса
Графический интерфейс пользователя представляет собой иерархию объектов android.view.View и android.view.ViewGroup . Каждый объект ViewGroup представляет контейнер, который содержит и упорядочивает дочерние объекты View . В частности, к контейнерам относят такие элементы, как RelativeLayout, LinearLayout, GridLayout, ConstraintLayout и ряд других.
Простые объекты View представляют собой элементы управления и прочие виджеты, например, кнопки, текстовые поля и т.д., через которые пользователь взаимодействует с программой:
Большинство визуальных элементов, наследующихся от класса View, такие как кнопки, текстовые поля и другие, располагаются в пакете android.widget
При определении визуального у нас есть три стратегии:
Создать элементы управления программно в коде java
Объявить элементы интерфейса в XML
Сочетание обоих способов — базовые элементы разметки определить в XML, а остальные добавлять во время выполнения
Сначала рассмотрим первую стратегию — определение интерейса в коде Java.
Создание интерфейса в коде java
Для работы с визуальными элементами создадим новый проект. В качестве шаблона проекта выберем Empty Activity :
Пусть он будет называться ViewsApp:
И после создания проекта два основных файла, которые будут нас интересовать при создании визуального интерфейса — это класс MainActivity и определение интерфейса для этой activity в файле activity_main.xml .
Определим в классе MainActivity простейший интерфейс:
При создании виджетов в коде Java применяется их конструктор, в который передается контекст данного виджета, а точнее объект android.content.Context , в качестве которого выступает текущий класс MainActivity.
Здесь весь интерфейс представлен элементом TextView, которое предназначено для выводa текста. С помощью методов, которые, как правило, начинаются на set , можно установить различные свойства TextView. Например, в данном случае метод setText() устанавливает текст в поле, а setTextSize() задает высоту шрифта.
Для установки элемента в качестве интерфейса приложения в коде Activity вызывается метод setContentView() , в который передается визуальный элемент.
Если мы запустим приложение, то получим следующий визуальный интерфейс:
Подобным образом мы можем создавать более сложные интерейсы. Например, TextView, вложенный в ConstraintLayout:
Для каждого контейнера конкретные действия по добавлению и позиционированию в нем элемента могут отличаться. В данном случае контейнеров выступает класс ConstraintLayout, поэтому для определения позиционирования и размеров элемента необходимо создать объект ConstraintLayout.LayoutParams . (Для LinearLayout это соответственно будет LinearLayout.LayoutParams, а для RelativeLayout — RelativeLayout.LayoutParams и т.д.). Этот объект инициализируется двумя параметрами: шириной и высотой. Для указания ширины и высоты можно использовать константу ViewGroup.LayoutParams.WRAP_CONTENT , которая устанавливает размеры элемента, необходимые для размещения а экране его содержимого.
Далее определяется позиционирование. В зависимости от типа контейнера набор устанавливаемых свойств может отличаться. Так, строка кода
указывает, что левая граница элемента будет выравниваться по левой ганице контейнера.
указывает, что верхняя граница элемента будет выравниваться по верхней ганице контейнера. В итоге элемент будет размещен в левом верхнем углу ConstraintLayout.
Для установки всех этих значений для конкретного элемента (TextView) в его метод setLayoutParams() передается объект ViewGroup.LayoutParams (или один из его наследников, например, ConstraintLayout.LayoutParams).
Все классы контейнеров, которые наследуются от android.view.ViewGroup (RelativeLayout, LinearLayout, GridLayout, ConstraintLayout и т.д.), имеют метод void addView(android.view.View child) , который позволяет добавить в контейнер другой элемент — обычный виджет типа TextView или другой контейнер. И в данном случае посредством данного метода TextView добавляется в ConstraintLayout:
Опять же отмечу, что для конкретного контейнера конкретные действия могут отличаться, но как правило для всех характерно три этапа:
Создание объекта ViewGroup.LayoutParams и установка его свойств
Передача объекта ViewGroup.LayoutParams в метод setLayoutParams() элемента
Передача элемента для добавления в метод addView() объекта контейнера
Хотя мы можем использовать подобный подход, в то же время более оптимально определять визуальный интерейс в файлах xml, а всю связанную логику определять в классе activity. Тем самым мы достигнем разграничения интерфейса и логики приложения, их легче будет разрабатывать и впоследствии модифицировать. И в следующей теме мы это рассмотрим.
Источник
Android – создание простого пользовательского интерфейса
Создание простого пользовательского интерфейса в android приложении
Графический интерфейс андроид приложений строится на иерархии из элементов двух типов: View и ViewGroup. Элементами типа View являются любые дочерние элементы пользовательского интерфейса (UI widgets), такие как кнопка (button), поле для ввода и пр. ViewGroup – это невидимый контейнер графических элементов (вышеупомянутых view), определяющий их размещение на интерфейсе. Это может быть вертикальный, горизонтальный список или таблицы элементов.. Один ViewGroup может содержать множество view и другие ViewGroup. Оперируя различными графическими элементами и контейнерами эл-в можно создавать интерфейсы.
Иерархия view и viewGroup при построении пользовательского интерфейса в android
Перейдем от теории к практике, изменим стандартный экран приложения (HelloWorld), который отображается при запуске (ну или можете создать новое приложение 😉 ). Откроем текущее отображение экрана (файл activity_main.xml из директории res/layout).
Создание LinearLaout
Обратите внимание, что перед Вами открылся визуальный редактор интерфейса (Graphical layout). Все действия можно выполнять тут, а можно перейти в режим отображения кода ( activity_main.xml – слева внизу под набором доступных элементов). Я использую оба варианта. Как по мне удобно накидать необходимых элементов с помощью графического редактора а потом уже точечно по необходимости подправить каждый элемент в коде. Выбирайте удобный для Вас способ, но настоятельно рекомендую разобраться с тем, что пишется в коде.
По умолчанию на форме находится RelativeLayout (ViewGrop) и текстовое поле (view). Подробно о каждом контейнере поговорим позже, сейчас удалим текст с экрана и поменяем стандартный Layout на LinearLaout, в который добавим поле android:orientation и установим значение «horizontal» .
LinearLaout – это ViewGrop, который отображает дочерние элементы один за другим в вертикальном или горизонтальном формате, в зависимости от значения поля android:orientation . Используя линейный контейнер графические элементы на экране будут отображены в том же порядке, в котором они находятся в xml файле.
Поля android:layout_width и android:layout_height должны быть указаны для всех графических элементах для указания их размера. Учитывая, что наш LinearLaout это корневой элемент интерфейса, мы указываем ему заполнить все пространство экрана, устанавливая width и height равными «match_parent» .
Создание простого интерфейса в android с LinearLayout
Добавление текстового поля
Далее добавим в интерфейс текстовое поле для ввода (элемент EditText ). Как и при использовании любого другого графического элемента, необходимо указать некоторые основные свойства данного объекта. В нашем случае элемент задается следующим кодом:
Добавление поля для ввода текста в android интерфейс
В этом случае свойства android:layout_width и android:layout_height заданы как «wrap_content» , указывая что элементы должны быть такого размера, чтобы заполнить содержимое отображения. Если Вы укажите значение «match_parent» , то поле для ввода заполнит весь экран т.к. указано что оно должно растянуться до размера своего предка – LinearLayout .
Свойство android:id – это уникальный идентификатор для графического элемента. Он будет использоваться чтобы обратиться к элементу из кода программы, например, для чтения значения.
Знак собачки ( @ ) необходим, когда идет обращение к любому ресурсу из XML. Он следует после указания типа ресурса ( id в текущем случае), слэш, потом имя ресурса ( edit_message ).
Знак плюса ( + ) необходим только в случае первого объявления ID ресурса. Когда происходит компиляция, SDK tools использует ID чтобы создать новый ресурс в файле gen/R.java . В дальнейшем при использовании идентификатора не нужно указывать знак плюса.
Свойство android:hint – это значение той строки, что будет отображаться в поле для ввода по умолчанию (когда оно пустое). Вместо того, чтобы задавать строку в файле разметки, используется запись «@string/edit_message», кот. говорит о том, что значение строки берется с файла ресурсов строк. “edit_message” – это ключ, по которому будет получено значение строки. Т.к. мы обращаемся к конкретному ресурсу (а не просто идентификатору) нет необходимости использовать знак плюса. В данный момент, из-за того, что строка в файле ресурсов еще не объявлена, компилятор выдает ошибку. Исправим ее, добавив соответствующий ресурс!
Добавление строки в файл ресурсов (strings.xml)
Все строки, что используются в интерфейсе должны быть объявлены в отдельном файле ресурсов. В дальнейшем такой подход значительно упростит изменение текстов приложения и добавления локализаций (других языков, кот будет поддерживать приложение).
По умолчанию, в проекте уже есть ресурсный файл со строками: res/values/strings.xml . Добавьте новую строку с именем «edit_message» и значением “Enter a message.” Так же Вы можете удалить строку “hello_world”. И можно сразу добавить строку, которую мы вскоре будем использовать для кнопки: “Send” с ключом «button_send» .
В результате файл strings.xml выглядит следующим образом (в режиме кода! переключатель слева внизу ;)):
android resources – strings.xml
Добавление кнопки на экран приложения
Далее добавим на форму кнопку, следующую за полем для ввода. Свойства height и width установлены в «wrap_content» , что говорит о том, что кнопка будет размером, необходимым для текста на кнопке. Атрибут android:id не установлен т.к. он не будет использоваться в коде приложения.
В результате получается следующий интерфейс:
Создаем простой android интерфейс
Размещение поля для ввода по всем ширине экрана
Оптимизируем его немного: растянем поле для ввода по ширине экрана. В данный момент ширина обоих графических элементов установлена в «wrap_content» . Для кнопки данное значение нормально, но для поля для ввода – не очень т.к. пользователь может ввести строку длиннее, чем поместиться в элемент (можете запустить сейчас приложение и попробовать ввести длинное значение 😉 ).
Итак, чтобы растянуть поле на неиспользуемую часть экрана в LinearLayout (в других контейнерах невозможно указать вес для графического элемента! Там используются другие свойства), необходимо указать атрибут weight ( android:layout_weight ).
Свойство weight это число, указывающее на то, сколько оставшегося пространства будет занимать один элемент на экране среди множества других. Т.е. фактически задаются пропорции занимаего пространства каждым графическим элементом. К примеру, есть 2 элемента, у одного вес равен 2, у второго – 1. на экране первый элемент будет занимать 2/3 всего пространства а второй – оставшиеся место.
По умолчанию вес каждого элемента равен нулю. Если для любого элемента указать значение веса больше нуля, этот элемент растянется по “свободному” пространству экрана. Мы так и сделаем, указав полю ввода вес равный одному. В результате форма должны быть представлена следующим кодом:
Код простого интерфейса android приложения
А сам интерфейс будет выглядит вот так:
Простой пользовательский интерфейс andoird приложения
Т.к. редактировался главная и единственная форма приложения, ее Вы и увидите при запуске приложения ;).
Источник
Android компонент с нуля
Задание:
Разработать кнопку-бегунок, которая работает следующим образом: прямоугольная область, слева находится блок со стрелкой, показывающий направление сдвига:
Пользователь зажимает стрелку и переводит её в право, по мере отвода, стрелка вытягивает цветные квадратики:
Как только пользователь отпускает блок, то вся линия сдвигается влево и скрывает все показанные блоки. После скрытия последнего блока должно генерироваться широковещательное сообщение что лента полностью спрятана.
Подготовка
Для создания нового компонента создадим новый проект. Далее создаём новый класс с именем «CustomButton», в качестве предка используем класс «View». Далее создадим конструктор класса и в итоге наш будущий компонент будет иметь вид:
Теперь приступаем к написанию кода класса. Прежде чем начать писать код, скиньте в папку /res/drawable-hdpi, изображение разноцветной ленты. В конструкторе нужно перво наперво инициализировать все объекты и сделать все предварительные настройки. Делаем следующее:
1 — Копируем ссылку на контекст основной активности;
2 — Загружаем подготовленную заготовку-полоску разделённую цветными квадратиками;
3 — Настраиваем компонент необходимый для рисования на поверхности/
Также объявим объекты в начале класса:
Теперь нам необходимо переопределить процедуру настройки размеров компонента — onMeasure. Я специально сделал постоянные размеры для компонента (300*50) чтобы не усложнять пример. Процедура будет иметь вид:
Теперь переопределим процедуру перерисовки компонента «onDraw». Данная процедура вызывается каждый раз когда необходимо перерисовать компонент. Процедура будет иметь вид:
Заготовка для нашего нового компонента готова, давайте поместим её на главную активность. Во первых разместим на главной поверхности новый LinearLayout, под именем «LinearLayout1». Далее в конструкторе класса создадим класс для новой кнопки, создадим класс реализации«LinearLayout1» и добавим кнопку на поверхность. Класс активности будет иметь вид:
Если вы запустите проект на выполнение то на устройстве (эмуляторе) вы увидите примерно следующее:
Функционал
Теперь приступим к реализации анимации и реакции на внешние события. Когда пользователь нажимает на компонент интерфейса, предком которого является View, то автоматически генерируются события, в частности можно отследить координаты нажатия на компонент, и этапы нажатия (нажали, подвигали, отжали). Поэтому требуется переопределить процедуру onTouchEvent, отвечающую за внешние события. Процедура имеет один аргумент «MotionEvent event», он содержит в себе все параметры текущего события. Извлекаем эти параметры следующим образом:
Приводим процедуру к следующему виду:
Каждую строчку расписывать не буду, определю только главную идею. Пользователь нажимает на стрелку компонента, это действие фиксируется в переменной _Last_Action = 1, также фиксируем что пользователь не вытянул ни одного кубика из ленты — _X = 0. Далее отслеживаем перемещение пальца по компоненту и вычисляем сколько кубиков должно показаться на экране, для этого вычисляем _X. Принудительная перерисовка происходит с помощью команды invalidate(). В конце фиксируем отжатие пальца и запускаем таймер, если пользователь вытянул хотя бы один кубик. Таймер необходим чтобы возвращать полоску в исходное состояние не резко, а постепенно.
Теперь реализуем сам таймер, который будет возвращать полоску в исходное положение. Код таймера будет иметь вид:
В данной процедуре происходит цикличное выполнение операции уменьшения значения переменной _X на 1, тем самым показывая какой сектор должен быть показан на компоненте. Так как из дополнительных потоков нельзя влиять на внешний вид компонента, приходится посылать сообщения перерисовки через Handle. Поэтому в конструктор класса добавим реализацию перехвата сообщений для Handle и перерисовку внешнего вида виджета:
Теперь осталось изменить процедуру перерисовки виджета, а именно строку позиционирования ленты на поверхности (ширина одного квадратика на ленте, равна 60 pix, а общая длинна составляет 300 pix):
Добавим все переменные в начало реализации класса.
В итоге класс будет меть вид:
Внешние сообщения
Сильно мудрить не будем, реализуем событие что «лента спрятана» с помощью широковещательных сообщений. В реализации таймера добавим строки отправки сообщений:
В переменной «Name» хранится имя нашего компонента. Для сохранения имени, создадим дополнительную процедуру:
Добавим в блок объявления объектов имя компонента — public String Name.
Теперь в конструкторе нашей активности добавим перехватчик широковещательных сообщений:
После строки создания объекта кнопки, добавим строку передачи нового имени в объект:
Источник