Программное добавление и удаление виджета
Обычно мы размещаем виджеты через XML. Но можно это делать и программно. Такой подход используется при динамическом размещении, когда неизвестно, сколько элементов должно быть на экране.
Добавляем виджет
Допустим у нас есть простейшая разметка.
Пустая компоновка LinearLayout с идентификатором mainlayout не содержит вложенных виджетов. Через метод addView(view) класса LinearLayout мы можем добавить нужный нам элемент.
Удаляем виджет
Существует и обратный метод для удаления вида — removeView(), а также метод removeAllViews(), удаляющий все дочерние элементы родителя. Рассмотрим следующий пример. Создадим разметку, где компонент LinearLayout с идентификатором master будет родителем для будущих элементов, которые мы будем добавлять или удалять:
activity_main.xml
Создадим пару дополнительных макетов, которые будет дочерними элементами для FrameLayout. Мы будем управлять ими программно.
layer1.xml
layer2.xml
Напишем код, который будет добавлять или удалять компоновки через флажки.
Обратите внимание, что добавление идёт в том порядке, как мы отмечаем флажки. Если мы отметим флажком второй CheckBox, то сначала на экране появится блок с компоновкой layer2.xml, а уже ниже компоновка layer1.xml. На скриншоте представлен этот вариант.
Получить доступ к дочерним элементам можно через методы getChildCount() и getChildAt().
Источник
Полный список
В этом уроке мы:
— добавляем компоненты на экран прямо из приложения
На прошлом уроке мы создавали компоненты в методе Activity.onCreate, т.е. при создании приложения. На этом уроке будем создавать уже в работающем приложении. Создавать будем Button-ы, т.к. они наглядней всего отображаются. Будем указывать текст, который будет отображен на кнопке и выравнивание: слева, по центру или справа. Также предусмотрим возможность удаления созданных элементов.
Project name: P0171_DynamicLayout2
Build Target: Android 2.3.3
Application name: DynamicLayout2
Package name: ru.startandroid.develop.dynamiclayout2
Create Activity: MainActivity
Создадим экран, который поможет нам создавать View-компоненты. Открываем main.xml и пишем там следующее:
Рассмотрим подробно экран.
rgGravity – это RadioGroup, с тремя RadioButton (rbLeft, rbCenter, rbRight). Этот компонент мы используем для выбора выравнивания создаваемого компонента
etName – текстовое поле, здесь будем указывать текст, который будет отображаться на созданном компоненте
btnCreate – кнопка, запускающая процесс создания.
btnClear – кнопка, стирающая все, что создали
llMain – вертикальный LinearLayout, в котором будут создаваться компоненты
Экран готов, давайте кодить реализацию. Открываем MainActivity.java. Начнем с того, что опишем и найдем все необходимые нам компоненты. Кстати, у нас есть пара кнопок, которые мы будем использовать, значит им нужен обработчик. В качестве обработчика назначим Activity (т.е. необходимо дописать: implements OnClickListener) и создадим пустой пока метод обработки onClick:
Я также создал переменную wrapContent и буду хранить в ней значение LinearLayout.LayoutParams.WRAP_CONTENT. Делаю это только для снижения громоздкости кода.
Теперь опишем процесс создания Button-компонента заполнив метод onClick:
Разберем написанное. Для начала мы проверяем, что была нажата кнопка btnCreate – т.е. кнопка создания. Затем создаем LayoutParams с высотой и шириной по содержанию. Здесь я использовал переменную, про которую писал выше – wrapContent. Иначе получилось бы довольно громоздко.
Далее создаем переменную btnGravity, в которую по умолчанию запишем значение выравнивания LEFT. Для определения, какой RadioButton выделен в данный момент, используем метод getCheckedRadioButtonId – он для RadioGroup возвращает ID «чекнутого» RadioButton-а. Мы его сравниваем с нашими тремя ID и заносим соответствующее значение в переменную btnGravity. Скидываем это значение в gravity у LayoutParams.
Далее создаем кнопку и присваиваем ей текст из etName. Обратите внимание, что недостаточно написать getText, т.к. это не даст текста. Необходимо еще вызвать метод toString. Ну и в конце добавляем созданный Button в наш LinearLayout.
Сохраним все и запустим приложение. Добавим несколько кнопок.
Кнопки должны появляться с указанным выравниванием и текстом.
Когда вводите текст, снизу появляется клавиатура и закрывает обзор. Чтобы она исчезла, надо нажать кнопку Back (Назад) на эмуляторе или ESC на обычной клавиатуре. Если клавиатура появляется японская с иероглифами, вызовите контекстное меню для поля ввода (долгое нажатие левой кнопкой мыши), нажмите Input method и выберите из списка Android Keyboard.
Осталось нереализованной кнопка Clear, которая призвана удалять все созданное. Для этого нам необходимо дополнить метод onClick, добавим в switch ( v.getId ()) еще один case:
Метод removeAllViews удаляет все дочерние View-компоненты с нашего LinearLayout. С помощью Toast выводим на экран сообщение об успехе. Сохраним, запустим и проверим. Добавляем несколько кнопок, жмем кнопку Clear и наблюдаем результат:
В итоге у нас получилось очень даже динамическое приложение, которое умеет менять само себя.
На форуме задают вопрос: как потом получить доступ к этим созданным компонентам. Тут есть пара простых вариантов.
1) При создании вы можете сами присваивать компонентам ID. Это делается методом setId . И потом по этим ID просто вызываете findViewById.
2) Вы можете сохранять созданные компоненты в свой массив или список. Либо можете воспользоваться методом getChildAt. Вызов этого метода для llMain позволит получить его дочерние компоненты по индексу. Получить кол-во дочерних элементов позволит метод getChildCount.
Полный код урока:
На следующем уроке:
— изменяем layout-параметры для уже существующих компонентов экрана
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Введение
Это будет серия постов на тему создания пользовательского view компонента для Android. Я покажу как нарисовать содержимое компонента, как работают layouting и measuring, как реализовать view groups и как анимировать содержимое компонента. В этом посте я объясню, как расширить стандартный view, как его использовать и как создать свои собственные xml атрибуты.
Специфические задачи, специфические view
Стандартные view компоненты, которые предоставляет Android, могут использоваться для многих задач и ситуаций. Тем не менее, в наших приложениях наибольшую часть кода часто занимает конфигурация этих view для специфических задач. Этот конфигурационный код часто находится в activity вашего приложения, поэтому их сложно содержать в чистоте. А при наличии большого количества различного кода возникают сложности и с его разделением в отдельные классы.
Предположим, вы работаете над приложением, которое содержит статистику тренировок пользователя. Например, общая дистанция, общее время и так далее, в зависимости от типа тренинга. Для того чтобы отображать данные в удобном виде, вы решили их адаптировать, основываясь на их продолжительности. Если это 2378 секунд, вы хотите отображать это время как «40 минут», а если это 18550 секунд, то лучше было бы отображать на дисплей «5 часов 9 минут».
Создание custom view
Один из способов решения этой задачи — создать специализированный view, который будет должным образом обрабатывать ваш текст. Давайте начнем с создания нашего собственного класса DurationTextView, который будет расширять класс TextView.
TextView, как и все view классы, имеет три различных конструктора: первый просто принимает контекст (Context), второй принимает контекст и набор атрибутов (AttributeSet), а третий еще дополнительно принимает стиль «по умолчанию». В большинстве случаев вам достаточно реализовать второй конструктор, который показан выше.
Теперь мы создали view и чтобы его использовать, мы добавим его в файл разметки:
Обратите внимание, вам необходимо полностью указывать имя вашего класса, который вы реализовали.
В данный момент этот класс практически идентичен стандартному TextView, поэтому давайте добавим ему некоторую функциональность.
Добавление логики отображения
Поскольку этот view будет отображать длительность, давайте добавим метод setDuration().
Что делает этот метод? Он получает значение длительности, переводит его в текстовую строку в определенном формате, используя некую логику, а затем выводит с помощью метода setText(). В данном случае логика заключается в переводе секунд в минуты и дальнейшем разделении на часы и минуты. Также в методе присутствует логика для корректного отображения одной минуты: «1 minute» вместо «1 minute(s)».
В конце метода отформатированное время преобразуется в строку с помощью шаблона.
private static final String TEMPLATE = «Duration: %s«;
Шаблон начинается со слова «Duration», а далее жирными буквами отображается отформатированная строка.
Для простоты я использовал в коде строковые литералы. В нормальном коде, эти строковые литералы лучше перенести в strings.xml, это позволяет в дальнейшем локализовать их.
Использование полученного view
Попробуем использовать наш view. В xml файл разметки добавим 5 custom View.
А в activity в методе onCreate() после метода setContentView() добавим следующие строки.
Соберем проект и загрузим его в эмулятор. Полученный результат можно видеть на изображении ниже.
Добавление xml атрибутов
Если бы мы могли задавать шаблон, то созданный нами компонент был бы более универсальным. По идее можно добавить метод, который позволит нам устанавливать шаблон, однако это не так просто. Если подумать, длительности нам нужно устанавливать динамически, а шаблон скорее всего будет все время одинаковым. Поэтому вместо метода, давайте добавим нашему custom view новые xml атрибуты.
В первую очередь нужно создать в папке values файл attrs.xml, где мы сможем определить атрибуты. Для этого view мы добавим один атрибут — template типа string. Выглядеть это будет так:
Мы записали тег declare-styleable и задали имя TemplateTextView. Имя может быть произвольным, но обычно задают имя, совпадающее с именем view. В данном случае я не задаю имя DurationTextView, потому что планирую использовать template атрибут еще в другом view.
Далее мы определили новый атрибут, установив ему имя template и формат string. Помимо string существует множество других форматов, например, Color, Integer, Boolean, Reference и так далее.
Использовать новый атрибут в layout xml можно так.
Обратите внимание, в корневом элементе мы добавляем такую строчку.
xmlns:app= «http://schemas.android.com/apk/res-auto»
Это позволяет нам использовать атрибуты, которые определены в файле attrs.xml, в нашем layout. В данном случае мы задали префикс «app», хотя он может быть произвольным.
Для того чтобы использовать новый атрибут, нужно получить его значение в нашем custom view. Сначала заменяем приватную статическую константу «TEMPLATE» переменной «template». Затем добавляем в наш конструктор следующий код.
В первой строке мы получаем набор атрибутов, который содержит все атрибуты, существующие в xml файле. Метод obtainStyledAttributes() делает две основные вещи. Во-первых, он фильтрует все атрибуты из attrs с помощью контекста, применяет стили и resolves reference to values. Во-вторых, он возвращает только те атрибуты, которые вы определили. Они задаются вторым аргументом, который представляет собой массив ссылок на требуемые атрибуты. В данном случае в R.styleable.TemplateTextView у нас только один атрибут R.attr.template, который мы создали в файле attrs.xml.
Далее мы используем массив attributes, чтобы получить значение атрибута. Если значение шаблона не было определено или не содержит «%s», мы устанавливаем template = «%s». И в заключении нужно не забыть освободить ресурсы с помощью функции recycle().
После некоторых изменений в layout, приложение будет выглядеть так:
Здесь я установил шаблон для первых трех custom view
Большая часть view в Android имеет методы, которые позволяют устанавливать значения XML атрибутов в коде. Возможно вам тоже понадобиться добавить какой-нибудь метод, это зависит от того, как вы будете использовать view.
В следующей части мы посмотрим как нарисовать свой собственное содержимое view компонента и сделаем view для отображения графика.
Исходники к статье можно скачать c GitHub.
По материалам сайта Jayway
Вольный перевод — Pavel Bobkov.
Источник
Полный список
В этом уроке мы:
— рисуем экран программно, а не через layout-файл
До этого мы создавали экран с помощью layout-файлов. Но то же самое мы можем делать и программно.
Project name: P0161_DynamicLayout
Build Target: Android 2.3.3
Application name: DynamicLayout
Package name: ru.startandroid.develop.dinamiclayout
Create Activity: MainActivity
Открываем MainActivity.java и обратим внимание на строку:
Напомню, что в этой строке мы указываем, что Activity в качестве экрана будет использовать layout-файл main.xml. Есть другая реализация этого метода, которая на вход принимает не layout-файл, а View-элемент и делает его корневым. В layout-файлах корневой элемент обычно LinearLayout, мы тоже используем его.
Обновим импорт – CTRL+SHIFT+O. Eclipse предложит нам выбрать, какой именно LayoutParams мы будем использовать. Тут надо остановиться подробнее. Вспомним теорию про экраны. Экран состоит из ViewGroup и вложенных в них View.
Известные нам примеры ViewGroup – это LinearLayout, TableLayout, RelativeLayout и т.д. Каждая из этих ViewGroup имеет вложенный класс LayoutParams. Базовым для этих LayoutParams является ViewGroup.LayoutParams.
ViewGroup.LayoutParams имеет всего два атрибута: height и width. Его подкласс ViewGroup.MarginLayoutParams наследует два этих атрибута и имеет свои четыре: bottomMargin, leftMargin, rightMargin, topMargin. Класс LinearLayout.LayoutParams в свою очередь является подклассом ViewGroup.MarginLayoutParams, наследует от него уже 6 аттрибутов и добавляет свои два: gravity и weight.
Т.е. объект LinearLayout имеет вложенный класс LinearLayout.LayoutParams с layout-аттрибутами. И эти аттрибуты распространяются на все дочерние View и ViewGroup.
Т.е. View, находящаяся в LinearLayout имеет один набор layout-параметров:
а View из RelativeLayout – другой:
Есть и общие элементы, т.к. родители у этих ViewGroup одни.
Вернемся в Eclipse, он ждет нашего выбора. Используем базовый класс ViewGroup.LayoutParams
Давайте разберем код. Мы создаем LinearLayout и ставим вертикальную ориентацию. Далее создаем LayoutParams. Конструктор на вход принимает два параметра: width и height. Мы оба ставим MATCH_PARENT. Далее вызывается метод setContentView. На вход ему подается LinearLayout и LayoutParams. Это означает, что корневым элементом Activity будет LinearLayout с layout-свойствами из LayoutParams.
Если мы сейчас запустим приложение, то ничего не увидим, т.к. LinearLayout – прозрачен. Давайте добавлять в LinearLayout View-компоненты.
Мы снова создаем объект LayoutParams с атрибутами width = wrap_content и height = wrap_content. Теперь если мы присвоим этот объект какому-либо View, то это View будет иметь ширину и высоту по содержимому.
Далее мы создаем TextView, настраиваем его текст, присваиваем ему выше созданный LayoutParams и добавляем в LinearLayout с помощью метода addView (View child).
С Button аналогично – создаем, правим текст, а затем используем другую реализацию метода addView (View child, ViewGroup.LayoutParams params), которая одновременно добавляет Button в LinearLayout и присваивает для Button указанный LayoutParams. Результат будет тот же, что и с TextView, но вместо двух строк кода получилась одна.
Обратите внимание, что для двух объектов View я использовал один объект LayoutParams — lpView. Оба View-объекта считают параметры из LayoutParams и используют их.
Сохраним и запустим приложение. Видим, что компоненты на экране появились. И видно, что их высота и ширина определена по содержимому (wrap_content).
Объект lpView имеет базовый тип android.view.ViewGroup.LayoutParams. А значит позволит настроить только ширину и высоту. Но для View в LinearLayout доступны, например, отступ слева или выравнивание по правому краю. И если мы хотим их задействовать, значит надо использовать LinearLayout.LayoutParams:
Смотрим код. Мы создаем объект типа LinearLayout.LayoutParams с помощью такого же конструктора, как и для обычного LayoutParams, указывая width и height. Затем мы указываем отступ слева = 50. Отступ здесь указывается в пикселах. Далее схема та же: создаем объект, настраиваем текст и добавляем его в LinearLayout c присвоением LayoutParams.
Аналогично добавим компонент с выравниванием:
Сохраним и запустим. Button1 имеет отступ 50px. А Button2 выравнена по правому краю:
Вероятно, эта тема будет не очень понятна с первого раза. Поэтому на следующих двух уроках мы закрепим эти знания и попрактикуемся в добавлении элементов на экран и их настройке.
Полный код урока:
На следующем уроке:
— добавляем компоненты на экран во время работы приложения
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник