แอปจำนวนมากต้องควบคุมสิ่งที่วาดบน บนหน้าจอ ซึ่งอาจจะมีขนาดเล็กพอๆ กับการใส่กล่องหรือวงกลมบนหน้าจอ อยู่ในตำแหน่งที่เหมาะสม หรืออาจเป็นการจัดเรียงกราฟิกที่ละเอียดประณีต องค์ประกอบในสไตล์ต่างๆ มากมาย
ภาพวาดพื้นฐานพร้อมตัวปรับแต่งและ DrawScope
วิธีหลักในการวาดสิ่งที่กำหนดเองในเครื่องมือเขียนคือการใช้ตัวแก้ไข เช่น Modifier.drawWithContent
, Modifier.drawBehind
และ Modifier.drawWithCache
เช่น หากต้องการวาดสิ่งที่อยู่หลังคอมโพสิเบิล ให้ใช้ตัวแก้ไข drawBehind
เพื่อเริ่มดำเนินการตามคำสั่งวาดภาพ
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
หากต้องการแค่ Composable ที่สามารถวาดได้ คุณสามารถใช้
Canvas
Composable คอมโพสิเบิล Canvas
เป็นไวลด์การ์ดที่สะดวกสำหรับ Modifier.drawBehind
วาง Canvas
ในเลย์เอาต์เช่นเดียวกับที่วางองค์ประกอบ UI อื่นๆ ของ 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
ซึ่งแสดงเต็มพื้นที่ภาพวาด ดังตัวอย่างด้านบน คุณจะเห็น
ให้สี่เหลี่ยมผืนผ้าอยู่ในตำแหน่งด้านบนซ้าย หากต้องการปรับขนาดและตำแหน่งของ
รายการของคุณ คุณจำเป็นต้องเข้าใจระบบพิกัดในการเขียน
จุดเริ่มต้นของระบบพิกัด ([0,0]
) อยู่ที่พิกเซลซ้ายสุดใน
พื้นที่วาดรูป x
เพิ่มขึ้นเมื่อเคลื่อนที่ไปทางขวา และ y
เพิ่มขึ้นเมื่อเคลื่อนที่
ลง
![ตารางกริดแสดงระบบพิกัดซึ่งแสดงด้านซ้ายบน [0, 0] และมุมขวาล่าง [ความกว้าง, ความสูง]](https://developer.android.google.cn/static/develop/ui/compose/images/graphics/introduction/compose_coordinate_system_drawing.png?hl=th)
เช่น หากต้องการวาดเส้นทแยงมุมจากมุมขวาบนของพื้นที่แคนวาสไปยังมุมซ้ายล่าง คุณสามารถใช้ฟังก์ชัน 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()
เพื่อเพิ่มขนาดของการดำเนินการวาดภาพขึ้นอีก 1 ปัจจัย การดำเนินการ เช่น
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()
เพื่อหมุนการดำเนินการวาดภาพรอบจุด Pivot ตัวอย่างเช่น พารามิเตอร์
โค้ดต่อไปนี้หมุนสี่เหลี่ยมผืนผ้า 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
เพื่อใช้ทั้งการหมุนและการแปล โดยหมุนสี่เหลี่ยมผืนผ้าและเลื่อนไปทางซ้ายการดำเนินการวาดทั่วไป
วาดข้อความ
หากต้องการวาดข้อความในเครื่องมือเขียน โดยทั่วไปคุณจะใช้คอมโพสิเบิล Text
ได้ อย่างไรก็ตาม
หากคุณอยู่ใน DrawScope
หรือคุณต้องการเขียนข้อความด้วยตนเองด้วย
ที่กำหนดเอง คุณสามารถใช้
DrawScope.drawText()
หากต้องการวาดข้อความ ให้สร้าง TextMeasurer
โดยใช้ rememberTextMeasurer
และเรียกใช้ drawText
โดยใช้เครื่องมือวัดดังนี้
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }

วัดข้อความ
การวาดข้อความจะทำงานแตกต่างจากคำสั่งวาดอื่นๆ เล็กน้อย โดยปกติแล้ว คุณจะต้องกำหนดขนาด (ความกว้างและความสูง) ให้กับคำสั่งวาดภาพเพื่อวาดรูปทรง/รูปภาพ สำหรับข้อความ จะมีพารามิเตอร์ 2-3 รายการที่ควบคุมขนาดของข้อความที่แสดงผล เช่น ขนาดแบบอักษร แบบอักษร ตัวห้อย และระยะห่างระหว่างตัวอักษร
เมื่อใช้ฟีเจอร์เขียน คุณจะใช้ 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
ที่กำหนดเองซึ่งต้องการวาดลงบน
Canvas คุณสามารถเข้าถึง Canvas และเรียก 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 - ดูวิธีสร้าง UI ที่กําหนดเองใน Compose ด้วยเลย์เอาต์และกราฟิก
- JetLagged Sample - Compose Sample ที่แสดงวิธีวาดกราฟที่กำหนดเอง
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ตัวปรับแต่งกราฟิก
- กราฟิกในเครื่องมือเขียน
- เส้นการจัดตำแหน่งใน Jetpack Compose