Trong Compose, đối tượng Painter
được dùng để thể hiện nội dung nào đó có thể vẽ (thay thế cho các API Drawable
được xác định trong Android) và tạo tác động đến hoạt động đo lường cùng với bố cục của thành phần kết hợp tương ứng đang sử dụng đối tượng đó. BitmapPainter
lấy ImageBitmap
có khả năng vẽ Bitmap
trên màn hình.
Đối với hầu hết các trường hợp sử dụng, việc sử dụng painterResource()
ở trên sẽ trả về đúng Painter cho thành phần (tức là BitmapPainter
hoặc VectorPainter
). Để biết thêm thông tin về sự khác biệt giữa 2 loại này, hãy đọc phần ImageBitmap so với ImageVector.
Painter
khác với DrawModifier
ở chỗ khi được dùng sẽ vẽ một cách nghiêm ngặt trong giới hạn được cấp và hoàn toàn không tác động đến hoạt động đo lường hoặc bố cục của thành phần kết hợp.
Để tạo một Painter tuỳ chỉnh, hãy mở rộng lớp Painter
và triển khai phương thức onDraw
. Phương thức này cho phép truy cập vào DrawScope
để vẽ các đồ hoạ tuỳ chỉnh. Bạn cũng có thể ghi đè intrinsicSize
dùng để tạo tác động đến Thành phần kết hợp có ở trong:
class OverlayImagePainter constructor( private val image: ImageBitmap, private val imageOverlay: ImageBitmap, private val srcOffset: IntOffset = IntOffset.Zero, private val srcSize: IntSize = IntSize(image.width, image.height), private val overlaySize: IntSize = IntSize(imageOverlay.width, imageOverlay.height) ) : Painter() { private val size: IntSize = validateSize(srcOffset, srcSize) override fun DrawScope.onDraw() { // draw the first image without any blend mode drawImage( image, srcOffset, srcSize, dstSize = IntSize( this@onDraw.size.width.roundToInt(), this@onDraw.size.height.roundToInt() ) ) // draw the second image with an Overlay blend mode to blend the two together drawImage( imageOverlay, srcOffset, overlaySize, dstSize = IntSize( this@onDraw.size.width.roundToInt(), this@onDraw.size.height.roundToInt() ), blendMode = BlendMode.Overlay ) } /** * Return the dimension of the underlying [ImageBitmap] as it's intrinsic width and height */ override val intrinsicSize: Size get() = size.toSize() private fun validateSize(srcOffset: IntOffset, srcSize: IntSize): IntSize { require( srcOffset.x >= 0 && srcOffset.y >= 0 && srcSize.width >= 0 && srcSize.height >= 0 && srcSize.width <= image.width && srcSize.height <= image.height ) return srcSize } }
Bây giờ, chúng ta đã có Painter
tuỳ chỉnh nên có thể phủ bất kỳ hình ảnh nào lên hình ảnh nguồn như sau:
val rainbowImage = ImageBitmap.imageResource(id = R.drawable.rainbow) val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) val customPainter = remember { OverlayImagePainter(dogImage, rainbowImage) } Image( painter = customPainter, contentDescription = stringResource(id = R.string.dog_content_description), contentScale = ContentScale.Crop, modifier = Modifier.wrapContentSize() )
Bạn có thể xem kết quả kết hợp 2 hình ảnh này bằng một Painter tuỳ chỉnh ở bên dưới:
Bạn cũng có thể sử dụng Painter tuỳ chỉnh với Modifier.paint(customPainter)
để vẽ nội dung lên trên thành phần kết hợp như sau:
val rainbowImage = ImageBitmap.imageResource(id = R.drawable.rainbow) val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) val customPainter = remember { OverlayImagePainter(dogImage, rainbowImage) } Box( modifier = Modifier.background(color = Color.Gray) .padding(30.dp) .background(color = Color.Yellow) .paint(customPainter) ) { /** intentionally empty **/ }
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- ImageBitmap và ImageVector {:#bitmap-vs-vector}
- Đồ hoạ trong Compose
- Hình ảnh xuất hiện khi đang tải {:#loading-images}