6

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.

rmtheis
  • 5,992
  • 12
  • 61
  • 78
lostintranslation
  • 23,756
  • 50
  • 159
  • 262

3 Answers3

4

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))

Santanu Sur
  • 10,997
  • 7
  • 33
  • 52
2

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.

nglauber
  • 18,674
  • 6
  • 70
  • 75
  • 1
    This overrides the entire content view. What if I am using a ComposeView tag in xml as a partial compose in an existing layout file? – lostintranslation May 07 '21 at 22:36
  • 1
    No problem at all... you can use this custom view in your XML layout file as usual... – nglauber May 07 '21 at 22:45
  • 1
    @nglauber @lostintranslation Creating an `AbstractComposeView` is redundant here , we can simply wrap up a kotlin object / class and render the content underneath. (Thought the question mostly asked about the syntax from java class.) } However i can only find creating `AbstractComposeView` or `ComposeView` useful from `Fragment` and **NOT** `Activity` ( or section of an activity where we want to render a compsable UI ) – Santanu Sur May 08 '21 at 05:38
  • 1
    I see, but using your approach you can't use your composable in a XML layout file. As you can see in the first comment of this answer, he wants to put the composable in a layout XML file. – nglauber May 08 '21 at 14:03
  • Does the first line of the question ask for a solution involving any XML layout ? Not sure though. – Santanu Sur May 08 '21 at 16:50
0

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() }
Cosmin C.
  • 13
  • 6