четверг, 26 декабря 2013 г.

Компоненты, сделанные на заказ

Андроид предоставляет сложную и мощную модель компонентов для построения  пользовательских интерфейсов, основанную на классах View и ViewGroup. Начнём с того, что платформа включает в себя разнообразные готовые подклассы элементов View и ViewGroup, называемые элементами и контейнерами. Их вы можете использовать для построения своего интерфейса. 
Неполный список полезных элементов включает в себя ButtonTextView,EditTextListViewCheckBoxRadioButtonGallerySpinner,  и много элементов особого назначения AutoCompleteTextView,ImageSwitcher, и TextSwitcher.
Среди контейнеров часто используемые LinearLayoutFrameLayoutRelativeLayout и другие. 
Если не один из готовых элементов или контейнеров не отвечает вашим запросам, то вы можете создать свой собственный подкласс View. Если вам необходимо внести небольшие корректировки в существующий элемент или контейнер, то вы можете просто переопределить методы этого подкласса.
Создание своего собственного подкласса View даёт вам контроль над внешним видом и функциями элемента. Вот некоторые примеры того, что Вы могли бы сделать со своим собственным элементов View
  • Вы сможете создавать полностью необычно отрисованный элемент. Например "регулятор громкости", ручка визуализируется с помощью 2D графики и напоминает аналоговый электронный переключатель громкости.
  • Вы могли бы объединить группу элементов в один. Возможно, сделать что-то вроде ComboVox (сочитание всплывающего списка и поля для ввода текста). Или двухпанельный переключатель (левая и правая понель со списком, где в каждом списке можно выбрать элемент). Ну и так далее.
  • Вы можете переопределить метод элемента EditText, отвечающий за отрисовку элемента на экране.
  • Вы можете ловить событи, например нажатие на клавишу, и обрабатывать их в своё методе.
Далее будет объяснено, как создавать собственные элементы и использовать их в вашем приложении.

Основной подход

Вот краткий обзор того, что вам нужно знать, чтобы начать работу в создании собственных элементов:
  1. Расширить существующий класс или подкласс вашим классом.
  2. Переопределить некоторые методы суперкласса. МЕтоды для переопределения начинаются с 'on'. Например, OnDraw (), onMeasure (), и OnKeyDown (). Это похоже на событи в Activity  или ListActivity, которые вы переопределяете для жизненного цикла и других функциональных моментов.
  3. Испольуйте ваш новый расширенный класс.  После завершения ваш новый расширенный класс может использоваться вместо View, на котором он основан.
Совет: расширенные классы могут быть определены как внутренние классы внутри активити, которая их использует. Это полезно, так как активити управляет доступом к ним, но не является необходимой (возможно вы хотите создать новый View для более широкого использования в вашем приложении).

Полностью настроенный элемент

Полностью настроенные элементы могут быть исопльзованы для создания графических компонентов, которые будут выглядеть так, как вы захотите. Возможно, это графический измеритель напряжения, который выглядит как старый аналоговый датчик. Или текст песни, где на каждое слово прыгает мячик, когда приходит время спеть его в короке. В любом случае, вы хотите что-то такое, что обычные элементы сделать не смогут, независимо от того, как вы их объедините.
К счастью, вы можете сохдать такие элементы, которые будут делать и выглядеть так, как вы того захотите, ограниченный только вашим воображением, экраном и мощностью процессора. 
Чтобы создать полностью новый компонент необходимо:

  1. Создать новый супер элемент, расширив класс View.
  2. Вы можете объявить конструктор, который будет принимать атрибуты и параметры из  XML, также вы можете использовать собственные атрибуты и параметры.
  3. Возможно вы хотите создать свои собственные обработчики событий, свойства доступа и модификаторы, а также более сложное поведение для нового класса.
  4. Вы почти наверняка хотите переопределить метод onMeasure () и, вероятно, также вам необходимо переопределить метод OnDraw (), если хотите, чтобы элемент что-то показывал. В то время как по умолчанию OnDraw () ничего не делает, а  onMeasure установлен размер 100х100, который вероятно не является таким, каким вы хотите.  Другие методы тоже необходимо переопределить в соответствии с требованиями.

Расширение методов onDraw() и onMeasure()

Метод onDraw()  предоставляет вам холст (Canvas), на котором можно реализовать всё, что угодно: 2D-графику,  другие стандартные или пользовательские элементы, стилизованный текст, или что-нибудь ещё, что придёт вам в голову.
Примечание: это не относится к 3D-графике. Если вы хотите использовать 3D-графику, необходимо расширить SurfaceView вместо View, и сделать это в отдельном потоке.
С onMeasure () немного сложнее. onMeasure является важной частью договора рендеринга между компонентом и его контейнером. onMeasure () должен быть изменен, чтобы эффективно и точно сообщить результаты измерения содержащихся в нем частей. Это составляет небольшие сложности в виде требований границ от родителя (которые передаются методу onMeasure()) и требований вызвать метод  setMeasuredDimension с измеренной высотой и шириной, как только они были рассчитаны. Если вам неудастся вызвать этот метод в переопределённом   onMeasure(), будет выброшено исключение во время измерения.
На высоком уровне, реализации onMeasure () выглядит примерно так:
  1. Вызывается переопределённый метод onMeasure с параметрами измерения ширины и высоты (widthMeasureSpec и heightMeasureSpec параметры, оба целые коды, представляющие размеры), которые   должны рассматриваться как требования к ограничениям на ширину и высоту, которые вы должны предоставить.
  2. Метод onMeasure() вашего компонента должен рассчитывать ширину и высоту,  в которую необходимо преобразовать ваш компонент. Следует не выходить за рамки параметров,  хотя можно расширить их (в данном случае, родитель может выбрать, что делать, включая отсечения, прокрутку, выбрасывание исключений, или попросить метод onMeasure () повторить попытку, возможно, с различными параметрами в качестве размеров).
  3. После того, получили ширину и высоту, необходимо вызвать метод setMeasuredDimension(int width, int height), передав в параметрах полученную ширину и высоту. Если этого не сделать, произойдёт выброс исключительной ситуации.

Составные элементы управления

Если вы не хотите полностью с нуля создавать новый компонент,  а взамен тому ищите возможность совместить повторно используемый элемент, содержащий группу существующих элементов управления, тогда создайте Compound Component (составной элемент), который будет отвечать всем этим требованиям. В двух словах, этот элемент объединяет несолько более атомных элементов в логическую группу элементов, которые можно использовать как один элемент. Например,  ComboBox можно рассматривать как сочетание в одной строке EditText и прилегающей кнопки с прикрепленным PopupList. Если нажать на кнопку и выберите что-то из списка, заполняется поле EditText, но пользователь может также  ввести что-то сам непосредственно в EditText если он этого захочет. 
В андроид есть два других элемента, с помощью которых легко сделать тоже самое: Spinner и AutoCompleteTextView, но несмотря на это, концепция Combo Box делает пример простым для понимания.

Для создания составного компонента необходимо:
  1. Начать нужно с создания класса расширяющего Layout.  Возможно, что в случае поля со списком, мы можем использовать LinearLayout с горизонтальной ориентацией. Помните, что другие макеты могут быть вложены, поэтому наш составной компонент может быть сколь угодно сложным и структурированным. Обратите внимание, что так же, как с помощью Activity, вы можете использовать любое  подход к созданию составного компоненты, описание с помощью XML или вы можете вкладывать элементы программно из вашего кода.
  2. В конструктор нового класса передать параметры, которые ожидает суперкласс в первую очередь. Затем вы можете настроить другие элементы, используемые внутри вашего нового компонента. Это то место, когда надо было бы создать EditText и PopupList. Обратите внимание, что вы также можете ввести свои собственные атрибуты и параметры в XML, который может быть выдвинут и используемой конструкторе.
  3. Вы также можете создать слушателей для событий, что ваши "внутренние" элементы могут генерировать, 
  4. Вы также можете создавать свои собственные свойства  методов доступа и модификаторов, например, позволяют значению EditText быть установлены изначально в компоненте и запроса для его содержания по мере необходимости.
  5. В случае расширения Layout вам не нужно переопределить OnDraw () и onMeasure () методы, так как макет будет иметь поведение по умолчанию, что, скорее всего, работать просто отлично. Тем не менее, вы все равно можете переопределить их, если вам нужно.
  6. Вы можете переопределить другие методы 'on'.
Подводя итог, использование макета в качестве основы для создания пользовательского элемента управления имеет ряд преимуществ, в том числе: 
  • Вы можете описать макет, используя описательный XML файл так же, как для экрана деятельности, или вы можете создавать представления программно и вкладывать их в макет из кода.
  • OnDraw () и onMeasure () методы (плюс большинство других 'on' ... методов), скорее всего, иметь соответствующую поведение таким образом, вы не должны переопределить их.
  • В конце концов, вы можете очень быстро построить сколь угодно сложные составные элементы и повторно использовать их как если бы они были одним компонентом.