#android #android-layout #kotlin #anko
#Android #android-layout #kotlin #anko
Вопрос:
Я читал, что наибольшим преимуществом использования Anko является его повторное использование. Но я не смог найти его точный пример.
В настоящее время в новой системе компоновки Android схема котла выглядит следующим образом:
DrawerLayout (with some setup)
CoordinatorLayout (with some setup)
AppBarLayout (with some setup)
ToolBar
<The Main Content>
NavigationView (with header inflated)
Из приведенной выше структуры макета только <The Main Content>
varry . И
во многих случаях эти церемониальные настройки дублируются почти в каждом действии.
Итак, здесь, с Anko, я думаю, есть ли многоразовое решение этой проблемы. Я не ожидаю, что он будет использоваться повторно для макета общего назначения, но, по крайней мере, я могу минимизировать церемониальный код в проекте. Может быть, мне нужно что-то вроде:
class MainUI: AnkoComponent<MainActivity> {
override fun createView(ui: AnkoContext<MainActivity>): View{
return with(ui) {
myCustomRootLayout {
//here is what <The Main Content> will be
}
}
}
}
Из приведенного выше кода я ожидаю myCustomRootLayout
, что он выполнит всю церемониальную настройку для корневого макета, такого как (DrawerLayout, CoordinatorLayout и т. Д. И т. Д.).
Возможно ли это?
РЕДАКТИРОВАТЬ Итак, я думаю, что мой вопрос: как создать пользовательский компонент, в котором может размещаться другой компонент
Ответ №1:
Один из способов повторного использования кода — просто извлечь myCustomRootLayout
его в метод расширения следующим образом:
class MainUI: AnkoComponent<MainActivity> {
override fun createView(ui: AnkoContext<MainActivity>): View {
return with(ui) {
myCustomRootLayout {
recyclerView()
}
}
}
}
fun <T> AnkoContext<T>.myCustomRootLayout(customize: AnkoContext<T>.() -> Unit = {}): View {
return relativeLayout {
button("Hello")
textView("myFriend")
customize()
}
}
Однако, как указано в документации:
Хотя вы можете использовать DSL напрямую (в
onCreate()
другом месте или везде), не создавая никаких дополнительных классов, часто бывает удобно иметь пользовательский интерфейс в отдельном классе. Если вы используете предоставленный интерфейс AnkoComponent, вы также бесплатно получаете функцию предварительного просмотра макета DSL.
Кажется, было бы неплохо извлечь повторно используемую часть в отдельные AnkoComponent
:
class MainUI : AnkoComponent<MainActivity> {
override fun createView(ui: AnkoContext<MainActivity>): View {
return with(ui) {
MyCustomRootLayout<MainActivity>({
recyclerView()
}).createView(ui)
}
}
}
class MyCustomRootLayout<T : Context>(val customize: AnkoContext<T>.() -> Unit = {}) : AnkoComponent<T> {
override fun createView(ui: AnkoContext<T>) = with(ui) {
relativeLayout {
button("Hello")
textView("myFriend")
customize()
}
}
}
Комментарии:
1. спасибо за ответ. да, я понимаю об этом. но можно найти пример того, как создать пользовательский компонент, который является контейнером другого компонента. Смотрите Мой код,
myCustomRootLayout
должен содержатьDrawerLayout, CoordinatorLayout, AppBarLayout
etc и т.д., но также должен содержать другой компонент<The Main Content>
. Поэтому в будущем я могу использовать их следующим образом:myCustomRootLayout { recyclerView() }
(добавив в него представление recycler)2. @ktutnik и
myCustomRootLayout
метод расширения, иMyCustomRootLayout
класс принимают делегат, который вызывается после настройки элементов components. Этот делегат можно использовать для добавления пользовательских дочерних элементов, т.е.recyclerView()
3. Я беспокоюсь о положении вставленного дочернего элемента. Требуется ли какое-то усилие, чтобы поместить дочерние элементы в качестве дочерних элементов CoordinatorLayout в корневом представлении?
4. @ktutnik У меня почти такая же проблема. Вы нашли способ вставить пользовательский вид в качестве дочернего элемента в другой макет?
5. @SuhairZain: извините, все еще не могу найти способ.
Ответ №2:
Я действительно нашел способ сделать это, мне потребовалось некоторое время, чтобы понять это.
У меня здесь очень простой тестовый макет, содержимое добавляется в RelativeLayout
.
Ключевым моментом здесь является добавление вашего пользовательского макета в делегированный AnkoContext
, который делегирует непосредственному родителю ( RelativeLayout
в моем случае).
abstract class BaseAnkoComponent<T> : AnkoComponent<T> {
companion object {
val TOOLBAR_ID = View.generateViewId()
val COLLAPSING_ID = View.generateViewId()
val COORDINATOR_ID = View.generateViewId()
val APPBAR_ID = View.generateViewId()
val CONTENT_ID = View.generateViewId()
}
abstract fun <T> AnkoContext<T>.content(ui: AnkoContext<T>): View?
override fun createView(ui: AnkoContext<T>) = with(ui) {
coordinatorLayout {
id = COORDINATOR_ID
lparams(matchParent, matchParent)
appBarLayout(R.style.AppTheme_AppBarOverlay) {
id = APPBAR_ID
lparams(matchParent, wrapContent)
fitsSystemWindows = true
collapsingToolbarLayout {
id = COLLAPSING_ID
val collapsingToolbarLayoutParams = AppBarLayout.LayoutParams(matchParent, matchParent)
collapsingToolbarLayoutParams.scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL or AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS
layoutParams = collapsingToolbarLayoutParams
isTitleEnabled = false
toolbar {
id = TOOLBAR_ID
val toolbarLayoutParams = CollapsingToolbarLayout.LayoutParams(matchParent, dimenAttr(R.attr.actionBarSize))
toolbarLayoutParams.collapseMode = CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PIN
layoutParams = toolbarLayoutParams
minimumHeight = dimenAttr(R.attr.actionBarSize)
background = ColorDrawable(colorAttr(R.attr.colorPrimary))
popupTheme = R.style.AppTheme_PopupOverlay
}
}
}
with(AnkoContext.createDelegate(relativeLayout {
id = CONTENT_ID
val relativeLayoutParams = CoordinatorLayout.LayoutParams(matchParent, matchParent)
relativeLayoutParams.behavior = AppBarLayout.ScrollingViewBehavior()
layoutParams = relativeLayoutParams
})) {
content(ui)
}
}
}
}
А затем вы можете расширять BaseAnkoComponent
и создавать свой контент таким же образом с помощью Anko DSL.
class FooActivityUi : BaseAnkoComponent<FooActivity>() {
override fun <T> AnkoContext<T>.content(): View? {
return verticalLayout {
lparams(width = matchParent, height = matchParent)
button("Hello")
textView("myFriend")
}
}
}
Я уверен, что есть лучший способ сделать это, но я его не нашел. Что-то новенькое для Kotlin и Anko.