Nhiều ứng dụng cần có khả năng điều khiển chính xác nội dung được vẽ trên màn hình. Việc này có thể đơn giản như đặt một hộp hoặc một vòng tròn trên màn hình ở đúng vị trí, hoặc có thể là sự sắp xếp chi tiết các thành phần đồ hoạ theo nhiều kiểu.
Thao tác vẽ cơ bản bằng đối tượng sửa đổi và DrawScope
Cách chính để vẽ nội dung tuỳ chỉnh nào đó trong Compose là sử dụng đối tượng sửa đổi, chẳng hạn như Modifier.drawWithContent
, Modifier.drawBehind
và Modifier.drawWithCache
.
Ví dụ: để vẽ một nội dung nào đó phía sau thành phần kết hợp, bạn có thể sử dụng đối tượng sửa đổi drawBehind
để bắt đầu thực thi các lệnh vẽ:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
Nếu tất cả những gì bạn cần là một thành phần kết hợp để vẽ, thì bạn có thể sử dụng thành phần kết hợp Canvas
. Thành phần kết hợp Canvas
là một trình bao bọc tiện lợi xung quanh Modifier.drawBehind
. Bạn đặt Canvas
trong bố cục theo cách tương tự như cách bạn thực hiện cho bất kỳ thành phần trên giao diện người dùng nào khác trong Compose. Trong Canvas
, bạn có thể vẽ các thành phần có quyền điều khiển chính xác về kiểu và vị trí của các thành phần đó.
Tất cả các đối tượng sửa đổi của thao tác vẽ đều hiển thị DrawScope
, một môi trường vẽ theo phạm vi duy trì trạng thái riêng. Điều này cho phép bạn đặt các tham số cho một nhóm gồm các thành phần đồ hoạ. DrawScope
cung cấp một số trường hữu ích, như size
, đối tượng Size
giúp xác định kích thước hiện tại của DrawScope
.
Để vẽ một nội dung nào đó, bạn có thể sử dụng một trong nhiều hàm vẽ trên DrawScope
. Ví dụ: mã sau đây sẽ vẽ một hình chữ nhật ở góc trên cùng bên trái màn hình:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F drawRect( color = Color.Magenta, size = canvasQuadrantSize ) }
Để tìm hiểu thêm về nhiều đối tượng sửa đổi của thao tác vẽ, vui lòng xem tài liệu về Đối tượng sửa đổi đồ hoạ.
Hệ toạ độ
Để vẽ một nội dung nào đó trên màn hình, bạn cần biết độ lệch (x
và y
) và kích thước của mục. Với nhiều phương thức vẽ trên DrawScope
, vị trí và kích thước sẽ do các giá trị tham số mặc định cung cấp. Các tham số mặc định thường đặt mục ở [0, 0]
trỏ vào canvas và cung cấp size
mặc định lấp đầy toàn bộ vùng vẽ như trong ví dụ trên – bạn có thể thấy hình chữ nhật được đặt ở trên cùng bên trái. Để điều chỉnh kích thước và vị trí của mục, bạn cần biết về hệ toạ độ trong Compose.
Điểm gốc của hệ toạ độ ([0,0]
) là điểm ảnh ở ngoài cùng bên trái trong vùng vẽ. x
tăng khi di chuyển sang phải và y
tăng khi di chuyển xuống dưới.
Ví dụ: nếu muốn vẽ một đường chéo từ góc trên cùng bên phải của vùng canvas đến góc dưới cùng bên trái, bạn có thể sử dụng hàm DrawScope.drawLine()
, đồng thời chỉ định độ lệch bắt đầu và kết thúc bằng vị trí x và y tương ứng:
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 ) }
Các phép biến đổi cơ bản
DrawScope
cung cấp các phép biến đổi để thay đổi vị trí hoặc cách thực thi các lệnh vẽ.
Điều chỉnh theo tỷ lệ
Sử dụng DrawScope.scale()
để tăng kích thước của các thao tác vẽ theo hệ số. Các thao tác như scale()
áp dụng cho mọi thao tác vẽ trong hàm lambda tương ứng. Ví dụ: mã sau đây tăng scaleX
thêm 10 lần và scaleY
thêm 15 lần:
Canvas(modifier = Modifier.fillMaxSize()) { scale(scaleX = 10f, scaleY = 15f) { drawCircle(Color.Blue, radius = 20.dp.toPx()) } }
Dịch chuyển
Sử dụng DrawScope.translate()
để di chuyển các thao tác vẽ lên trên, xuống dưới, sang trái hoặc sang phải. Ví dụ: mã sau đây di chuyển bản vẽ 100 px sang phải và 300 px lên trên:
Canvas(modifier = Modifier.fillMaxSize()) { translate(left = 100f, top = -300f) { drawCircle(Color.Blue, radius = 200.dp.toPx()) } }
Xoay
Sử dụng DrawScope.rotate()
để xoay các thao tác vẽ quanh điểm chuyển đổi. Ví dụ: mã sau đây xoay hình chữ nhật một góc 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 ) } }
Phần lồng ghép
Sử dụng DrawScope.inset()
để điều chỉnh các tham số mặc định của DrawScope
hiện tại, thay đổi ranh giới vẽ và theo đó dịch chuyển bản vẽ:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F inset(horizontal = 50f, vertical = 30f) { drawRect(color = Color.Green, size = canvasQuadrantSize) } }
Mã này sẽ thêm khoảng đệm vào các lệnh vẽ một cách hiệu quả:
Nhiều phép biến đổi
Để áp dụng nhiều phép biến đổi cho các bản vẽ, hãy sử dụng hàm DrawScope.withTransform()
. Hàm này sẽ tạo và áp dụng một phép biến đổi giúp kết hợp mọi thay đổi mà bạn muốn. Việc sử dụng withTransform()
hiệu quả hơn việc tạo các lệnh gọi lồng nhau cho các phép biến đổi riêng lẻ, vì bạn có thể thực hiện mọi phép biến đổi trong một thao tác duy nhất. Khi đó, Compose sẽ không cần tính toán và lưu lại từng phép biến đổi lồng nhau nữa.
Ví dụ: Mã sau đây áp dụng cho cả quá trình dịch chuyển và xoay đối với hình chữ nhật:
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 ) } }
Thao tác vẽ phổ biến
Vẽ văn bản
Để vẽ văn bản trong Compose, thông thường, bạn có thể dùng thành phần kết hợp Text
. Tuy nhiên, nếu đang ở trong DrawScope
hoặc nếu muốn vẽ văn bản theo cách thủ công bằng chế độ tuỳ chỉnh, thì bạn có thể sử dụng phương thức DrawScope.drawText()
.
Để vẽ văn bản, hãy tạo một TextMeasurer
bằng rememberTextMeasurer
rồi gọi drawText
bằng trình đo lường:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }
Đo lường văn bản
Thao tác vẽ văn bản hoạt động hơi khác so với các lệnh vẽ khác. Thông thường, bạn cung cấp kích thước (chiều rộng và chiều cao) cho lệnh vẽ để vẽ hình dạng/hình ảnh. Đối với văn bản, có một vài tham số giúp kiểm soát kích thước của văn bản được hiển thị, chẳng hạn như kích thước phông chữ, phông chữ, dấu gạch nối và khoảng cách chữ cái.
Với Compose, bạn có thể dùng TextMeasurer
để truy cập vào kích thước văn bản được đo lường, tuỳ thuộc vào các yếu tố ở trên. Nếu muốn vẽ nền phía sau văn bản, bạn có thể sử dụng thông tin đã đo lường để biết kích thước của vùng văn bản:
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() )
Đoạn mã này tạo ra nền màu hồng trên văn bản:
Điều chỉnh các quy tắc ràng buộc, kích thước phông chữ hoặc bất kỳ thuộc tính nào ảnh hưởng đến kết quả kích thước đo lường trong một kích thước mới được báo cáo. Bạn có thể đặt kích thước cố định cho cả width
và height
, sau đó văn bản sẽ tuân theo tập hợp TextOverflow
. Ví dụ: mã sau đây hiển thị văn bản bằng 1⁄3 chiều cao và 1⁄3 chiều rộng của vùng thành phần kết hợp và đặt TextOverflow
thành 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() )
Giờ đây, văn bản được vẽ trong các điều kiện ràng buộc có dấu ba chấm ở cuối:
Vẽ hình ảnh
Để vẽ ImageBitmap
bằng DrawScope
, hãy tải hình ảnh lên bằng ImageBitmap.imageResource()
rồi gọi drawImage
:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })
Vẽ các hình dạng cơ bản
Có nhiều hàm vẽ hình dạng trên DrawScope
. Để vẽ một hình dạng, hãy dùng một trong các hàm vẽ định sẵn, chẳng hạn như drawCircle
:
val purpleColor = Color(0xFFBA68C8) Canvas( modifier = Modifier .fillMaxSize() .padding(16.dp), onDraw = { drawCircle(purpleColor) } )
API |
Đầu ra |
Vẽ đường dẫn
Đường dẫn là một loạt các lệnh toán học dẫn đến một thao tác vẽ sau khi được thực thi. DrawScope
có thể vẽ một đường dẫn bằng phương thức DrawScope.drawPath()
.
Ví dụ: giả sử bạn muốn vẽ một hình tam giác. Bạn có thể tạo đường dẫn bằng các hàm như lineTo()
và moveTo()
sử dụng kích thước của vùng vẽ.
Sau đó, hãy gọi drawPath()
bằng đường dẫn mới tạo này để có hình tam giác.
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() )
Truy cập vào đối tượng Canvas
Với DrawScope
, bạn không có quyền truy cập trực tiếp vào đối tượng Canvas
. Bạn có thể sử dụng DrawScope.drawIntoCanvas()
để truy cập ngay vào đối tượng Canvas
mà bạn có thể gọi hàm trên đối tượng đó.
Ví dụ: nếu có Drawable
tuỳ chỉnh mà bạn muốn vẽ vào canvas, bạn có thể truy cập vào canvas và gọi Drawable#draw()
, truyền vào đối tượng 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() )
Tìm hiểu thêm
Để biết thêm thông tin về tính năng Vẽ trong Compose, hãy xem các tài nguyên sau:
- Đối tượng sửa đổi đồ hoạ – Tìm hiểu về các loại đối tượng sửa đổi thao tác vẽ.
- Bút vẽ – Tìm hiểu cách tuỳ chỉnh việc vẽ nội dung.
- Custom Layouts and Graphics in Compose (Đồ hoạ và bố cục tuỳ chỉnh trong Compose) – Hội nghị Nhà phát triển Android năm 2022 – Tìm hiểu cách xây dựng một giao diện người dùng tuỳ chỉnh trong Compose bằng Bố cục và Đồ hoạ.
- JetLagged Sample (Mẫu JetLagged) – Mẫu trong Compose trình bày cách vẽ một biểu đồ tuỳ chỉnh.
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Đối tượng sửa đổi đồ hoạ
- Đồ hoạ trong Compose
- Căn chỉnh dòng trong Jetpack Compose