אפשר לכלול היררכיית תצוגה של Android בממשק משתמש של Compose. הגישה הזו שימושית במיוחד אם רוצים להשתמש ברכיבי ממשק משתמש שעדיין לא זמינים ב-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 (LazyColumn, LazyRow,
Pager וכו'), כדאי להשתמש ב-AndroidView בעומס יתר שהוצג בגרסה 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() } ) } } }
מקטעים (fragments) ב-Compose
משתמשים ב-AndroidFragment composable כדי להוסיף Fragment ב-Compose.
ל-AndroidFragment יש טיפול ספציפי במקטעים, כמו הסרת המקטע כשהפונקציה הניתנת להרכבה יוצאת מההרכבה.
כדי לכלול מקטע, משתמשים בקוד AndroidFragment קומפוזבילי. מעבירים מחלקה Fragment אל AndroidFragment, ואז מתווסף מופע של המחלקה ישירות אל הקומפוזיציה. AndroidFragment גם מספק אובייקט fragmentState כדי ליצור את AndroidFragment עם מצב נתון, arguments כדי להעביר אותו אל הפריט החדש, וקריאה חוזרת (callback) של onUpdate שמספקת את הפריט מהקומפוזיציה. בדומה לרכיבים קומפוזביליים מובנים רבים אחרים, AndroidFragment מקבל פרמטר Modifier שאפשר להשתמש בו, למשל, כדי להגדיר את המיקום שלו ברכיב הקומפוזבילי ברמת ההורה.
כדי להתקשר אל AndroidFragment ב'כתיבת אימייל':
@Composable fun FragmentInComposeExample() { AndroidFragment<MyFragment>() }
התקשרות למסגרת Android מ-Compose
Compose פועלת במסגרת המחלקות של Android. לדוגמה, הוא מתארח במחלקות של Android View, כמו Activity או Fragment, ועשוי להשתמש במחלקות של Android framework כמו Context, במשאבי מערכת, ב-Service או ב-BroadcastReceiver.
מידע נוסף על משאבי מערכת זמין במאמר משאבים ב-Compose.
רכיב היצירה המוזיקלית
CompositionLocal
classes מאפשרים להעביר נתונים באופן מרומז דרך פונקציות הניתנות להגדרה. בדרך כלל הם מסופקים עם ערך בצומת מסוים בעץ ממשק המשתמש. אפשר להשתמש בערך הזה ברכיבי צאצא שאפשר להרכיב, בלי להצהיר על 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") } }
דוגמה מלאה יותר מופיעה בקטע Case Study: 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 של Interoperability כשמשתמשים ב-Compose ב-Views ולהפך, כדאי לעיין בדף שיקולים נוספים כדי לקבל מידע נוסף.
מומלץ בשבילך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- שיקולים נוספים
- תופעות לוואי בפיתוח נייטיב
- נתונים בהיקף מקומי עם CompositionLocal