אפשר לכלול היררכיית תצוגה של Android בממשק משתמש של Compose. הגישה הזו שימושית במיוחד אם רוצים להשתמש ברכיבי ממשק משתמש שעדיין לא זמינים בכתיבה, כמו AdView
.
בנוסף, הגישה הזו מאפשרת לכם לעשות שימוש חוזר בתצוגות מותאמות אישית שעיצבתם.
כדי לכלול רכיב תצוגה או היררכיה, משתמשים ב-AndroidView
composable. AndroidView
מקבלת פונקציית למבדה שמחזירה את הערך View
. AndroidView
מספק גם קריאה חוזרת (callback) של update
שמופעלת כשהתצוגה מורחבת. הפונקציה AndroidView
מורכבת מחדש בכל פעם שמשתנה ערך של State
שנקרא בתוך הקריאה החוזרת. AndroidView
, כמו הרבה רכיבים קומפוזביליים מובנים אחרים, מקבל פרמטר Modifier
שאפשר להשתמש בו, למשל, כדי להגדיר את המיקום שלו ברכיב הקומפוזבילי של האב.
@Composable fun CustomView() { var selectedItem by remember { mutableIntStateOf(0) } // Adds view to Compose AndroidView( modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree factory = { context -> // Creates view MyView(context).apply { // Sets up listeners for View -> Compose communication setOnClickListener { selectedItem = 1 } } }, update = { view -> // View's been inflated or state read in this block has been updated // Add logic here if necessary // As selectedItem is read here, AndroidView will recompose // whenever the state changes // Example of Compose -> View communication view.selectedItem = selectedItem } ) } @Composable fun ContentExample() { Column(Modifier.fillMaxSize()) { Text("Look at this CustomView!") CustomView() } }
AndroidView
עם view binding
כדי להטמיע פריסת XML, משתמשים ב-API AndroidViewBinding
שמופיע בספרייה androidx.compose.ui:ui-viewbinding
. כדי לעשות את זה, צריך להפעיל view binding בפרויקט.
@Composable fun AndroidViewBindingExample() { AndroidViewBinding(ExampleLayoutBinding::inflate) { exampleView.setBackgroundColor(Color.GRAY) } }
AndroidView
ברשימות עצלניות
אם אתם משתמשים ב-AndroidView
ב-Lazy list (LazyColumn
, LazyRow
,
Pager
וכו'), כדאי להשתמש ב-AndroidView
overload שהוצג בגרסה 1.4.0-rc01. העומס הזה מאפשר ל-Compose לעשות שימוש חוזר במופע View
הבסיסי כשנעשה שימוש חוזר בקומפוזיציה שמכילה אותו, כמו במקרה של רשימות Lazy.
העומס הזה של AndroidView
מוסיף 2 פרמטרים נוספים:
-
onReset
– קריאה חוזרת (callback) שמופעלת כדי לציין שהמערכת עומדת לעשות שימוש חוזר ב-View
. הערך הזה לא יכול להיות null כדי לאפשר שימוש חוזר בתצוגה. -
onRelease
(אופציונלי) – קריאה חוזרת שמופעלת כדי לציין שהרכיבView
יצא מהקומפוזיציה ולא ייעשה בו שימוש חוזר.
@Composable fun AndroidViewInLazyList() { LazyColumn { items(100) { index -> AndroidView( modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree factory = { context -> MyView(context) }, update = { view -> view.selectedItem = index }, onReset = { view -> view.clear() } ) } } }
מקטעים ב-Compose
משתמשים ב-AndroidViewBinding
composable כדי להוסיף Fragment
ב-Compose.
ל-AndroidViewBinding
יש טיפול ספציפי בקטע, כמו הסרת הקטע כשהפונקציה הניתנת להרכבה יוצאת מההרכבה.
כדי לעשות את זה, צריך להרחיב קובץ XML שמכיל את FragmentContainerView
כמחזיק של Fragment
.
לדוגמה, אם הגדרתם את my_fragment_layout.xml
, תוכלו להשתמש בקוד כמו זה, ולהחליף את מאפיין ה-XML android:name
בשם המחלקה של Fragment
:
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container_view" android:layout_width="match_parent" android:layout_height="match_parent" android:name="com.example.compose.snippets.interop.MyFragment" />
כך מרחיבים את קטע הקוד הזה ב-Compose:
@Composable fun FragmentInComposeExample() { AndroidViewBinding(MyFragmentLayoutBinding::inflate) { val myFragment = fragmentContainerView.getFragment<MyFragment>() // ... } }
אם אתם צריכים להשתמש בכמה רכיבים באותו פריסת מסך, אתם צריכים להגדיר מזהה ייחודי לכל FragmentContainerView
.
התקשרות למסגרת Android מ-Compose
התכונה 'יצירה' פועלת במסגרת מחלקות Android. לדוגמה, הוא מתארח במחלקות של Android View, כמו Activity
או Fragment
, ועשוי להשתמש במחלקות של Android framework כמו Context
, במשאבי מערכת, ב-Service
או ב-BroadcastReceiver
.
מידע נוסף על משאבי מערכת זמין במאמר משאבים ב-Compose.
רכיב היצירה המוזיקלית
CompositionLocal
מחלקות מאפשרות להעביר נתונים באופן מרומז באמצעות פונקציות שניתנות להרכבה. בדרך כלל מסופק להם ערך בצומת מסוים בעץ של ממשק המשתמש. אפשר להשתמש בערך הזה ברכיבי צאצא שאפשר להרכיב, בלי להצהיר על CompositionLocal
כפרמטר בפונקציה שאפשר להרכיב.
הפונקציה CompositionLocal
משמשת להעברת ערכים לסוגי מסגרות של Android ב-Compose, כמו Context
, Configuration
או View
שבהם קוד ה-Compose מתארח עם LocalContext
, LocalConfiguration
או LocalView
התואמים.
שימו לב שהמחלקות CompositionLocal
מתחילות בקידומת Local
כדי שיהיה קל יותר למצוא אותן באמצעות השלמה אוטומטית בסביבת הפיתוח המשולבת (IDE).
כדי לגשת לערך הנוכחי של CompositionLocal
, משתמשים במאפיין current
שלו. לדוגמה, הקוד הבא מציג הודעת טוסט על ידי העברת LocalContext.current
למתודה Toast.makeToast
.
@Composable fun ToastGreetingButton(greeting: String) { val context = LocalContext.current Button(onClick = { Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show() }) { Text("Greet") } }
דוגמה מלאה יותר מופיעה בקטע מקרה לדוגמה: BroadcastReceivers בסוף המסמך הזה.
אינטראקציות אחרות
אם אין כלי מוגדר לאינטראקציה שאתם צריכים, השיטה המומלצת היא לפעול לפי ההנחיה הכללית של Compose: הנתונים זורמים למטה, האירועים זורמים למעלה (הסבר מפורט יותר מופיע במאמר חשיבה ב-Compose). לדוגמה, הקומפוזבל הזה מפעיל פעילות אחרת:
class OtherInteractionsActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // get data from savedInstanceState setContent { MaterialTheme { ExampleComposable(data, onButtonClick = { startActivity(Intent(this, MyActivity::class.java)) }) } } } } @Composable fun ExampleComposable(data: DataExample, onButtonClick: () -> Unit) { Button(onClick = onButtonClick) { Text(data.title) } }
מקרה לדוגמה: מקלטים לשידורים
כדי להציג דוגמה מציאותית יותר לתכונות שאולי תרצו להעביר או להטמיע ב-Compose, וכדי להדגים את CompositionLocal
ואת תופעות הלוואי, נניח שצריך לרשום BroadcastReceiver
מפונקציה שאפשר להרכיב ממנה ממשק משתמש.
הפתרון משתמש ב-LocalContext
כדי להשתמש בהקשר הנוכחי, וב-rememberUpdatedState
וב-DisposableEffect
לתופעות לוואי.
@Composable fun SystemBroadcastReceiver( systemAction: String, onSystemEvent: (intent: Intent?) -> Unit ) { // Grab the current context in this part of the UI tree val context = LocalContext.current // Safely use the latest onSystemEvent lambda passed to the function val currentOnSystemEvent by rememberUpdatedState(onSystemEvent) // If either context or systemAction changes, unregister and register again DisposableEffect(context, systemAction) { val intentFilter = IntentFilter(systemAction) val broadcast = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { currentOnSystemEvent(intent) } } context.registerReceiver(broadcast, intentFilter) // When the effect leaves the Composition, remove the callback onDispose { context.unregisterReceiver(broadcast) } } } @Composable fun HomeScreen() { SystemBroadcastReceiver(Intent.ACTION_BATTERY_CHANGED) { batteryStatus -> val isCharging = /* Get from batteryStatus ... */ true /* Do something if the device is charging */ } /* Rest of the HomeScreen */ }
השלבים הבאים
אחרי שהסברנו על ממשקי ה-API של יכולת פעולה הדדית כשמשתמשים ב-Compose ב-Views ולהפך, כדאי לעיין בדף שיקולים נוספים כדי לקבל מידע נוסף.
מומלץ
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- שיקולים נוספים
- תופעות לוואי ב-Compose
- נתונים בהיקף מקומי עם CompositionLocal