Anko: Splitting a layout into smaller functions

Created on 4 Jul 2017  路  4Comments  路  Source: Kotlin/anko

I tried to factor out a part of my layout into a separate function.
But I am getting an exception.

Being able to split the layout definition is very useful, so I guess I am doing something wrong?
I have also tried to return a View from my test() function, which did not work either.
See below for the exception thrown by Android.

class GenericRecyclerUI(val dataAdapter: RecyclerView.Adapter<GenericRecyclerViewHolder>) : AnkoComponent<Fragment> {
    override fun createView(ui: AnkoContext<Fragment>): View {
        return with(ui) {
            val c = (ui.owner as GenericRecyclerFragment).configuration  // config object

            verticalLayout {

                if (c.showHeader) {
                    textView {
                        padding = dip(5)
                        backgroundColor = resources.getColor(c.headerBackground)
                        text = c.headerTitle
                        typeface = Typeface.DEFAULT_BOLD
                        textSize = 22f
                        textColor = Color.WHITE
                        textAlignment = View.TEXT_ALIGNMENT_GRAVITY
                        gravity = Gravity.CENTER

                    }.lparams {
                        width = matchParent
                        height = c.headerHeight
                        bottomMargin = dip(3)
                    }
                }

                test(this@with)


                frameLayout {
                    lparams(width = matchParent, height = matchParent)
                    val recycler = recyclerView {
                        id = R.id.ui_grv_recycler
                        lparams(width = matchParent, height = matchParent)
                        layoutManager = LinearLayoutManager(ctx)
                        adapter = dataAdapter
                    }

                }

            }
        }
    }

    private fun test(ui: AnkoContext<Fragment>)  {
        with(ui) {
            editText() {
                textSize = 20f
            }
        }
    }
}

This code throws an exception:
Caused by:
java.lang.IllegalStateException: View is already set: 0,0-0,0}
at org.jetbrains.anko.AnkoContextImpl.alreadyHasView(AnkoContext.kt:118)
at org.jetbrains.anko.AnkoContextImpl.addView(AnkoContext.kt:100)
at org.jetbrains.anko.internals.AnkoInternals.addView(Internals.kt:48)
at org.example.ui.GenericRecyclerUI.createView(GenericRecyclerFragment.kt:286)
at org.example.ui.GenericRecyclerFragment.onCreateView(GenericRecyclerFragment.kt:218)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2192)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1255)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1472)
at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1691)
at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:3440)
at android.support.v4.app.FragmentController.onCreateView(FragmentController.java:120)
at android.support.v4.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:378)
at android.support.v4.app.BaseFragmentActivityHoneycomb.onCreateView(BaseFragmentActivityHoneycomb.java:33)
at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:79)
at android.view.LayoutInflater.createViewFromTag

Most helpful comment

To answer my own question, the problem here is that the receiver is actually _LinearLayout.

So adding an extension method to _LinearLayout does the job.

    private fun _LinearLayout.test2() {
        editText {
            textSize = 20f
        }.lparams {
            width = matchParent
            height = dip(40)
        }
    }

However, could this be done without adding a method to _LinearLayout?

All 4 comments

To answer my own question, the problem here is that the receiver is actually _LinearLayout.

So adding an extension method to _LinearLayout does the job.

    private fun _LinearLayout.test2() {
        editText {
            textSize = 20f
        }.lparams {
            width = matchParent
            height = dip(40)
        }
    }

However, could this be done without adding a method to _LinearLayout?

Best since sliced bread!

just use command+option+M in Android Studio ~

@nkanellopoulos I had the same issue and here is my take on it

fun foodTypeFilter(vm: ViewManager, wording: String): View {
    return vm.run {
        relativeLayout {
            button(wording).lparams {
                alignParentBottom()
                centerHorizontally()
            }
            backgroundColor = Color.GRAY
            elevation = dip(10).toFloat()
        }
    }
}
// later... in side of createView(ui: AnkoContext<FoodFragment>): View {
foodTypeFilter(this, "Croquettes".toUpperCase())

Essentially passing this in the function, the param being an abstract "ViewManager"

Hope this helps !

Was this page helpful?
0 / 5 - 0 ratings