blob: 3e09abe3c3480d7fd810a1697af3baabe4f8fdf6 [file] [log] [blame]
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.activity.compose
import android.view.ViewGroup
import androidx.activity.ComponentActivity
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionContext
import androidx.compose.ui.platform.ComposeView
import androidx.lifecycle.ViewTreeLifecycleOwner
import androidx.lifecycle.ViewTreeViewModelStoreOwner
import androidx.savedstate.ViewTreeSavedStateRegistryOwner
/**
* Composes the given composable into the given activity. The [content] will become the root view
* of the given activity.
*
* This is roughly equivalent to calling [ComponentActivity.setContentView] with a [ComposeView]
* i.e.:
*
* ```
* setContentView(
* ComposeView(this).apply {
* setContent {
* MyComposableContent()
* }
* }
* )
* ```
*
* @param parent The parent composition reference to coordinate scheduling of composition updates
* @param content A `@Composable` function declaring the UI contents
*/
public fun ComponentActivity.setContent(
parent: CompositionContext? = null,
content: @Composable () -> Unit
) {
val existingComposeView = window.decorView
.findViewById<ViewGroup>(android.R.id.content)
.getChildAt(0) as? ComposeView
if (existingComposeView != null) with(existingComposeView) {
setParentCompositionContext(parent)
setContent(content)
} else ComposeView(this).apply {
// Set content and parent **before** setContentView
// to have ComposeView create the composition on attach
setParentCompositionContext(parent)
setContent(content)
// Set the view tree owners before setting the content view so that the inflation process
// and attach listeners will see them already present
setOwners()
setContentView(this, DefaultActivityContentLayoutParams)
}
}
private val DefaultActivityContentLayoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
/**
* These owners are not set before AppCompat 1.3+ due to a bug, so we need to set them manually in
* case developers are using an older version of AppCompat.
*/
private fun ComponentActivity.setOwners() {
val decorView = window.decorView
if (ViewTreeLifecycleOwner.get(decorView) == null) {
ViewTreeLifecycleOwner.set(decorView, this)
}
if (ViewTreeViewModelStoreOwner.get(decorView) == null) {
ViewTreeViewModelStoreOwner.set(decorView, this)
}
if (ViewTreeSavedStateRegistryOwner.get(decorView) == null) {
ViewTreeSavedStateRegistryOwner.set(decorView, this)
}
}