Reputation: 24563
Google gives the following example of how to use a ComposeView in XML and inflate it in a fragment.
class ExampleFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
return inflater.inflate(
R.layout.fragment_example, container, false
).apply {
findViewById<ComposeView>(R.id.compose_view).setContent {
// In Compose world
MaterialTheme {
Text("Hello Compose!")
}
}
}
}
}
I have an activity written in java, not kotlin. Is it possible to use setContent from a Java activity? If so I am struggling with the syntax.
Upvotes: 8
Views: 7845
Reputation: 11
To manage it from a single place, we can manage it with the help of a manager in both Kotlin and Java.
object ComposeViewManager {
fun setComposableContent(
composeView: ComposeView,
content: ComposableProvider,
) {
composeView.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
content.ProvideComposableContent()
}
}
}
}
fun setComposableContentForKotlin(
composeView: ComposeView,
content: @Composable ComposableProvider.() -> Unit,
) {
composeView.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme {
ComposableProviderImpl().content()
}
}
}
}
}
In my article where I explain in detail how to use Compose View in Java and Kotlin: What is ComposeView and How to Use in Kotlin and Java codes?
With clean architecture
Upvotes: 1
Reputation: 63
You don't necessarily need the AbstractComposeView. I was able to do this just with the following:
Add ComposeView to your layout.xml just as you would any other View:
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Create a new kt file, for example ComposeFunctions.kt that has a function to set the content to the ComposeView:
@file:JvmName("ComposeFunctions")
package (your package goes here)
fun setContent(composeView: ComposeView) {
composeView.setContent { composable kt function goes here }
}
Now from your java Activity/Fragment
ComposeView composeView = view.findViewById(R.id.compose_view);
ComposeFunctions.setContent(composeView);
I have used this successfully on WearOS for androidx.wear.compose.material.TimeText:
composeView.setContent { TimeText() }
Upvotes: 2
Reputation: 11477
Instead of creating an AbstractComposeView
, you can simply wrap up a kotlin function and pass on the activity instance and set the content.
For example:
object ComposeContent {
fun setContentFromJavaActivity(activity: AppCompatActivity) {
activity.setContent {
// Your composable content goes here
}
}
}
Activity onCreate(..)
:-
public class MyJavaActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ComposeContent.INSTANCE.setContentFromJavaActivity(this);
}
}
(Creating instance of AbstractComposeView
or ComposeView
comes handy only when we want to render a section of an Activity with a compose UI (or in a Fragment
))
Upvotes: 7
Reputation: 23854
Yes, it's possible.
First you should create a subclass of AbstractComposeView
:
class MyComposeView
@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
AbstractComposeView(context, attrs) {
@Composable
override fun Content() {
YourComposableFunction()
}
}
and then set this view as Activity content...
public class MyJavaActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyComposeView(this));
}
}
You can also declare your view in any layout file...
<com.example.MyComposeView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
and call setContentView(R.layout.your_layout_file)
as usual.
Upvotes: 4