Возможно ли повторно использовать макет в Kotlin Anko

#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.