การเบลอใน Compose

เอฟเฟกต์เบลอจะทำให้รายละเอียดภาพดูนุ่มนวลขึ้น สร้างระยะชัดลึกของภาพ และดึงความสนใจไปยังองค์ประกอบ UI ที่อยู่เบื้องหน้า ใน Jetpack Compose ให้ใช้ Modifier.blur เพื่อเบลอเนื้อหาที่วาดภายใน Composable ซึ่งรวมถึงรูปภาพ รูปร่าง ข้อความ และคอนเทนเนอร์เลย์เอาต์ การใช้ Modifier.blur จะแสดงผล Composable เป็นเลเยอร์กราฟิกแยกต่างหาก

ซ้าย: รูปภาพต้นฉบับ ตรงกลาง: รูปภาพที่มีการเบลอแบบเดียวกันทั่วทั้งพื้นผิว ขวา: รูปภาพที่มีการเบลอแบบไล่ระดับซึ่งมีความคมชัดที่ด้านบนและเบลอมากขึ้นที่ด้านล่าง
รูปที่ 1 ซ้าย: รูปภาพต้นฉบับ ตรงกลาง: รูปภาพที่มีการเบลอแบบเดียวกันทั่วทั้งพื้นผิว ขวา: รูปภาพที่มีการเบลอแบบไล่ระดับซึ่งคมชัดที่ด้านบนและเบลอมากขึ้นเรื่อยๆ จนถึงด้านล่าง

คุณสามารถปรับเปลี่ยนการเบลอได้ 2 วิธีโดยขึ้นอยู่กับเป้าหมายการออกแบบ ดังนี้

  • การเบลอแบบสม่ำเสมอ: ใช้รัศมีการเบลอคงที่ทั่วทั้ง Composable โดยใช้รัศมีเท่ากันทั้ง 2 แกนหรือใช้รัศมีแนวนอนและแนวตั้งแยกกัน (radiusX, radiusY)
  • เบลอแบบไล่ระดับ: เปลี่ยนรัศมีการเบลอตามพื้นที่ใน Composable โดยใช้การไล่ระดับสี BlurRadiusSpec หรือ Shader ที่กำหนดเอง

ใช้การเบลอแบบสม่ำเสมอ

หากต้องการใช้การเบลอคงที่กับ Composable ทั้งหมด ให้ส่งรัศมี Dp ไปยัง Modifier.blur ส่งค่า radius ค่าเดียวเพื่อเบลอเนื้อหาเท่าๆ กันทั้งแกนแนวนอน (X) และแนวตั้ง (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)),
            ),
    )
}

สุนัขที่เบลออย่างสม่ำเสมอทั้งในแกนแนวนอนและแนวตั้ง
รูปที่ 2 สุนัขที่เบลออย่างสม่ำเสมอทั้งในแกนแนวนอนและแนวตั้ง

หากต้องการสร้างเอฟเฟกต์ภาพเบลอจากการเคลื่อนไหวตามทิศทาง ให้ส่งค่า radiusX และ radiusY แยกกันไปยัง Modifier.blur ทั้ง radiusX และ radiusY ต้องมากกว่า 0.dp เพื่อให้ใช้เอฟเฟกต์เบลอได้ ดังที่แสดงในตัวอย่างต่อไปนี้

@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)),
            ),
    )
}

สุนัขที่มีเอฟเฟกต์ภาพเบลอจากการเคลื่อนไหวในแนวนอนที่ชัดเจน
รูปที่ 3 รูปภาพสี่เหลี่ยมจัตุรัสของสุนัขที่มีเอฟเฟกต์ภาพเบลอจากการเคลื่อนไหวในแนวนอนที่ชัดเจน

ใช้การเบลอแบบไล่ระดับ

การเบลอแบบไล่ระดับจะเปลี่ยนรัศมีการเบลอใน Composable เพื่อสร้างการเปลี่ยนผ่านที่ราบรื่นระหว่างบริเวณที่คมชัดและบริเวณที่เบลอ

ส่ง BlurRadiusSpec ไปยัง Modifier.blur เช่น ใช้ BlurRadiusSpec.verticalGradient กับ startRadius = 0.dp และ endRadius = 6.dp เพื่อให้ด้านบนของรูปภาพคมชัดในขณะที่ค่อยๆ เบลอไปทางด้านล่าง ดังที่แสดงในตัวอย่างต่อไปนี้

@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)),
            ),
    )
}

สุนัขที่คมชัดที่ด้านบนและค่อยๆ เบลอไปทางด้านล่าง
รูปที่ 4 รูปภาพสุนัขที่คมชัดที่ด้านบนและค่อยๆ เบลอไปทางด้านล่าง

ระบุการไล่ระดับสีเบลอด้วย BlurRadiusSpec

ใน BlurRadiusSpec ระบบจะตั้งค่าการวัดเป็น Dp และปรับให้เข้ากับขนาดและความหนาแน่นของการแสดงผลของเลเยอร์โดยอัตโนมัติเมื่อวาด ภาพเบลอที่แตกต่างกันตามพื้นที่จำกัดอยู่ที่ 150 พิกเซลเมื่อแปลงแล้ว ส่วน BlurRadiusSpec.uniform ไม่มีขีดจำกัด

ตารางต่อไปนี้แสดงฟังก์ชันโรงงานที่ใช้ได้ใน BlurRadiusSpec

โรงงาน BlurRadiusSpec คำอธิบาย
BlurRadiusSpec.verticalGradient เปลี่ยนรัศมีการเบลอในแนวตั้งจากบน (0f) ลงล่าง (1f) ทั่วทั้งเลเยอร์อย่างราบรื่น
BlurRadiusSpec.horizontalGradient เปลี่ยนรัศมีการเบลอในแนวนอนอย่างราบรื่นจากขอบซ้าย (0f) ไปยังขอบขวา (1f)
BlurRadiusSpec.linearGradient ใช้การเปลี่ยนภาพแบบเบลอตามทิศทางตามเส้นตรงที่เชื่อมต่อพิกัด DpOffset ที่เฉพาะเจาะจง
BlurRadiusSpec.radialGradient กระจายการเบลอออกจากจุดโฟกัสไปยังขอบเขต fallOffRadius
BlurRadiusSpec.uniform ใช้รัศมีการเบลอที่สม่ำเสมอทั่วทั้งเลเยอร์
BlurRadiusSpec.shader ใช้อัลฟาแชแนลของ Shader ที่กำหนดเองเพื่อควบคุมและปรับขนาด maxRadius ที่แต่ละพิกเซล

ปรับแต่งการกระจายการเบลอด้วย BlurStop

การเบลอแบบไล่ระดับสีมาตรฐานจะประมาณค่าในช่วงเชิงเส้นระหว่าง 0f ถึง 1f หากต้องการปรับแต่งการกระจายการเบลอทั่วทั้งพื้นผิว เช่น การเบลอขอบหลายขอบหรือทำให้ส่วนตรงกลางคมชัดอย่างสมบูรณ์ ให้ส่ง List<BlurStop> ที่มีรายการ BlurStop 2 ถึง 16 รายการไปยัง verticalGradient, horizontalGradient, linearGradient หรือ radialGradient กำหนดสิ่งต่อไปนี้สำหรับแต่ละรายการ BlurStop

  • fraction: ตำแหน่งสัมพัทธ์ตามการไล่ระดับสีจาก 0.0f เป็น 1.0f ระบบจะจัดเรียงจุดหยุดโดยอัตโนมัติตามเศษส่วน
  • radius: รัศมีการเบลอใน Dp ที่ใช้ที่ตำแหน่งเศษส่วนนั้น

ตัวอย่างเช่น 4 จุดจะเบลอขอบด้านบนและด้านล่างของรูปภาพขณะที่ยังคงความคมชัดตรงกลางไว้อย่างสมบูรณ์ ดังที่แสดงในตัวอย่างต่อไปนี้

@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,
            ),
    )
}

สุนัขที่มีขอบด้านบนและด้านล่างเบลอ ขณะที่ยังคงโฟกัสแถบแนวนอนตรงกลางให้คมชัด
รูปที่ 5 รูปภาพสุนัขที่มีขอบด้านบนและด้านล่างเบลอ โดยยังคงแถบแนวนอนตรงกลางไว้ในโฟกัสที่คมชัด

กำหนดค่าพร็อพเพอร์ตี้เลเยอร์ด้วย BlurScope

คุณสามารถส่งบล็อกการกำหนดค่าไปยัง Modifier.blur { ... } แทนการส่ง blurRadiusSpec โดยตรงได้ บล็อกนี้จะทำงานภายใน BlurScope ซึ่งช่วยให้คุณเข้าถึงความหนาแน่นของเลย์เอาต์และพร็อพเพอร์ตี้ต่อไปนี้ได้โดยตรง

  • size: DpSize: ความกว้างและความสูงที่วัดได้ของเลเยอร์ที่เบลอใน Dp ซึ่งกำหนดพื้นที่พิกัดสำหรับเรขาคณิตของการไล่ระดับสี
  • blurRadiusSpec: BlurRadiusSpec: การกำหนดค่ารัศมีเบลอทั่วทั้งพื้นผิว ค่าเริ่มต้นคือ BlurRadiusSpec.uniform(0.dp) (ไม่เบลอ)
  • edgeTreatment: BlurredEdgeTreatment: กลยุทธ์ที่ใช้ในการสุ่มตัวอย่างและตัดพิกเซลที่อยู่นอกขอบเขตเนื้อหา ค่าเริ่มต้นคือ BlurredEdgeTreatment.Rectangle
  • alpha: Float: ความทึบแสงของเลเยอร์ที่เบลอในช่วง 0f..1f ค่าเริ่มต้นคือ 1f

เนื่องจากบล็อก BlurScope ทำงานในระหว่างเฟสเลเยอร์กราฟิก หลังจากวัดค่าและเลย์เอาต์ คุณจึงคำนวณเรขาคณิตการไล่ระดับสีจาก size ได้โดยไม่ต้องทริกเกอร์การจัดองค์ประกอบใหม่

ควบคุมการตัดขอบด้วย BlurredEdgeTreatment

เนื่องจากการเบลอจะสุ่มตัวอย่างพิกเซลที่อยู่ใกล้เคียงภายในรัศมีการเบลอ เอาต์พุตที่เบลอจึงขยายออกไปเกินขอบเขตเนื้อหาต้นฉบับตามรัศมีการเบลอ BlurredEdgeTreatment จะกำหนดวิธีสุ่มตัวอย่างพิกเซลที่อยู่นอกขอบเขตเดิม และกำหนดว่าจะตัดผลลัพธ์ให้เป็นรูปร่างหรือไม่

BlurredEdgeTreatment ใช้ได้กับทั้งการเบลอแบบสม่ำเสมอและแบบไล่ระดับ ดังนี้

BlurredEdgeTreatment ลักษณะการทำงาน เอาต์พุต
BlurredEdgeTreatment.Rectangle (ค่าเริ่มต้น) ครอบตัดผลลัพธ์การเบลอให้อยู่ในขอบเขตสี่เหลี่ยมผืนผ้าของเนื้อหาต้นฉบับและสุ่มตัวอย่างพิกเซลขอบที่ใกล้ที่สุด (TileMode.Clamp) รูปภาพสุนัขที่เบลอซึ่งถูกครอบตัดเป็นขอบเขตสี่เหลี่ยมผืนผ้าที่คมชัด
BlurredEdgeTreatment(shape) ตัดผลลัพธ์การเบลอตาม Shape ที่ระบุ (เช่น RoundedCornerShape(8.dp)) และสุ่มตัวอย่างพิกเซลขอบที่ใกล้ที่สุด (TileMode.Clamp) ช่วยให้ผลลัพธ์ที่เบลอคมชัดที่ขอบเขตของรูปร่างโดยไม่เกินขอบเขตเดิม รูปภาพสุนัขที่เบลอซึ่งถูกตัดเป็นรูปทรงมุมโค้งมนที่มีขอบคม
BlurredEdgeTreatment.Unbounded ไม่ครอบตัดผลลัพธ์การเบลอ (TileMode.Decal) พิกเซลที่อยู่นอกขอบเขตเนื้อหาจะแสดงตัวอย่างสีดำโปร่งใส ทำให้ขอบด้านนอกของรูปภาพดูไม่ชัดและเบลอเกินขอบเขตเดิม รูปภาพสุนัขที่เบลอซึ่งขอบค่อยๆ จางลงอย่างนุ่มนวลเกินขอบเขตเดิม

หากต้องการดูวิธีที่ API เหล่านี้รวมกันในรูปแบบ UI ที่สมบูรณ์ เช่น การทำให้ขอบของเนื้อหาที่เลื่อนจางลง การเน้นจุดโฟกัส หรือการมาสก์การเบลอด้วยเฉดสีที่กำหนดเอง โปรดดูกรณีการใช้งานการเบลอที่พบบ่อย