Android : Compose Interoperability APIs
In this article, We’ll be discussing how to use compose and views together in the same project.
Using Views in Compose
To integrate existing android views into compose, Jetpack Compose provides the AndroidView
component, which allows seamless integration of complex, custom, or third-party Android Views into your Compose-based UI without having to recreate them from scratch using Compose’s built-in components.
This will be also useful if you want to use UI elements that are not yet available in Compose like AdView..etc
To use View in compose, use AndroidView
composable.
AndroidView
is passed a lambda that returns aView
AndroidView
provides anfactory
callback that is used to create the viewAndroidView
provides anupdate
callback that is called when the view is inflatedAndroidView
takes aModifier
parameter that can be used to set padding, width, height…etc
AndroidView(
modifier = // pass modifier to adjust the position
factory = { context ->
// Create custom view
},
update = { view ->
// This will call once the view inflated
}
)
Note: We can only use custom view with this approach. If you want to embed xml layout in compose then we need to use AndroidViewBinding
API
Using AndroidView in Lists
If you are using an AndroidView
in a Lazy list (LazyColumn
, LazyRow
, Pager
, etc.), consider using the AndroidView
overload introduced in version 1.4.0-rc01 and later. This overload allows Compose to reuse the underlying View
instance when the containing composition is reused as is the case for Lazy lists.
This overload of AndroidView
adds 2 additional parameters:
onReset
- A callback invoked to signal that theView
is about to be reused. This must be non-null to enable View reuse.onRelease
(optional) - A callback invoked to signal that theView
has exited the composition and will not be reused again.
@Composable
fun SampleComposeList() {
LazyColumn {
items(10) { index ->
AndroidView(
modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI
factory = { context ->
MyListView(context)
},
update = { view ->
view.selectedItem = index
},
onReset = { view ->
view.clear()
}
)
}
}
}
Using XML layout in Compose UI
To embed an XML layout, use the AndroidViewBinding
API.
// layout file: main_layout.xml....viewbinding generated class MainLayoutBinding
@Composable
fun MainScreen() {
AndroidViewBinding(MainLayoutBinding::inflate) {
sampleView.setBackgroundColor(Color.BLACK)
}
}
To use this API, follow below setups
- Add dependency:
implementation "androidx.compose.ui:ui-viewbinding:<compose version>"
- Enable view binding in build.gradle
android {
...
buildFeatures {
viewBinding = true
}
}
To add Fragment in Compose
we can use the AndroidViewBinding
composable to add a Fragment
in Compose
//Layout
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="<Add Fragment class>" />
@Composable
fun FragmentInComposeExample() {
AndroidViewBinding(MyFragmentLayoutBinding::inflate) {
val myFragment = fragmentContainerView.getFragment<MyFragment>()
// ...
}
}
Using Compose in Views
We can add Compose-based UI into an existing app that uses a View-based design.
ComposeView
API is an Android View
Using Compose in Activity
To create a new, entirely Compose-based screen, have your activity call the setContent()
method, and pass whatever composable functions you like
class ExampleActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent { // In here, we can call composables!
MaterialTheme {
Greeting(name = "compose")
}
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
Using ComposeView in XML
- Add ComposeView tag in xml
- use setContent to set the ComposeView
// XML layout activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
// Activity
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val composeView = findViewById<ComposeView>(R.id.compose_view)
// use the setContent to display Composable UI.
composeView.setContent {
// We then render a simple Text component from Compose.
Text(
text = "Hello Compose"
)
}
}
}
Using ComposeView without XML
To create ComposeView in Fragment or Activity directly in Code without adding in XML layout
class ExampleFragmentNoXml : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
// Dispose of the Composition when the view's LifecycleOwner
// is destroyed
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
// In Compose world
Text("Hello Compose!")
}
}
}
}
}