Как добавить пользовательские группы просмотра в Anko DSL?

Anko docs сообщает нам, как добавлять пользовательские представления в DSL. Но если мое пользовательское представление представляет собой группу представлений, возникают проблемы.

class MyFrameLayout(context: Context) : FrameLayout(context) fun ViewManager.myFrameLayout(init: MyFrameLayout.() -> Unit = {}) = ankoView({ MyFrameLayout(it) }, init) class MyUI : AnkoComponent<Fragment> { override fun createView(ui: AnkoContext<Fragment>) = with(ui) { myFrameLayout { textView("hello").lparams { // error: Unresolved reference: lparams bottomMargin = dip(40) } } } } 

но если я myFrameLayout вызов frameLayout на frameLayout он работает нормально. Итак, каков способ использования групп представлений с Anko DSL?

На самом деле вам просто нужно расширить anko и объявить свой заказ, а затем использовать его в DSL в обычном режиме:

 public inline fun ViewManager.customView() = customView {} public inline fun ViewManager.customView(init: CustomView.() -> Unit) = ankoView({ CustomView(it) }, init) 

Затем используйте его в DSL нормально

 frameLayout { customView() } 

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

Если вы перейдете к любой из деклараций lparams от вашего кода, вы увидите, что внутри созданного Anko DSL-кода lparams является функцией расширения для T: View которая выглядит так:

 fun <T: View> T.lparams( width: Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT, height: Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT, init: android.widget.FrameLayout.LayoutParams.() -> Unit = defaultInit ): T { val layoutParams = android.widget.FrameLayout.LayoutParams(width, height) layoutParams.init() this@lparams.layoutParams = layoutParams return this } 

(и больше перегрузок для разных конструкторов LayoutParams )

Он объявляется внутри класса, поэтому он видим только в функциях с приемником этого класса, см. Другой вопрос об этом методе программирования DSL.


Чтобы иметь возможность использовать lparams для вашей пользовательской ViewGroup в Anko DSL, вы должны объявить аналогичную функцию или функции внутри своего пользовательского кода просмотра, что создаст соответствующие LayoutParams для вашего класса.

Если вы хотите также скрыть функцию lparams из-за пределов DSL, вы можете сделать подкласс MyFrameLayout и использовать его только в DSL-коде, работая с MyFrameLayout самостоятельно в другом месте.

После этого вы можете вызвать lparams на любом View внутри лямбда, которое вы передаете как init: MyFrameLayout.() -> Unit to fun ViewManager.myFrameLayout .

Если мы посмотрим на источники Anko, мы увидим, что frameLayout возвращает экземпляр класса _FrameLayout , где определены эти функции lparams . По моему lparams это необходимо, поэтому эти функции lparams доступны только в коде построения макета.

В файле Layouts.kt Anko есть следующие классы _<ViewGroup> для каждой поддерживаемой группы ViewGroup .

Таким образом, простой способ поддержки настраиваемой группы просмотра состоит в создании класса _<ViewGroup> с lparams методов lparams . Проблема в том, что этот класс _<ViewGroup> часто содержит гораздо больше кода, чем моя <ViewGroup> !

И если я хочу создать много настраиваемых групп просмотра, добавление поддержки Anko для них становится большой болью при таком подходе. Предположим, у меня есть MyFrameLayout1 , MyFrameLayout2 , MyFrameLayout3 . Они в основном являются FrameLayout , поэтому я хочу, чтобы с ними использовались те же параметры макета. Но мне нужно создать _FrameLayout1 , _FrameLayout2 , _FrameLaoyt3 которые просто копируют / _FrameLayout Anko.

Поэтому я немного улучшил этот подход. Я создаю interface _FrameLayout :

 interface _FrameLayout { // copy/paste from Anko's _FrameLayout } 

и теперь для поддержки любого пользовательского подкласса FrameLayout мне просто нужно:

 class _MyFrameLayout(ctx: Context) : MyFrameLayout(ctx), _FrameLayout fun ViewManager.myFrameLayout(init: _MyFrameLayout.() -> Unit = {})= ankoView({ _MyFrameLayout(it) }, init) 

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

Intereting Posts
Как загрузить фрагмент в BottomNavigationView в зависимости от выбранного элемента? Ссылка на значения и методы вызова в типах общих типов Модуль библиотеки Android не компилируется при использовании классов из чистого модуля Kotlin Разумные ситуации для использования `Let` Котлина передача var-args в MessageFormat.format в kotlin IOException: AsyncTask Image Загрузить Kotlin Android (дескриптор Bad File) Есть ли простой способ получить объект by _id в Котлине? Импорт статических методов в Котлин Модернизация с kotlin, неспособная создать @Body Firebase: повторная проверка подлинности Google Auth ERROR (недопустимый id_token в IdP) Android: невозможно обновить Listview с помощью CustomAdapter Ошибка исключения исключения в асинхронном вызове Anko (Kotlin) Смарт-литье и сравнение внутри Когда выражение после «есть» проверка типа Как показать только день и месяц в диалоговом окне выбора даты в Kotlin (Android)? Kotlin: Как запустить методы обслуживания в контексте класса транзакций?