【问题标题】:Is it possible to reuse a layout in Kotlin Anko是否可以在 Kotlin Anko 中重用布局
【发布时间】:2017-02-25 21:08:03
【问题描述】:

我读到使用 Anko 的最大好处是它的可重用性。但我找不到它的确切例子。

目前在新的Android布局系统中,样板如下:

DrawerLayout (with some setup)
   CoordinatorLayout (with some setup)
      AppBarLayout (with some setup)
         ToolBar
      <The Main Content>
   NavigationView (with header inflated)

从上面的布局结构来看,只有&lt;The Main Content&gt;是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 等)。

这可能吗?

编辑 所以我认为我的问题是:如何制作可以托管其他组件的自定义组件

【问题讨论】:

    标签: android android-layout kotlin anko


    【解决方案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()
        }
    }
    

    然而stated in the documentation:

    虽然您可以直接使用 DSL(在 onCreate() 或任何地方 否则),无需创建任何额外的类,通常很方便 在单独的类中有 UI。如果您使用提供的 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()
            }
        }
    }
    

    【讨论】:

    • 感谢您的回复。是的,我明白这一点。但可以找到如何制作作为其他组件容器的自定义组件的示例。查看我的代码,myCustomRootLayout 应该包含 DrawerLayout, CoordinatorLayout, AppBarLayout 等,但还应该托管另一个组件 &lt;The Main Content&gt;。所以将来我可以像这样使用它们:myCustomRootLayout { recyclerView() }(在其中添加一个回收器视图)
    • @ktutnik myCustomRootLayout 扩展方法和MyCustomRootLayout 类都接受在设置组件元素后调用的委托。此委托可用于添加自定义子元素,即recyclerView()
    • 我担心插入的孩子的位置。是否需要付出一些努力才能将孩子作为 CoordinatorLayout 的孩子而不是根视图?
    • @ktutnik 我有一个几乎相同的问题。您是否找到将自定义视图作为子项插入另一个布局的方法?
    • @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 来说有点陌生。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2017-12-18
      • 2015-07-30
      相关资源
      最近更新 更多