如何在 Fragment 中使用 Compose?

Nur*_*lov 24 android android-jetpack-compose

该文档描述了如何在 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!")
    }
}
Run Code Online (Sandbox Code Playgroud)

}

但是我怎样才能在片段中使用它呢?

ver*_*as1 51

setContentViewGroup现在已经过时。

以下内容从 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.")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于混合组合 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.")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • `setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed)` 此外,在执行此操作时应检查组合策略。https://developer.android.com/jetpack/compose/interop/interop-apis#compose-in-fragments (15认同)

Gab*_*tti 26

1.0.x您一起可以:

- 在 xml 布局中定义 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_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>
Run Code Online (Sandbox Code Playgroud)
  • ComposeView然后使用 XML ID获取,设置组合策略并调用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
        }
    
        /** ... */
    }
Run Code Online (Sandbox Code Playgroud)

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!")
                    }
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)


Nur*_*lov 12

找到了:

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
            }
        }
    }
 }
}
Run Code Online (Sandbox Code Playgroud)


Cri*_*tan 11

您不需要使用 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!")
}

Run Code Online (Sandbox Code Playgroud)

  • 虽然这是事实,但这并不会使片段作为主干的用例无效,这可能是迁移代码库的常见场景。所以这并不能回答问题。 (9认同)
  • 虽然这是可能的,但在具有多个屏幕的应用程序中是不可行的。 (6认同)
  • 真的。这就是为什么在现实世界中,您实际上不应该像我的示例中那样编写代码。每个屏幕(如“WelcomeScreen”和“SecondScreen”)应位于其自己的文件中,而不是位于 MainActivity.kt 中。这同样适用于导航。 (6认同)
  • 将所有撰写代码放入一个活动中最终会导致活动长达数千行。也许更多。 (2认同)
  • 应用程序逻辑(您通常将其放入 ViewModel 中)怎么样? (2认同)

Yev*_*ian 10

在我看来,如果你想以像这样的漂亮方式使用 Jetpack Compose 和片段

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
) = contentView {
    Text("Hello world")
}
Run Code Online (Sandbox Code Playgroud)

您可以为片段创建自己的扩展函数

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
}
Run Code Online (Sandbox Code Playgroud)

我喜欢这种方法,因为它看起来类似于 Activity 的setContent { }扩展

您还可以定义另一个 CompositionStrategy

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
) = contentView(DisposeOnLifecycleDestroyed(viewLifecycleOwner)) {
    Text("Hello world")
}
Run Code Online (Sandbox Code Playgroud)