Reputation: 1855
I'm using Anko in my Android project, but I don't know how can it reference the child views I created in the DSL when the referenced view is not at the same level where I reference it.
The following code works:
alert {
customView {
val input = textInputLayout {
editText {
hint = "Name"
textColor =resources.getColor(R.color.highlight)
}
}
positiveButton("OK") { "${input.editText.text}" }
}
}.show()
but the following code does not work:
alert {
customView {
val vertical = verticalLayout {
textView {
text = "Edit device name"
textColor = resources.getColor(R.color.highlight)
textSize = 24F
}
val input = textInputLayout {
editText {
hint = "Name"
textColor = resources.getColor(R.color.highlight)
}
}
}
positiveButton("OK") { "${vertical.input.editText.text}" } // Cannot resolve "input"
}
}.show()
Upvotes: 15
Views: 3200
Reputation: 739
I usually declare a view as a property in a class with lateinit
modifier; this way it's not nullable and most of views are declared in one place, improving readability:
lateinit var toolbar: Toolbar
...
appBarLayout {
toolbar = toolbar {}.lparams(width = matchParent, height = matchParent)
}.lparams(width = matchParent)
...
setSupportActionBar(toolbar)
Upvotes: 1
Reputation: 101
Probably the best way is to use Android IDs for the elements you need to reference later, and the find<T : View>(Int) : T
function. This allows you to reference them from anywhere, as long as the view still exists, and you have access to the application/activity scope.
See the Anko Documentation for details
Example case: Dynamically adding buttons to an existing view
verticalLayout {
id = R.id.button_container
}
//note that the code below here may be executed anywhere after the above in your onCreate function
//verticalLayout is a Anko subclass of LinearLayout, so using the android class is valid.
val buttonContainer = find<LinearLayout>(R.id.button_container)
val containerContext = AnkoContext.Companion.create(ctx, buttonContainer)
val button = ctx.button {
text = "click me"
onClick = { toast("created with IDs!") }
}
buttonContainer.addView(button.createView(containerContext, buttonContainer))
Upvotes: 0
Reputation: 33749
You can always elevate a view, passing the context vertical
manually:
customView {
val vertical = verticalLayout {
textView {
text = "Edit device name"
textColor = resources.getColor(R.color.highlight)
textSize = 24F
}
}
val input = /*here:*/ vertical.textInputLayout {
editText {
hint = "Name"
textColor = resources.getColor(R.color.highlight)
}
}
positiveButton("OK") { "${input.editText.text}" }
}
Upvotes: 1
Reputation: 1815
I propose using findViewById()
alert {
customView {
val vertical = verticalLayout {
textView {
text = "Edit device name"
textSize = 24F
}
val input = textInputLayout {
editText {
id = R.id.my_id_resource // put your id here
hint = "Name"
}
}
}
positiveButton("OK") { "${(vertical.findViewById(R.id.my_id_resource) as? EditText)?.text}" }
}
}.show()
Upvotes: 2
Reputation: 43811
As I see it there are two ways. The super hacky way would be to declare the positive button within the textInputLayout
block. This is possible because you can access all outer scopes from within any nested scope and the positiveButton
method is declared in the alert
scope:
alert {
customView {
verticalLayout {
textInputLayout {
val editText = editText {
hint = "Name"
}
positiveButton("OK") { toast("${editText.text}") }
}
}
}
}.show()
The less hacky way would be to declare a variable that can be accessed from both scopes. However you would need to make it nullable since you can't initialize it immediately:
alert {
var editText: EditText? = null
customView {
verticalLayout {
textInputLayout {
editText = editText {
hint = "Name"
}
}
}
}
positiveButton("OK") { toast("${editText!!.text}") }
}.show()
Upvotes: 6