你可以將Compose-based UI 加到採用view-based設計的既有App。
如要建立以 Compose 為基礎的新畫面,請讓活動呼叫 setContent() 方法,然後視需要傳遞任何可組合項。
class ExampleActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { // In here, we can call composables! MaterialTheme { Greeting(name = "compose") } } } } @Composable fun Greeting(name: String) { Text(text = "Hello $name!") }
這段程式碼看起來就像 Compose-only App中會出現的寫法。
出局 ViewCompositionStrategy 人,得分 ComposeView
ViewCompositionStrategy 定義應處置組合結構的時間。預設值 ViewCompositionStrategy.Default 會在基礎 ComposeView 與視窗卸載時處置組合結構,除非它是集區容器 (例如 RecyclerView) 的一部分。在單一 Activity 且僅限 Compose 的應用程式中,這項預設行為是您想要的,但如果您在程式碼集中逐步新增 Compose,這項行為可能會在某些情況下導致狀態遺失。
如要變更 ViewCompositionStrategy,請呼叫 setViewCompositionStrategy() 方法,並提供其他策略。
下表彙整了 ViewCompositionStrategy 的不同使用情境:
ViewCompositionStrategy |
說明和互通情境 |
|---|---|
DisposeOnDetachedFromWindow |
當基礎 ComposeView 從視窗卸離時,系統會捨棄組合結構。現已由 DisposeOnDetachedFromWindowOrReleasedFromPool 取代。互通情境: * ComposeView,無論是檢視區塊階層中的唯一元素,還是混合檢視區塊/Compose 畫面 (不在片段中)。 |
DisposeOnDetachedFromWindowOrReleasedFromPool (預設) |
與 DisposeOnDetachedFromWindow 類似,當組合結構不在集區容器 (例如 RecyclerView) 中時,如果是在集區容器中,則會在集區容器本身與視窗分離時,或在項目遭到捨棄時 (即集區已滿時) 處置。互通情境: * ComposeView 是檢視區塊階層中的唯一元素,或是在混合檢視區塊/Compose 畫面 (不在片段中) 的情境中。* ComposeView 做為集區容器 (例如 RecyclerView) 中的項目。 |
DisposeOnLifecycleDestroyed |
提供的 Lifecycle 遭到刪除時,Composition 也會一併刪除。互通性情境 * 片段檢視畫面中的 ComposeView。 |
DisposeOnViewTreeLifecycleDestroyed |
當檢視畫面附加至下一個視窗時,ViewTreeLifecycleOwner.get 會傳回 ,而當 LifecycleOwner 擁有的 Lifecycle 遭到刪除時,系統會處置組合結構。互通情境: * 片段檢視畫面中的 ComposeView。* 在生命週期未知的檢視畫面中, ComposeView。 |
Fragment 中的 ComposeView (過渡步驟)
如要在片段或現有的 View 版面配置中加入 Compose UI 內容,請使用 ComposeView 並呼叫其 setContent() 方法。ComposeView 是 Android View。
您可將 ComposeView 和其他的 View 一樣地放在 XML 版面配置中:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <androidx.compose.ui.platform.ComposeView android:id="@+id/compose_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
在 Kotlin 原始碼中,從 XML 定義的版面配置資源加載版面配置。然後使用 XML ID 取得 ComposeView,並設定最適合代管 View 的 Composition 策略,並呼叫 setContent() 以使用 Compose。
class ExampleFragmentXml : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { val view = inflater.inflate(R.layout.fragment_example, container, false) val composeView = view.findViewById<ComposeView>(R.id.compose_view) composeView.apply { // Dispose of the Composition when the view's LifecycleOwner // is destroyed setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { // In Compose world MaterialTheme { Text("Hello Compose!") } } } return view } }
或者,您也可以使用檢視區塊繫結,參照為 XML 版面配置檔案產生的繫結類別,取得 ComposeView 的參照:
class ExampleFragment : Fragment() { private var _binding: FragmentExampleBinding? = null // This property is only valid between onCreateView and onDestroyView. private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentExampleBinding.inflate(inflater, container, false) val view = binding.root binding.composeView.apply { // Dispose of the Composition when the view's LifecycleOwner // is destroyed setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { // In Compose world MaterialTheme { Text("Hello Compose!") } } } return view } override fun onDestroyView() { super.onDestroyView() _binding = null } }
圖 1. 這個程式碼會顯示在 View UI 階層中新增 Compose 元素的程式碼輸出內容。「Hello Android!」文字會以 TextView 小工具顯示。「您好 Compose!」文字會顯示Compose 文字元素。
假如您使用 Compose 建立全螢幕畫面,可以直接在片段中加入 ComposeView,避免完全使用 XML 版面配置檔案。
class ExampleFragmentNoXml : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { return ComposeView(requireContext()).apply { // Dispose of the Composition when the view's LifecycleOwner // is destroyed setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { MaterialTheme { // In Compose world Text("Hello Compose!") } } } } }
在同一個版面配置中有多個 ComposeView 執行個體
如果在同一個版面配置中有多個 ComposeView 元素,則每個元素都必須有專屬 ID 供 savedInstanceState 運作。
class ExampleFragmentMultipleComposeView : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View = LinearLayout(requireContext()).apply { addView( ComposeView(requireContext()).apply { setViewCompositionStrategy( ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed ) id = R.id.compose_view_x // ... } ) addView(TextView(requireContext())) addView( ComposeView(requireContext()).apply { setViewCompositionStrategy( ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed ) id = R.id.compose_view_y // ... } ) } }
res/values/ids.xml 檔案已定義 ComposeView ID:
<resources> <item name="compose_view_x" type="id" /> <item name="compose_view_y" type="id" /> </resources>
在版面配置編輯器中預覽可組合項
您也可以在版面配置編輯器中,預覽含有 ComposeView 的 XML 版面配置中的可組合項。這樣一來,您就能在混合式 View 和 Compose 版面配置中,查看可組合項的外觀。
假設您想在版面配置編輯器中顯示下列可組合項。請注意,加上 @Preview 註解的可組合函式很適合在版面配置編輯器中預覽。
@Preview @Composable fun GreetingPreview() { Greeting(name = "Android") }
如要顯示這個可組合函式,請使用 tools:composableName 工具屬性,並將其值設為要在版面配置中預覽的可組合函式完整名稱。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.compose.ui.platform.ComposeView android:id="@+id/my_compose_view" tools:composableName="com.example.compose.snippets.interop.InteroperabilityAPIsSnippetsKt.GreetingPreview" android:layout_height="match_parent" android:layout_width="match_parent"/> </LinearLayout>
