如何在 Fragment 中使用 Compose?
Posted
技术标签:
【中文标题】如何在 Fragment 中使用 Compose?【英文标题】:How to use Compose inside Fragment? 【发布时间】:2020-04-09 14:37:24 【问题描述】:文档描述了如何在 Activity 中创建 UI (Jetpack Compose https://developer.android.com/jetpack/compose)。
class MainActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContent
Text("Hello world!")
但是我如何在片段中使用它呢?
【问题讨论】:
请编辑您的问题以提供一个可重复的最小示例。到目前为止,您的问题还很模糊,很难看出您在做什么以及问题出在哪里。 如果我不确定我是否得到你,请在你的活动中使用框架布局,片段有自己的生命周期和你可以使用的 xml 文件,这里是官方文档链接developer.android.com/guide/components/fragments 好的,我给你一个赞,现在享受代码..我已经发布了代码.. 【参考方案1】:ViewGroup
上的setContent
现在已弃用。
从 Compose v1.0.0-alpha01 开始,以下是准确的。
对于纯撰写 UI Fragment
:
class ComposeUIFragment : Fragment()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View?
return ComposeView(requireContext()).apply
setContent
Text(text = "Hello world.")
对于混合撰写 UI Fragment
- 将 ComposeView
添加到 xml 布局,然后:
class ComposeUIFragment : Fragment()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View?
return inflater.inflate(R.layout.fragment_compose_ui, container, false).apply
findViewById<ComposeView>(R.id.composeView).setContent
Text(text = "Hello world.")
【讨论】:
setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed)
此外,在执行此操作时应审查组合策略。 developer.android.com/jetpack/compose/interop/…
如何获取Fragment中的NavController?【参考方案2】:
Compose 不需要 Fragments。您无需 Fragment 或 Activity 即可导航到另一个屏幕:
class MainActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContent
val navController = rememberNavController()
NavHost(navController, startDestination = "welcome")
composable("welcome") WelcomeScreen(navController)
composable("secondScreen") SecondScreen()
@Composable
fun WelcomeScreen(navController: NavController)
Column
Text(text = "Welcome!")
Button(onClick = navController.navigate("secondScreen") )
Text(text = "Continue")
@Composable
fun SecondScreen()
Text(text = "Second screen!")
【讨论】:
虽然这是真的,但它不会使将片段用作主干的用例无效,这可能是迁移代码库的常见场景。所以这并不能回答问题。 虽然这是可能的,但在具有多个屏幕的应用中是不可行的。 @JasonCrosby 我不明白你为什么不在有很多屏幕的应用程序中使用它。是的,NavHost
会增长,但您可以轻松地将其提取到单独的文件中,这样您的主要活动将保持精简。
将所有的撰写代码放在一个活动中最终会导致数千行的活动。也许更多。
是的。这就是为什么在现实世界中,您实际上不应该像我的示例中那样编写代码。每个屏幕(如WelcomeScreen
和SecondScreen
)都应该在自己的文件中,而不是在 MainActivity.kt 中。同样适用于导航。【参考方案3】:
找到了:
class LoginFragment : Fragment()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View?
// Inflate the layout for this fragment
val fragmentView = inflater.inflate(R.layout.fragment_login, container, false)
(fragmentView as ViewGroup).setContent
Hello("Jetpack Compose")
return fragmentView
@Composable
fun Hello(name: String) = MaterialTheme
FlexColumn
inflexible
// Item height will be equal content height
TopAppBar( // App Bar with title
title = Text("Jetpack Compose Sample")
)
expanded(1F)
// occupy whole empty space in the Column
Center
// Center content
Text("Hello $name!") // Text label
【讨论】:
可以分享一下fragment_login.xml的内容吗? 已弃用(在 alpha12 上测试)【参考方案4】:使用1.0.x
,您可以:
- 在 xml-layout 中定义 ComposeView。
在您的 layout-xml 文件中添加androidx.compose.ui.platform.ComposeView
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:orientation="vertical"
...>
<TextView ../>
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_
android:layout_ />
</LinearLayout>
然后使用 XML ID 获取ComposeView
,设置Composition strategy 并调用setContent()
:
class ExampleFragment : Fragment()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View
_binding = FragmentExampleBinding.inflate(inflater, container, false)
val view = binding.root
view.composeView.apply
// Dispose the Composition when viewLifecycleOwner is destroyed
setViewCompositionStrategy(
DisposeOnLifecycleDestroyed(viewLifecycleOwner)
)
setContent
// In Compose world
MaterialTheme
Text("Hello Compose!")
return view
/** ... */
- 直接在片段中包含ComposeView
。
class ExampleFragment : Fragment()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View
return ComposeView(requireContext()).apply
// Dispose the Composition when viewLifecycleOwner is destroyed
setViewCompositionStrategy(
DisposeOnLifecycleDestroyed(viewLifecycleOwner)
)
setContent
MaterialTheme
// In Compose world
Text("Hello Compose!")
【讨论】:
谢谢,setViewCompositionStrategy
解决了我的问题【参考方案5】:
如果你想以这样漂亮的方式使用带有片段的 Jetpack Compose,我想
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
) = contentView
Text("Hello world")
您可以为 Fragments 创建自己的扩展函数
fun Fragment.requireContentView(
compositionStrategy: ViewCompositionStrategy = DisposeOnDetachedFromWindow,
context: Context = requireContext(),
content: @Composable () -> Unit
): ComposeView
val view = ComposeView(context)
view.setViewCompositionStrategy(compositionStrategy)
view.setContent(content)
return view
fun Fragment.contentView(
compositionStrategy: ViewCompositionStrategy = DisposeOnDetachedFromWindow,
context: Context? = getContext(),
content: @Composable () -> Unit
): ComposeView?
context ?: return null
val view = ComposeView(context)
view.setViewCompositionStrategy(compositionStrategy)
view.setContent(content)
return view
我喜欢这种方法,因为它看起来类似于 Activity 的 setContent
扩展
你也可以定义另一个 CompositionStrategy
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
) = contentView(DisposeOnLifecycleDestroyed(viewLifecycleOwner))
Text("Hello world")
【讨论】:
以上是关于如何在 Fragment 中使用 Compose?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Fragment l 中使用 WebView? [关闭]
如何在Fragment中使用PreferenceFragment