Hi, I`ve created ToolbarComponent that I am using in several places in my application and I want to know if there is some way how to easily use this component when creating view or if there is some better way how to simulate "include" tag from xml.
The current usage that works but is not pretty is
UI {
frameLayout {
val ankoContext = AnkoContext.Companion.createReusable(ctx, this@BaseFragmentActivity)
addView(ToolbarComponent<BaseFragmentActivity>().createView(ankoContext))
}
}.view
this is how I did it
//views/utils.kt
fun <T: AnkoComponent<out Context>> ViewGroup.mount(component: T, onMount: (T.() -> Unit)? = null) =
context.render(component as AnkoComponent<Context>).apply {
addView(this)
onMount?.invoke(component)
}
inline fun Context.render(component: AnkoComponent<out Context>) =
(component as AnkoComponent<Context>).createView(AnkoContext.createReusable(this))
usage:
class Component: AnkoComponent<SomeActivity> {
// ...
}
// in a ViewGroup closure
verticalLayout {
mount(Component(/*some props*/)){
// do smt with Component, eg: hook up to sinks
}
}
1-liner :
ankoView(::CustomToolbarView, 0) {
backgroundColor = Color.RED
}
Please check Extending Anko.
Well thanks for @lukaspili and @yanex tip, but neither answers my question. I was not talking about custom view but about AnkoComponents
@davidbilik I know this is an old post, but it looks like you didn't quite get your answer, here's how I did it...
// Functions to allow me to use the DemoView directly in DSL
// Note that the init function now accepts the DemoView as the first argument which is how I'm able
// To make calls on the component.
inline fun ViewManager.demoView(theme: Int = 0) = demoView(theme) {}
inline fun ViewManager.demoView(theme: Int = 0, title: String = "", action: String = "",
init: View.(demoView: DemoView) -> Unit): View {
val demoView = DemoView(title, action)
return ankoView({ demoView.createView(AnkoContext.create(it)) }, theme, { init(demoView) })
}
// The DemoView component
class DemoView(val title: String, val action: String): AnkoComponent<Context> {
private lateinit var ankoContext: AnkoContext<Context>
private lateinit var buttonView: View
override fun createView(ui: AnkoContext<Context>): View = with(ui) {
ankoContext = ui
linearLayout {
orientation = HORIZONTAL
lparams(matchParent, wrapContent) {
padding = dip(8)
}
gravity = Gravity.CENTER_VERTICAL
textView(title).lparams(0, wrapContent) {
weight = 1f
}
button(action) {
[email protected] = this
}.lparams(wrapContent, wrapContent)
}
}
fun onClick(body: (title: String, action: String) -> Unit) {
buttonView.onClick { body(title, action) }
}
}
// Small demo activity to create 2 instances of DemoView
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
verticalLayout {
demoView(title = "title1", action = "action1") { demoView ->
demoView.onClick { title, action -> toast("$title: $action") }
}
demoView(title = "title2", action = "action2") { demoView ->
demoView.onClick { title, action -> toast("$title: $action") }
}
}
}
}
inline fun ViewManager.ankoComponent(component: AnkoComponent<Context>, theme: Int = 0) = ankoComponent(component, theme) {}
inline fun ViewManager.ankoComponent(
component: AnkoComponent<Context>,
theme: Int = 0,
init: View.(component: AnkoComponent<Context>) -> Unit
): View {
return ankoView({ component.createView(AnkoContext.create(it)) }, theme, { init(component) })
}
I've based on @yperess comment and make it easier to insert any ankoComponent. You can easily use it.
`
verticalLayout {
ankoComponent(someUI)
}
`
someUI in this case is instance of anko component you need to inject
Most helpful comment
@davidbilik I know this is an old post, but it looks like you didn't quite get your answer, here's how I did it...