موارد استفاده رایج از محو کردن

بخش‌های زیر نحوه ترکیب Modifier.blur، BlurRadiusSpec، BlurStop، و BlurScope را برای الگوهای رایج واسط کاربر نشان می‌دهد. برای آشنایی با این میاناهای برنامه‌سازی کاربردی، محو کردن در Compose را ببینید.

محو کردن لبه‌های محتوای پیمایشی یا کشیدنی

هنگام نمایش فهرست پیمایشی، گردونه، یا انتخابگر، می‌توانید از محو کردن تدریجی چندایستگاهی برای نرم کردن موارد نزدیک لبه‌های محفظه استفاده کنید و درعین‌حال منطقه مرکزی فعال را در کانون واضح نگه دارید.

محو کردن لبه‌های بالا و پایین فهرست پیمایشی

برای نرم کردن موارد هنگام پیمایش به داخل و خارج از نمای فهرست عمودی، BlurRadiusSpec.verticalGradient را با ورودی‌های BlurStop به LazyColumn اعمال کنید. در مثال زیر، که متن ترانه را خط‌به‌خط پیمایش می‌کند، ایست‌های 0.dp بین 0.42f و 0.58f خط فعال را در مرکز واضح نگه می‌دارند، درحالی‌که خطوط نزدیک به لبه‌های بالا و پایین به‌تدریج محو می‌شوند:

@Composable
fun SongListTopBottomBlurExample(lyrics: List<String>) {
    // ...
    LazyColumn(
        state = listState,
        flingBehavior = flingBehavior,
        modifier = Modifier
            .width(330.dp)
            .height(480.dp)
            .padding(horizontal = 24.dp)
            .blur(
                blurRadiusSpec = BlurRadiusSpec.verticalGradient(
                    stops = listOf(
                        BlurStop(fraction = 0.00f, radius = 18.dp), // Heavily blurred top edge
                        BlurStop(fraction = 0.24f, radius = 8.dp), // Soft upper transition
                        BlurStop(fraction = 0.42f, radius = 0.dp), // Sharp center focus starts
                        BlurStop(fraction = 0.58f, radius = 0.dp), // Sharp center focus ends
                        BlurStop(fraction = 0.76f, radius = 8.dp), // Soft lower transition
                        BlurStop(fraction = 1.00f, radius = 18.dp), // Heavily blurred bottom edge
                    ),
                ),
                edgeTreatment = BlurredEdgeTreatment.Unbounded,
            ),
        contentPadding = PaddingValues(vertical = 36.dp),
        verticalArrangement = Arrangement.spacedBy(26.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        // ...
    }
}

شکل ۱. فهرست عمودی از خطوط نوشتاری متن ترانه که خطوط بالا و پایین به‌صورت محو ناپدید می‌شوند درحالی‌که خط مرکزی واضح است.

محو کردن لبه‌های چپ و راست کنترل افقی

به‌طور مشابه، برای جلب توجه به مرکز مؤلفه‌ای که به‌صورت افقی پیمایش‌پذیر یا کشیدنی است، مثل انتخابگر چرخشی، گردونه، یا مقیاس اندازه‌گیری، BlurRadiusSpec.horizontalGradient را با ورودی‌های BlurStop اعمال کنید. در ترازوی وزن کشیدنی زیر، لبه‌های چپ و راست نرم می‌شوند درحالی‌که خطوط و اعداد نزدیک عقربه نشانگر مرکزی کاملاً واضح می‌مانند:

@Composable
fun HorizontalScaleBlurExample() {
    var selectedValue by remember { mutableFloatStateOf(65.0f) }
    val animatedValue by animateFloatAsState(
        targetValue = selectedValue,
        animationSpec = tween(durationMillis = 900, easing = FastOutSlowInEasing),
        label = "horizontalScaleSmoothScroll",
    )
    Column(
        modifier = Modifier
            .width(340.dp)
            .background(Color(0xFF0F172A), RoundedCornerShape(24.dp))
            .padding(vertical = 24.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            text = "${(animatedValue * 10).roundToInt() / 10.0} kg",
            color = Color.White,
            fontSize = 44.sp,
            fontWeight = FontWeight.Black,
        )
        Spacer(Modifier.height(16.dp))
        Box(
            // ...
        ) {
            // Ruler ticks blurred at the left and right edges, sharp at center
            Canvas(
                modifier = Modifier
                    .fillMaxSize()
                    .blur(
                        blurRadiusSpec = BlurRadiusSpec.horizontalGradient(
                            stops = listOf(
                                BlurStop(fraction = 0.00f, radius = 14.dp),
                                BlurStop(fraction = 0.28f, radius = 0.dp),
                                BlurStop(fraction = 0.72f, radius = 0.dp),
                                BlurStop(fraction = 1.00f, radius = 14.dp),
                            ),
                        ),
                        edgeTreatment = BlurredEdgeTreatment.Unbounded,
                    ),
            ) {
                // Draw horizontal ruler ticks offset by `animatedValue`
                // ...
            }
            // ...
        }
    }
}

شکل ۲. ابزارک مقیاس خط‌کش افقی که علامت‌های تیک محو را در نزدیکی لبه‌ها و علامت‌های تیک واضح را در نزدیکی عقربه نشانگر نشان می‌دهد.

ایجاد محوی مورب با linearGradient

BlurRadiusSpec.linearGradient شعاع محوشدگی را درطول یک پاره‌خط بین مقادیر start و end DpOffset در فضای مختصات لایه تغییر می‌دهد. در داخل بلوک لامبدا Modifier.blur، می‌توانید BlurScope.size را بخوانید تا یک محو کردن تدریجی قطری را در سراسر تصویر اصلی از گوشه بالا سمت چپ به گوشه پایین سمت راست اجرا کنید، درحالی‌که سوژه در بالا سمت چپ کاملاً واضح باقی می‌ماند و منطقه پایین سمت راست پشت نوشتار هم‌پوشان به‌تدریج محو می‌شود:

@Composable
fun DiagonalLinearBlurCardExample() {
    Box(
        modifier = Modifier
            .wrapContentSize()
            .background(Color(0xFFF8FAFC))
            .padding(10.dp),
    ) {
        Image(
            painter = painterResource(id = R.drawable.dog),
            contentDescription = stringResource(id = R.string.dog_content_description),
            contentScale = ContentScale.Crop,
            modifier = Modifier
                .size(width = 300.dp, height = 380.dp)
                .blur {
                    blurRadiusSpec = BlurRadiusSpec.linearGradient(
                        start = DpOffset(0.dp, 0.dp),
                        end = DpOffset(size.width, size.height),
                        stops = listOf(
                            BlurStop(fraction = 0.00f, radius = 0.dp),
                            BlurStop(fraction = 0.50f, radius = 0.dp),
                            BlurStop(fraction = 0.75f, radius = 14.dp),
                            BlurStop(fraction = 1.00f, radius = 28.dp),
                        ),
                    )
                    edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(24.dp))
                },
        )
        // ...
    }
}

پرتره سگی که در بالا سمت چپ واضح است و به‌تدریج به‌سمت گوشه پایین سمت راست محو می‌شود، با عنوان و زیرعنوان سفید واضح که روی ناحیه محوشده قرار گرفته است.
شکل ۳.‏ پرتره سگی که در بالا سمت چپ واضح است و به‌تدریج به‌سمت گوشه پایین سمت راست محو می‌شود، با عنوان و زیرعنوان سفید واضح که روی ناحیه محو قرار گرفته است.

ایجاد مورد ویژه متمرکز با radialGradient

BlurRadiusSpec.radialGradient با تغییر دادن شعاع محوشدگی به سمت بیرون از نقطه کانونی، جلوه نورافکن دایره‌ای ایجاد می‌کند. center را به‌عنوان DpOffset و fallOffRadius را به‌عنوان فاصله Dp از center که در آن به endRadius می‌رسد تعریف کنید. اگر center را به‌صورت DpOffset.Unspecified رها کنید، گرادیان در مرکز composable قرار می‌گیرد، و اگر fallOffRadius را به‌صورت Dp.Unspecified رها کنید، به‌طور پیش‌فرض روی نصف بعد کوچک‌تر لایه تنظیم می‌شود.

برای مثال، اعمال BlurRadiusSpec.radialGradient روی بخشی از نوشتار و به‌روزرسانی center از رویدادهای کشیدن اشاره‌گر به کاربر اجازه می‌دهد تا یک نورافکن دایره‌ای خوانش را روی پاراگراف بکشد و درعین‌حال نوشتار اطراف را محو کند، همان‌طور که در مثال زیر نشان داده شده است:

@Composable
fun RadialSpotlightTextExample() {
    var touchOffset by remember { mutableStateOf(Offset.Unspecified) }
    Box(
        modifier = Modifier
            .size(width = 330.dp, height = 340.dp)
            .background(Color(0xFF0F172A), RoundedCornerShape(20.dp))
            .pointerInput(Unit) {
                detectDragGestures(
                    onDragStart = { offset -> touchOffset = offset },
                    onDrag = { change, _ -> touchOffset = change.position },
                )
            }
            .blur {
                val spotlightCenter = if (touchOffset.isSpecified) {
                    DpOffset(touchOffset.x.toDp(), touchOffset.y.toDp())
                } else {
                    DpOffset(x = size.width / 2, y = size.height / 2)
                }
                blurRadiusSpec = BlurRadiusSpec.radialGradient(
                    startRadius = 0.dp,
                    endRadius = 10.dp,
                    center = spotlightCenter,
                    fallOffRadius = 215.dp,
                )
                edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(20.dp))
            }
            .padding(22.dp),
    ) {
        // ...
    }
}

شکل ۴. پاراگرافی از نوشتار با ناحیه‌ای دایره‌ای از نوشتار واضح در اطراف اشاره‌گر که به‌تدریج به‌سمت لبه دایره محو می‌شود.

ایجاد ماسک محو سفارشی با سایه‌زن

برای توزیع‌های محوشدگی فضایی پیچیده فراتر از گرادیان‌های خطی یا شعاعی، مانند الگوهای تکراری، شکل‌های دلخواه، یا نویز رویه‌ای، یک Shader سفارشی، مانند AGSL RuntimeShader، را به BlurRadiusSpec.shader ارسال کنید. سایه‌زن در مختصات پیکسل لایه از مبدأ بالا سمت راست ارزیابی می‌شود و کانال آلفای نمونه‌برداری‌شده آن (0..1) maxRadius را مقیاس‌بندی می‌کند.

سایه‌زن و پیکربندی BlurRadiusSpec.shader را یک‌بار بااستفاده از تابع ترکیب‌پذیر remember ایجاد کنید تا یک نمونه واحد در ترکیب‌های مجدد دوباره استفاده شود. ‫Compose بلوک پیکربندی را با اندازه لایه در هر حل فراخوانی می‌کند، که در آنجا یونیفرم‌های وابسته به اندازه را تنظیم می‌کنید:

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
fun ShaderBlurExample() {
    // Creates 6 diagonal frosted-glass bands across the image.
    val maskShader = remember {
        RuntimeShader(
            """
            uniform float2 size;
            half4 main(float2 coord) {
                float2 uv = coord / size;
                float band = smoothstep(0.4, 0.6, fract((uv.x + uv.y) * 3.0));
                return half4(0.0, 0.0, 0.0, half(band));
            }
            """.trimIndent(),
        )
    }
    val maskBlurSpec = remember(maskShader) {
        BlurRadiusSpec.shader(maxRadius = 24.dp) { sizePx ->
            maskShader.setFloatUniform("size", sizePx.width, sizePx.height)
            maskShader
        }
    }
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = stringResource(id = R.string.dog_content_description),
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(150.dp)
            .blur(blurRadiusSpec = maskBlurSpec),
    )
}

تصویر سگی با نوارهای محو شیشه مات مورب که با ماسک سایه‌زن سفارشی ایجاد شده است.
شکل ۵. تصویر سگی با نوارهای محو شیشه مات مورب که با ماسک سایه‌زن سفارشی ایجاد شده است.