46

How can I add Jetpack Compose & xml in the same activity? An example would be perfect.

Mahozad
  • 18,032
  • 13
  • 118
  • 133
Verlyn Luna
  • 665
  • 1
  • 6
  • 5

4 Answers4

107

If you want to use a Compose in your XML file, you can add this to your layout file:

<androidx.compose.ui.platform.ComposeView
  android:id="@+id/my_composable"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />

and then, set the content:

findViewById<ComposeView>(R.id.my_composable).setContent {
  MaterialTheme {
    Surface {
      Text(text = "Hello!")
    }
  }
}

If you want the opposite, i.e. to use an XML file in your compose, you can use this:

AndroidView(
  factory = { context ->
    val view = LayoutInflater.from(context).inflate(R.layout.my_layout, null, false)
    val textView = view.findViewById<TextView>(R.id.text)

    // do whatever you want...
    view // return the view
  },
  update = { view ->
    // Update the view
  }
)
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
nglauber
  • 18,674
  • 6
  • 70
  • 75
15

If you want to provide your composable like a regular View (with the ability to specify its attributes in XML), subclass from AbstractComposeView.

@Composable 
fun MyComposable(title: String) {
    Text(title)
}
// 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 you would use it just like a regular View:

<my.package.name.MyCustomView
    android:id="@+id/myView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:myAttribute="Helloooooooooo!" />

Thanks to ProAndroidDev for this article.

Footnote

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")
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
Mahozad
  • 18,032
  • 13
  • 118
  • 133
11

https://developer.android.com/jetpack/compose/interop?hl=en

To embed an XML layout, use the AndroidViewBinding API, which is provided by the androidx.compose.ui:ui-viewbinding library. To do this, your project must enable view binding. AndroidView, like many other built-in composables, takes a Modifier parameter that can be used, for example, to set its position in the parent composable.

@Composable
fun AndroidViewBindingExample() {
    AndroidViewBinding(ExampleLayoutBinding::inflate) {
        exampleView.setBackgroundColor(Color.GRAY)
    }
}
Qi Huan
  • 111
  • 2
  • 3
2

Updated : When you want to use XML file in compose function

AndroidView(
  factory = { context ->
    val view = LayoutInflater.from(context).inflate(R.layout.test_layout, null, false)
    val edittext= view.findViewById<EditText>(R.id.edittext)

    view 
  },
  update = {  }
)
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
Pradnya Bhagat
  • 159
  • 1
  • 3
  • 18