אפשר להוסיף ממשק משתמש מבוסס-Compose לאפליקציה קיימת שמשתמשת בעיצוב מבוסס-View.
כדי ליצור מסך חדש שמבוסס כולו על 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.
ViewCompositionStrategy
למשך ComposeView
ViewCompositionStrategy
מגדיר מתי יש לבטל את ה-Composition. ברירת המחדל, ViewCompositionStrategy.Default
, היא שהרכיב Composition מושמד כשהרכיב הבסיסי ComposeView
מתנתק מהחלון, אלא אם הוא חלק מקונטיינר של איגום כמו RecyclerView
. באפליקציה עם Activity יחיד שכוללת רק Compose, זוהי התנהגות ברירת המחדל הרצויה. עם זאת, אם מוסיפים Compose בהדרגה בבסיס הקוד, יכול להיות שההתנהגות הזו תגרום לאובדן מצב בתרחישים מסוימים.
כדי לשנות את ViewCompositionStrategy
, מתקשרים לשיטה setViewCompositionStrategy()
ומספקים שיטה אחרת.
בטבלה הבאה מפורטים התרחישים השונים שבהם אפשר להשתמש ב-ViewCompositionStrategy
:
ViewCompositionStrategy |
תיאור ותרחיש של פעולה הדדית |
---|---|
DisposeOnDetachedFromWindow |
האובייקט Composition יושמד כשהאובייקט הבסיסי ComposeView ינותק מהחלון. הוחלף מאז ב-DisposeOnDetachedFromWindowOrReleasedFromPool .תרחיש פעולה הדדית: * ComposeView אם זה הרכיב היחיד בהיררכיית התצוגה, או בהקשר של מסך מעורב של View/Compose (לא ב-Fragment). |
DisposeOnDetachedFromWindowOrReleasedFromPool (ברירת מחדל) |
בדומה ל-DisposeOnDetachedFromWindow , כשהקומפוזיציה לא נמצאת במאגר משותף, כמו RecyclerView . אם הוא נמצא במאגר, הוא יסולק כשהמאגר עצמו ינותק מהחלון, או כשהפריט יימחק (כלומר כשהמאגר מלא).תרחיש פעולה הדדית: * ComposeView אם זה הרכיב היחיד בהיררכיית התצוגה, או בהקשר של מסך מעורב של תצוגה/יצירה (לא ב-Fragment).* ComposeView כפריט בקונטיינר של מאגר, כמו RecyclerView . |
DisposeOnLifecycleDestroyed |
האובייקט Composition יושמד כשהאובייקט Lifecycle שסופק יושמד.תרחיש פעולה הדדית * ComposeView בתצוגה של Fragment. |
DisposeOnViewTreeLifecycleDestroyed |
האובייקט Composition יושמד כשהאובייקט Lifecycle שבבעלות LifecycleOwner שמוחזר על ידי ViewTreeLifecycleOwner.get של החלון הבא שאליו מצורף האובייקט View יושמד.תרחיש פעולה הדדית: * ComposeView באובייקט View של Fragment.* ComposeView בתצוגה שבה מחזור החיים עדיין לא ידוע. |
ComposeView
במקטעים
אם רוצים לשלב תוכן של ממשק משתמש של Compose ב-Fragment או בפריסת View
קיימת, משתמשים ב-ComposeView
ומפעילים את השיטה setContent()
. ComposeView
הוא View
ל-Android.
אפשר להוסיף את ComposeView
לפריסת ה-XML בדיוק כמו כל View
אחר:
<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. לאחר מכן מקבלים את ComposeView
באמצעות מזהה ה-XML, מגדירים אסטרטגיית קומפוזיציה שמתאימה ביותר למארח View
, וקוראים ל-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 } }
אפשר גם להשתמש ב-view binding כדי לקבל הפניות ל-ComposeView
על ידי הפניה למחלקת ה-binding שנוצרה עבור קובץ פריסת ה-XML:
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. הפלט של הקוד שמוסיף רכיבי Compose בהיררכיית ממשק המשתמש של View. הטקסט 'Hello Android!' מוצג על ידי ווידג'ט TextView
. הטקסט Hello Compose! מוצג על ידי רכיב טקסט של Compose.
אפשר גם לכלול ComposeView
ישירות ב-fragment אם המסך המלא בנוי באמצעות Compose, וכך לא צריך להשתמש בקובץ פריסה בפורמט 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
באותו פריסת דף, לכל אחד מהם צריך להיות מזהה ייחודי כדי שרכיב 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 // ... } ) } }
המזהים ComposeView
מוגדרים בקובץ res/values/ids.xml
:
<resources> <item name="compose_view_x" type="id" /> <item name="compose_view_y" type="id" /> </resources>
תצוגה מקדימה של פונקציות Composable ב-Layout Editor
אפשר גם לראות תצוגה מקדימה של רכיבי Composables בכלי לעריכת פריסות עבור פריסת ה-XML שמכילה ComposeView
. כך תוכלו לראות איך רכיבי ה-Composable נראים בפריסה של Views ו-Compose.
נניח שרוצים להציג את הרכיב הבא שאפשר להרכיב בעורך הפריסה. הערה
חשוב לדעת שרכיבים שאפשר להרכיב (composables) עם ההערה @Preview
הם מועמדים טובים לתצוגה מקדימה בכלי לעריכת פריסות.
@Preview @Composable fun GreetingPreview() { Greeting(name = "Android") }
כדי להציג את הקומפוזיציה הזו, משתמשים במאפיין tools:composableName
tools ומגדירים את הערך שלו לשם המלא של הקומפוזיציה כדי לראות תצוגה מקדימה בפריסה.
<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>
השלבים הבאים
עכשיו, אחרי שאתם יודעים אילו ממשקי API של יכולת פעולה הדדית צריך להשתמש כדי לכתוב הודעות בתצוגות, אתם יכולים לקרוא איך משתמשים בתצוגות בכתיבת הודעות.
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- שיקולים נוספים
- אסטרטגיית העברה {:#migration-strategy}
- השוואה בין הביצועים של Compose ו-View