是否可以在 Kotlin Anko 中重用布局

Posted

技术标签:

【中文标题】是否可以在 Kotlin Anko 中重用布局【英文标题】:Is it possible to reuse a layout in 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 等)。

这可能吗?

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

【问题讨论】:

【参考方案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 来说有点陌生。

【讨论】:

以上是关于是否可以在 Kotlin Anko 中重用布局的主要内容,如果未能解决你的问题,请参考以下文章

在Android中用Kotlin的Anko运行后台任务(KAD 09)

如何在 Kotlin 中使用 anko 删除除最新 10 条记录之外的所有记录?

用Anko和Kotlin实现Android上的对话框和警告提示(KAD 24)

体验:Anko + Kotlin

AnKo SQLite:从数据库中异步填充listview?

Kotlin/Anko/OpenCV/CameraView 无法创建处理程序,因为线程尚未调用 Looper.prepare()