I have a custom view created the traditional way: subclassing from the View class.
Specifically, my custom view has many custom attributes (and their corresponding Kotlin properties) that can be assigned in the XML layout:
<com.example.MyCustomView
app:myCustomAttr1 = "..."
app:myCustomAttr2 = "..."/>
Besides using AndroidView class to load a conventional Android view in Jetpack Compose, how can I convert my view to be a "true" Compose component?
Should I provide a separate composable for every part of my custom view? For example, a composable for the pie, another composable for the legend box?
Android developer documentation does not mention how to transform custom views to Compose.
Assuming I have created a composable version of my view like this:
@Composable fun MyComposable(title: String) {
Text(title)
}
to use that composable like a regular View (with the ability to specify its attributes in XML), we should create a custom view subclassing from AbstractComposeView:
// Do not forget these two imports for the delegation (by) to work
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
class MyCustomView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : AbstractComposeView(context, attrs, defStyle) {
var myProperty by mutableStateOf("A string")
init {
// See the footnote
context.withStyledAttributes(attrs, R.styleable.MyStyleable) {
myProperty = getString(R.styleable.MyStyleable_myAttribute)
}
}
// The important part
@Composable override fun Content() {
MyComposable(title = myProperty)
}
}
And this is how we would use it just like a regular view in XML:
<my.package.name.MyCustomView
android:id="@+id/myView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:myAttribute="Helloooooooooo!" />
and/or in an activity:
val myCustomView = findViewById<MyCustomView>(R.id.myView)
myCustomView.myProperty = "Woohoo!"
Thanks to ProAndroidDev for this article.
To define your own custom attributes for your view, see this post.
Also, make sure to use -ktx version of the AndroidX Core library to be able to access useful Kotlin extension functions like Context::withStyledAttributes
:
implementation("androidx.core:core-ktx:1.6.0")