Làm mờ trong Compose

Hiệu ứng làm mờ giúp làm dịu các chi tiết hình ảnh, tạo độ sâu trường ảnh và thu hút sự chú ý vào các phần tử trên giao diện người dùng ở nền trước. Trong Jetpack Compose, hãy sử dụng Modifier.blur để làm mờ nội dung được vẽ bên trong một thành phần kết hợp, bao gồm cả hình ảnh, hình dạng, văn bản và vùng chứa bố cục. Việc áp dụng Modifier.blur sẽ kết xuất thành phần kết hợp thành một lớp đồ hoạ riêng biệt.

Bên trái: hình ảnh gốc. Giữa: hình ảnh có hiệu ứng làm mờ đồng đều trên toàn bộ bề mặt. Bên phải: hình ảnh có hiệu ứng làm mờ tăng dần, sắc nét ở trên cùng và tăng dần về phía dưới.
Hình 1. Bên trái: hình ảnh gốc. Giữa: hình ảnh có hiệu ứng làm mờ đồng đều trên toàn bộ bề mặt. Bên phải: hình ảnh có hiệu ứng làm mờ tăng dần, sắc nét ở trên cùng và tăng dần về phía dưới.

Tuỳ thuộc vào mục tiêu thiết kế, bạn có thể thay đổi độ mờ theo hai cách:

  • Làm mờ đồng đều: Áp dụng bán kính làm mờ không đổi trên toàn bộ composable, đồng đều trên cả hai trục hoặc với bán kính ngang và dọc độc lập (radiusX, radiusY).
  • Làm mờ tăng dần: Thay đổi bán kính làm mờ theo không gian trên composable bằng cách sử dụng dải chuyển màu BlurRadiusSpec hoặc Shader tuỳ chỉnh.

Áp dụng hiệu ứng làm mờ đồng đều

Để áp dụng hiệu ứng làm mờ không đổi trên toàn bộ thành phần kết hợp, hãy truyền bán kính Dp đến Modifier.blur. Truyền một giá trị radius duy nhất để làm mờ nội dung đồng đều dọc theo cả trục ngang (X) và trục dọc (Y):

@Composable
fun UniformBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                radius = 8.dp,
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp)),
            ),
    )
}

Một chú chó được làm mờ đồng đều trên cả trục ngang và trục dọc.
Hình 2. Một chú chó được làm mờ đồng đều trên cả trục ngang và trục dọc.

Để tạo hiệu ứng làm mờ chuyển động có hướng, hãy truyền các giá trị radiusX và radiusY riêng biệt đến Modifier.blur. Cả radiusX và radiusY đều phải lớn hơn 0.dp để áp dụng hiệu ứng làm mờ, như trong ví dụ sau:

@Composable
fun DirectionalBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                radiusX = 10.dp,
                radiusY = 2.dp,
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp)),
            ),
    )
}

Một chú chó có hiệu ứng làm mờ chuyển động ngang mạnh.
Hình 3. Hình ảnh vuông của một chú chó có hiệu ứng làm mờ chuyển động ngang mạnh.

Áp dụng hiệu ứng làm mờ tăng dần

Hiệu ứng làm mờ tăng dần sẽ thay đổi bán kính làm mờ trên một composable, tạo ra hiệu ứng chuyển đổi mượt mà giữa các vùng sắc nét và vùng mờ.

Truyền BlurRadiusSpec đến Modifier.blur. Ví dụ: sử dụng BlurRadiusSpec.verticalGradient với startRadius = 0.dp và endRadius = 6.dp để giữ cho phần trên cùng của hình ảnh sắc nét trong khi làm mờ dần về phía dưới, như trong ví dụ sau:

@Composable
fun ProgressiveBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                // Sharp at the top (0.dp), progressively blurred toward the bottom (6.dp)
                blurRadiusSpec = BlurRadiusSpec.verticalGradient(
                    startRadius = 0.dp,
                    endRadius = 6.dp,
                ),
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp)),
            ),
    )
}

Một chú chó có phần trên sắc nét và mờ dần về phía dưới.
Hình 4. Hình ảnh một chú chó sắc nét ở phía trên và mờ dần về phía dưới.

Chỉ định độ dốc làm mờ bằng BlurRadiusSpec

Trong BlurRadiusSpec, các phép đo được đặt trong Dp và tự động điều chỉnh theo kích thước và mật độ hiển thị của lớp khi được vẽ. Độ mờ thay đổi theo không gian được giới hạn ở mức 150 pixel sau khi chuyển đổi, trong khi BlurRadiusSpec.uniform không có giới hạn.

Bảng sau đây liệt kê các hàm khởi tạo có sẵn trên BlurRadiusSpec:

BlurRadiusSpec nhà máy Mô tả
BlurRadiusSpec.verticalGradient Thay đổi mượt mà bán kính làm mờ theo chiều dọc từ trên cùng (0f) xuống dưới cùng (1f) trên toàn bộ lớp.
BlurRadiusSpec.horizontalGradient Thay đổi mượt mà bán kính làm mờ theo chiều ngang từ cạnh trái (0f) sang cạnh phải (1f).
BlurRadiusSpec.linearGradient Áp dụng hiệu ứng chuyển đổi làm mờ có hướng dọc theo một đường thẳng nối các toạ độ DpOffset cụ thể.
BlurRadiusSpec.radialGradient Trải rộng hiệu ứng làm mờ ra ngoài từ một tiêu điểm về phía ranh giới fallOffRadius.
BlurRadiusSpec.uniform Áp dụng bán kính làm mờ đồng đều trên toàn bộ lớp.
BlurRadiusSpec.shader Sử dụng kênh alpha của Shader tuỳ chỉnh để kiểm soát và điều chỉnh tỷ lệ maxRadius ở mỗi pixel.

Tuỳ chỉnh mức độ phân bổ hiệu ứng làm mờ bằng BlurStop

Hiệu ứng làm mờ chuyển màu chuẩn nội suy tuyến tính giữa 0f và 1f. Để tuỳ chỉnh mức độ phân bổ hiệu ứng làm mờ trên một bề mặt, chẳng hạn như làm mờ nhiều cạnh hoặc giữ cho phần giữa hoàn toàn sắc nét, hãy truyền một List<BlurStop> chứa từ 2 đến 16 mục nhập BlurStop đến verticalGradient, horizontalGradient, linearGradient hoặc radialGradient. Xác định những thông tin sau cho mỗi mục nhập BlurStop:

  • fraction: Vị trí tương đối dọc theo dải chuyển màu từ 0.0f đến 1.0f. Các điểm dừng được sắp xếp tự động theo phân số.
  • radius: Bán kính làm mờ tính bằng Dp được áp dụng tại vị trí phân số đó.

Ví dụ: 4 điểm dừng làm mờ các cạnh trên và dưới của hình ảnh trong khi vẫn giữ cho phần giữa hoàn toàn sắc nét, như trong ví dụ sau:

@Composable
fun MultiStopBlurExample() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(
                // Blurred at the top and bottom edges, sharp in the middle (0.3f..0.7f)
                blurRadiusSpec = BlurRadiusSpec.verticalGradient(
                    stops = listOf(
                        BlurStop(fraction = 0.0f, radius = 20.dp),
                        BlurStop(fraction = 0.3f, radius = 0.dp),
                        BlurStop(fraction = 0.7f, radius = 0.dp),
                        BlurStop(fraction = 1.0f, radius = 20.dp),
                    ),
                ),
                edgeTreatment = BlurredEdgeTreatment.Unbounded,
            ),
    )
}

Một chú chó có các cạnh trên và dưới bị làm mờ, trong khi dải ngang ở giữa vẫn được lấy nét rõ ràng.
Hình 5. Hình ảnh một chú chó có các cạnh trên và dưới bị làm mờ, trong khi dải ngang ở giữa vẫn được lấy nét rõ ràng.

Định cấu hình thuộc tính lớp bằng BlurScope

Thay vì truyền trực tiếp blurRadiusSpec, bạn có thể truyền một khối cấu hình đến Modifier.blur { ... }. Khối này chạy bên trong BlurScope, giúp bạn truy cập trực tiếp vào mật độ bố cục và các thuộc tính sau:

  • size: DpSize: Chiều rộng và chiều cao đo được của lớp làm mờ trong Dp, xác định không gian toạ độ cho hình học chuyển màu.
  • blurRadiusSpec: BlurRadiusSpec: Cấu hình bán kính làm mờ trên toàn bộ bề mặt. Mặc định là BlurRadiusSpec.uniform(0.dp) (không làm mờ).
  • edgeTreatment: BlurredEdgeTreatment: Chiến lược dùng để lấy mẫu và cắt các pixel bên ngoài ranh giới nội dung. Giá trị mặc định là BlurredEdgeTreatment.Rectangle.
  • alpha: Float: Độ mờ của lớp làm mờ trong phạm vi 0f..1f. Giá trị mặc định là 1f.

Vì khối BlurScope chạy trong giai đoạn lớp đồ hoạ, sau khi đo lường và bố cục, nên bạn có thể tính toán hình học chuyển màu từ size mà không cần kích hoạt quá trình kết hợp lại.

Kiểm soát việc cắt bớt cạnh bằng BlurredEdgeTreatment

Vì việc làm mờ lấy mẫu các pixel lân cận trong bán kính làm mờ, nên kết quả làm mờ sẽ vượt quá giới hạn nội dung nguyên gốc ban đầu theo bán kính làm mờ. BlurredEdgeTreatment xác định cách lấy mẫu các pixel bên ngoài giới hạn ban đầu và liệu kết quả có được cắt theo một hình dạng hay không.

BlurredEdgeTreatment hoạt động với cả hiệu ứng làm mờ đồng nhất và tăng dần:

BlurredEdgeTreatment Hành vi Đầu ra
BlurredEdgeTreatment.Rectangle (mặc định) Cắt kết quả làm mờ theo giới hạn hình chữ nhật của nội dung nguyên gốc và lấy mẫu các pixel cạnh gần nhất (TileMode.Clamp). Hình ảnh chú chó bị làm mờ được cắt theo ranh giới hình chữ nhật sắc nét.
BlurredEdgeTreatment(shape) Cắt kết quả làm mờ theo Shape được chỉ định (chẳng hạn như RoundedCornerShape(8.dp)) và lấy mẫu các pixel cạnh gần nhất (TileMode.Clamp). Giữ cho kết quả làm mờ sắc nét ở ranh giới hình dạng mà không bị tràn ra ngoài ranh giới ban đầu. Hình ảnh chú chó bị làm mờ được cắt thành hình góc bo tròn có các cạnh sắc nét.
BlurredEdgeTreatment.Unbounded Không cắt kết quả làm mờ (TileMode.Decal). Các pixel nằm ngoài giới hạn nội dung sẽ lấy mẫu màu đen trong suốt, khiến các cạnh bên ngoài của hình ảnh có vẻ mờ và nhoè ra ngoài giới hạn ban đầu. Hình ảnh chú chó bị làm mờ có các cạnh mờ dần một cách nhẹ nhàng ra ngoài ranh giới ban đầu.

Để xem cách các API này kết hợp trong các mẫu giao diện người dùng hoàn chỉnh, chẳng hạn như làm mờ các cạnh của nội dung cuộn, làm nổi bật tiêu điểm hoặc che mờ bằng chương trình đổ bóng tuỳ chỉnh, hãy xem phần Các trường hợp sử dụng làm mờ phổ biến.