אפליקציות רבות צריכות להיות מסוגלות לשלוט בדיוק במה שמוצג במסך. יכול להיות שזה יהיה פשוט כמו הצבת תיבה או עיגול במסך במקום הנכון, או סידור מורכב של אלמנטים גרפיים בסגנונות שונים.
שרטוט בסיסי עם משנים ו-DrawScope
הדרך העיקרית לצייר משהו בהתאמה אישית ב-Compose היא באמצעות שימוש במאפייני שינוי, כמו Modifier.drawWithContent
, Modifier.drawBehind
ו-Modifier.drawWithCache
.
לדוגמה, כדי לצייר משהו מאחורי רכיב ה-Composable, אפשר להשתמש במאפיין drawBehind
כדי להתחיל להריץ פקודות ציור:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
אם אתם צריכים רק קומפוזיציה שמציירת, אתם יכולים להשתמש בקומפוזיציה Canvas
. הפונקציה Canvas
היא עטיפה נוחה של Modifier.drawBehind
. ממקמים את Canvas
בפריסה באותו אופן שבו ממקמים כל רכיב אחר בממשק המשתמש של Compose. בתוך התג Canvas
, אפשר לצייר אלמנטים עם שליטה מדויקת בסגנון ובמיקום שלהם.
כל משני הציור חושפים DrawScope
, סביבת ציור בהיקף מוגבל ששומרת על המצב שלה. כך אפשר להגדיר את הפרמטרים של קבוצת אלמנטים גרפיים. השדה DrawScope
מספק כמה שדות שימושיים, כמו size
, אובייקט Size
שמציין את הממדים הנוכחיים של DrawScope
.
כדי לצייר משהו, אפשר להשתמש באחת מפונקציות הציור הרבות ב-DrawScope
. לדוגמה, הקוד הבא מצייר מלבן בפינה הימנית העליונה של המסך:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F drawRect( color = Color.Magenta, size = canvasQuadrantSize ) }

למידע נוסף על שינויים שונים בשרטוטים, אפשר לעיין במסמכי העזרה בנושא שינויים בגרפיקה.
מערכת קואורדינטות
כדי לצייר משהו על המסך, צריך לדעת את ההיסט (x
ו-y
) ואת הגודל של הפריט. בשיטות רבות של ציור ב-DrawScope
, המיקום והגודל מסופקים על ידי ערכי פרמטרים שמוגדרים כברירת מחדל. פרמטרי ברירת המחדל בדרך כלל ממקמים את הפריט בנקודה [0, 0]
באזור הציור, ומספקים size
כברירת מחדל שממלא את כל אזור הציור, כמו בדוגמה שלמעלה – אפשר לראות שהמלבן ממוקם בפינה הימנית העליונה. כדי לשנות את הגודל והמיקום של הפריט, צריך להבין את מערכת הקואורדינטות ב-Compose.
המקור של מערכת הקואורדינטות ([0,0]
) נמצא בפיקסל הימני העליון באזור הציור. הערך של x
עולה ככל שמתקדמים ימינה, והערך של y
עולה ככל שמתקדמים למטה.
![רשת שמציגה את מערכת הקואורדינטות, עם הפינה הימנית העליונה [0, 0] והפינה השמאלית התחתונה [width, height]](https://developer.android.com/static/develop/ui/compose/images/graphics/introduction/compose_coordinate_system_drawing.png?hl=he)
לדוגמה, אם רוצים לצייר קו אלכסוני מהפינה השמאלית העליונה של אזור הקנבס לפינה הימנית התחתונה, אפשר להשתמש בפונקציה DrawScope.drawLine()
ולציין היסט של נקודת ההתחלה ונקודת הסיום עם מיקומי ה-x וה-y המתאימים:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawLine( start = Offset(x = canvasWidth, y = 0f), end = Offset(x = 0f, y = canvasHeight), color = Color.Blue ) }
טרנספורמציות בסיסיות
DrawScope
מציע טרנספורמציות כדי לשנות את המקום או את האופן שבו פקודות הציור מבוצעות.
קנה המידה
משתמשים ב-DrawScope.scale()
כדי להגדיל את הגודל של פעולות השרטוט בפקטור מסוים. פעולות כמו
scale()
חלות על כל פעולות הציור בתוך פונקציית ה-lambda המתאימה. לדוגמה, הקוד הבא מגדיל את scaleX
פי 10 ואת scaleY
פי 15:
Canvas(modifier = Modifier.fillMaxSize()) { scale(scaleX = 10f, scaleY = 15f) { drawCircle(Color.Blue, radius = 20.dp.toPx()) } }

תרגום
משתמשים ב-DrawScope.translate()
כדי להזיז את פעולות הציור למעלה, למטה, שמאלה או ימינה. לדוגמה, הקוד הבא מעביר את הציור 100 פיקסלים ימינה ו-300 פיקסלים למעלה:
Canvas(modifier = Modifier.fillMaxSize()) { translate(left = 100f, top = -300f) { drawCircle(Color.Blue, radius = 200.dp.toPx()) } }

סיבוב
משתמשים ב-DrawScope.rotate()
כדי לסובב את פעולות השרטוט סביב נקודת ציר. לדוגמה, הקוד הבא מסובב מלבן ב-45 מעלות:
Canvas(modifier = Modifier.fillMaxSize()) { rotate(degrees = 45F) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }

rotate()
כדי להחיל סיבוב על היקף הציור הנוכחי, שמסובב את המלבן ב-45 מעלות.
מוטמע
משתמשים ב-DrawScope.inset()
כדי לשנות את פרמטרי ברירת המחדל של DrawScope
הנוכחי, לשנות את גבולות הציור ולתרגם את הציורים בהתאם:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F inset(horizontal = 50f, vertical = 30f) { drawRect(color = Color.Green, size = canvasQuadrantSize) } }
הקוד הזה מוסיף למעשה ריווח פנימי לפקודות הציור:

טרנספורמציות מרובות
כדי להחיל כמה טרנספורמציות על הציורים, משתמשים בפונקציה DrawScope.withTransform()
, שיוצרת ומחילת טרנספורמציה אחת שמשלבת את כל השינויים הרצויים. השימוש ב-withTransform()
יעיל יותר מאשר ביצוע קריאות מקוננות לטרנספורמציות נפרדות, כי כל הטרנספורמציות מתבצעות יחד בפעולה אחת, במקום ש-Compose יצטרך לחשב ולשמור כל אחת מהטרנספורמציות המקוננות.
לדוגמה, הקוד הבא מחיל גם תרגום וגם סיבוב על המלבן:
Canvas(modifier = Modifier.fillMaxSize()) { withTransform({ translate(left = size.width / 5F) rotate(degrees = 45F) }) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }

withTransform
כדי להחיל גם סיבוב וגם הזזה, לסובב את המלבן ולהזיז אותו שמאלה.פעולות נפוצות שקשורות לציור
ציור טקסט
כדי לצייר טקסט ב-Compose, בדרך כלל משתמשים ב-Text
composable. עם זאת, אם אתם נמצאים בDrawScope
או שאתם רוצים לצייר את הטקסט שלכם באופן ידני עם התאמה אישית, אתם יכולים להשתמש בשיטה DrawScope.drawText()
.
כדי לצייר טקסט, יוצרים TextMeasurer
באמצעות rememberTextMeasurer
וקוראים ל-drawText
עם הכלי למדידה:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }

מדידת טקסט
פקודות לציור טקסט פועלות קצת אחרת מפקודות אחרות לציור. בדרך כלל, כשמציינים פקודת ציור, מציינים גם את הגודל (הרוחב והגובה) של הצורה או התמונה שרוצים לצייר. כשמדובר בטקסט, יש כמה פרמטרים שקובעים את הגודל של הטקסט המעובד, כמו גודל הגופן, הגופן, ליגטורות ומרווחים בין אותיות.
כשמשתמשים ב-Compose, אפשר להשתמש ב-TextMeasurer
כדי לקבל גישה לגודל הטקסט שנמדד, בהתאם לגורמים שלמעלה. אם רוצים לצייר רקע מאחורי הטקסט, אפשר להשתמש במידע שנמדד כדי לקבל את גודל האזור שהטקסט תופס:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixedWidth((size.width * 2f / 3f).toInt()), style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
קטע הקוד הזה יוצר רקע ורוד לטקסט:

שינוי האילוצים, גודל הגופן או כל מאפיין שמשפיע על גודל התוצאות יגרום לדיווח על גודל חדש. אפשר להגדיר גודל קבוע גם ל-width
וגם ל-height
, ואז הטקסט יפעל לפי TextOverflow
שהוגדר. לדוגמה, הקוד הבא מציג טקסט בשליש מהגובה ובשליש מהרוחב של האזור שניתן להרכבה, ומגדיר את TextOverflow
ל-TextOverflow.Ellipsis
:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixed( width = (size.width / 3f).toInt(), height = (size.height / 3f).toInt() ), overflow = TextOverflow.Ellipsis, style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
הטקסט מוצג עכשיו באילוצים עם שלוש נקודות בסוף:

TextOverflow.Ellipsis
עם אילוצים קבועים למדידת הטקסט.ציור תמונה
כדי לצייר ImageBitmap
באמצעות DrawScope
, טוענים את התמונה באמצעות
ImageBitmap.imageResource()
ואז קוראים ל-drawImage
:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })

ImageBitmap
ב-Canvas.ציור צורות בסיסיות
יש הרבה פונקציות לציור צורות ב-DrawScope
. כדי לצייר צורה, משתמשים באחת מפונקציות הציור המוגדרות מראש, כמו drawCircle
:
val purpleColor = Color(0xFFBA68C8) Canvas( modifier = Modifier .fillMaxSize() .padding(16.dp), onDraw = { drawCircle(purpleColor) } )
API |
פלט |
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
ציור נתיב
נתיב הוא סדרה של הוראות מתמטיות שמובילות לציור אחרי ההפעלה. DrawScope
יכול לשרטט נתיב באמצעות השיטה DrawScope.drawPath()
.
לדוגמה, נניח שרצית לצייר משולש. אפשר ליצור נתיב באמצעות פונקציות כמו lineTo()
ו-moveTo()
, על סמך הגודל של אזור הציור.
אחר כך, קוראים ל-drawPath()
עם הנתיב החדש שנוצר כדי לקבל משולש.
Spacer( modifier = Modifier .drawWithCache { val path = Path() path.moveTo(0f, 0f) path.lineTo(size.width / 2f, size.height / 2f) path.lineTo(size.width, 0f) path.close() onDrawBehind { drawPath(path, Color.Magenta, style = Stroke(width = 10f)) } } .fillMaxSize() )

Path
בהודעה חדשה.גישה לאובייקט Canvas
ב-DrawScope
, אין לכם גישה ישירה לאובייקט Canvas
. אפשר להשתמש בפונקציה DrawScope.drawIntoCanvas()
כדי לקבל גישה לאובייקט Canvas
עצמו, שאפשר להפעיל עליו פונקציות.
לדוגמה, אם יש לכם Drawable
מותאם אישית שאתם רוצים לצייר על אזור הציור, אתם יכולים לגשת לאזור הציור ולהפעיל את Drawable#draw()
, ולהעביר את האובייקט Canvas
:
val drawable = ShapeDrawable(OvalShape()) Spacer( modifier = Modifier .drawWithContent { drawIntoCanvas { canvas -> drawable.setBounds(0, 0, size.width.toInt(), size.height.toInt()) drawable.draw(canvas.nativeCanvas) } } .fillMaxSize() )

Drawable
.מידע נוסף
למידע נוסף על ציור בכלי הכתיבה, אפשר להיעזר במקורות המידע הבאים:
- משנים של גרפיקה – מידע על סוגים שונים של משנים של ציורים.
- מכחול – כאן מוסבר איך להתאים אישית את הצביעה של התוכן.
- פריסות וגרפיקה בהתאמה אישית ב-Compose – Android Dev Summit 2022 – איך ליצור ממשק משתמש בהתאמה אישית ב-Compose באמצעות פריסות וגרפיקה.
- דוגמה ל-JetLagged – דוגמה ל-Compose שמראה איך ליצור תרשים בהתאמה אישית.
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- משני גרפיקה
- גרפיקה ב-Compose
- קווי יישור ב-Jetpack פיתוח נייטיב