محو کردن پنجره

در Android 12، میاناهای برنامه‌سازی کاربردی عمومی برای پیاده‌سازی جلوه‌های محو کردن پنجره، مانند محو کردن پس‌زمینه و محو کردن پشت، دردسترس است.

از محو کردن پنجره یا محو کردن بین پنجره‌ها برای محو کردن صفحه پشت پنجره موردنظر استفاده می‌شود. دو نوع محو کردن پنجره وجود دارد که می‌توان از آن‌ها برای دستیابی به جلوه‌های دیداری مختلف استفاده کرد:

  • محو کردن پس‌زمینه به شما امکان می‌دهد پنجره‌هایی با پس‌زمینه محو ایجاد کنید، و جلوه شیشه مات ایجاد کنید.

  • محو کردن پشت به شما امکان می‌دهد کل صفحه پشت پنجره (گفتگو) را محو کنید، و جلوه عمق میدان ایجاد کنید.

این دو جلوه را می‌توان به‌صورت جداگانه یا ترکیبی استفاده کرد، همان‌طور که در شکل زیر نشان داده شده است:

فقط محو کردن پس‌زمینه

a

فقط محو کردن پشت

b

محو کردن پشت و محو کردن پس‌زمینه

c

شکل ۱. فقط محو کردن پس‌زمینه (a)، فقط محو کردن پشت (b)، محو کردن پس‌زمینه و محو کردن پشت (c)

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

پیاده‌سازی

توسعه‌دهندگان نرم‌افزار

توسعه‌دهندگان برنامه باید شعاع محوی را برای ایجاد جلوه محو کردن ارائه دهند. شعاع محو کردن میزان تراکم محو کردن را کنترل می‌کند، یعنی هرچه شعاع بیشتر باشد، محو کردن متراکم‌تر است. محو کردن ۰ پیکسل یعنی محو کردن وجود ندارد. برای محو کردن پشت، شعاع ۲۰ پیکسلی جلوه عمق میدان خوبی ایجاد می‌کند، درحالی‌که شعاع محو کردن پس‌زمینه ۸۰ پیکسلی جلوه شیشه مات خوبی ایجاد می‌کند. از شعاع محو کردن بیشتر از ۱۵۰ پیکسل استفاده نکنید، زیرا این کار تأثیر قابل‌توجهی بر عملکرد خواهد داشت.

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

پس‌زمینه محو

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

  1. برای تنظیم شعاع محو کردن پس‌زمینه، Window#setBackgroundBlurRadius(int) را فراخوانی کنید. یا در طرح زمینه پنجره، R.attr.windowBackgroundBlurRadius را تنظیم کنید.

  2. R.attr.windowIsTranslucent را روی true تنظیم کنید تا پنجره نیمه‌شفاف شود. محو کردن در زیر سطح پنجره ترسیم می‌شود، بنابراین پنجره باید نیمه‌شفاف باشد تا محو کردن قابل‌مشاهده باشد.

  3. درصورت تمایل، Window#setBackgroundDrawableResource(int) را فراخوانی کنید تا پس‌زمینه پنجره مستطیلی قابل‌ترسیم با رنگ نیمه‌شفاف اضافه شود. یا در طرح زمینه پنجره، R.attr.windowBackground را تنظیم کنید.

  4. برای پنجره‌ای با گوشه‌های گرد، گوشه‌های گرد را برای ناحیه محوشده با تنظیم ShapeDrawable با گوشه‌های گرد به‌عنوان پس‌زمینه پنجره قابل‌رسم تعیین کنید.

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

محو کردن پشت سر

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

برای محو کردن محتوای پشت پنجره، این مراحل را دنبال کنید:

  1. FLAG_BLUR_BEHIND را به پرچم‌های پنجره اضافه کنید تا محو کردن پشت فعال شود. یا در طرح زمینه پنجره، R.attr.windowBlurBehindEnabled را تنظیم کنید.

  2. برای تنظیم شعاع محو کردن پشت، WindowManager.LayoutParams#setBlurBehindRadius را فراخوانی کنید. یا در طرح زمینه پنجره، R.attr.windowBlurBehindRadius را تنظیم کنید.

  3. درصورت تمایل، مقدار کم‌نور شدن مکمل را انتخاب کنید.

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

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

پشتیبانی از محو کردن پنجره‌ها به موارد زیر بستگی دارد:

  • نسخه Android: میاناهای برنامه‌سازی کاربردی محو کردن پنجره‌ها فقط در Android نسخه ۱۲ و بالاتر دردسترس است. کیت توسعه نرم‌افزار دستگاه را برای نسخه Android بررسی کنید.

  • عملکرد گرافیکی: دستگاه‌هایی که GPU با عملکرد پایین‌تر دارند ممکن است تصمیم بگیرند از محو کردن پنجرهپشتیبانی نکنند.

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

برای سازگار کردن برنامه‌تان با نسخه‌ها، دستگاه‌ها، و وضعیت‌های سیستم Android، این دستورالعمل‌ها را دنبال کنید:

  • شنونده‌ای را ازطریق WindowManager#addCrossWindowBlurEnabledListener اضافه کنید، تا وقتی محو کردن پنجره فعال یا غیرفعال می‌شود به شما اطلاع داده شود. علاوه‌براین، از WindowManager#isCrossWindowBlurEnabled برای پرسمان درباره اینکه آیا محو کردن پنجره درحال‌حاضر فعال است یا نه استفاده کنید.

  • دو نسخه برای پس‌زمینه پنجره پیاده‌سازی کنید تا با وضعیت فعال یا غیرفعال محو کردن پنجره سازگار باشد.

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

    • برای محو کردن پس‌زمینه، آلفای پس‌زمینه پنجره را افزایش دهید تا مات‌تر شود.

    • برای محو کردن پشت، لایه کم‌نوری با مقدار کم‌نور بیشتر اضافه کنید.

نمونه‌ای از محو کردن پشت و محو کردن پس‌زمینه

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

نمونه زیر از MainActivity.java یک کادر گفتگو با شعاع محوی پشت ۲۰ پیکسل و شعاع محوی پس‌زمینه ۸۰ پیکسل است. این پنجره گوشه‌های گرد دارد که در xml در پس‌زمینه پنجره قابل‌رسم تعریف شده است. این API به‌درستی نسخه‌های مختلف Android، دستگاه‌های مختلف (که احتمالاً از محو کردن پنجره پشتیبانی نمی‌کنند)، و تغییرات فعال یا غیرفعال بودن محو کردن زمان اجرا را مدیریت می‌کند. این ویژگی با تنظیم کردن آلفای قابل‌رسم پس‌زمینه پنجره و میزان تار شدن پنجره، تضمین می‌کند که محتوای کادر گفتگو در هریک از این شرایط خوانا باشد.

public class MainActivity extends Activity {

    private final int mBackgroundBlurRadius = 80;
    private final int mBlurBehindRadius = 20;

    // We set a different dim amount depending on whether window blur is enabled or disabled
    private final float mDimAmountWithBlur = 0.1f;
    private final float mDimAmountNoBlur = 0.4f;

    // We set a different alpha depending on whether window blur is enabled or disabled
    private final int mWindowBackgroundAlphaWithBlur = 170;
    private final int mWindowBackgroundAlphaNoBlur = 255;

    // Use a rectangular shape drawable for the window background. The outline of this drawable
    // dictates the shape and rounded corners for the window background blur area.
    private Drawable mWindowBackgroundDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWindowBackgroundDrawable = getDrawable(R.drawable.window_background);
        getWindow().setBackgroundDrawable(mWindowBackgroundDrawable);

        if (buildIsAtLeastS()) {
            // Enable blur behind. This can also be done in xml with R.attr#windowBlurBehindEnabled
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

            // Register a listener to adjust window UI whenever window blurs are enabled/disabled
            setupWindowBlurListener();
        } else {
            // Window blurs are not available prior to Android S
            updateWindowForBlurs(false /* blursEnabled */);
        }

        // Enable dim. This can also be done in xml, see R.attr#backgroundDimEnabled
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    }

    /**
     * Set up a window blur listener.
     *
     * Window blurs might be disabled at runtime in response to user preferences or system states
     * (e.g. battery saving mode). WindowManager#addCrossWindowBlurEnabledListener allows to
     * listen for when that happens. In that callback we adjust the UI to account for the
     * added/missing window blurs.
     *
     * For the window background blur we adjust the window background drawable alpha:
     *     - lower when window blurs are enabled to make the blur visible through the window
     *       background drawable
     *     - higher when window blurs are disabled to ensure that the window contents are readable
     *
     * For window blur behind we adjust the dim amount:
     *     - higher when window blurs are disabled - the dim creates a depth of field effect,
     *       bringing the user's attention to the dialog window
     *     - lower when window blurs are enabled - no need for a high alpha, the blur behind is
     *       enough to create a depth of field effect
     */
    @RequiresApi(api = Build.VERSION_CODES.S)
    private void setupWindowBlurListener() {
        Consumer<Boolean> windowBlurEnabledListener = this::updateWindowForBlurs;
        getWindow().getDecorView().addOnAttachStateChangeListener(
                new View.OnAttachStateChangeListener() {
                    @Override
                    public void onViewAttachedToWindow(View v) {
                        getWindowManager().addCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }

                    @Override
                    public void onViewDetachedFromWindow(View v) {
                        getWindowManager().removeCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }
                });
    }

    private void updateWindowForBlurs(boolean blursEnabled) {
        mWindowBackgroundDrawable.setAlpha(blursEnabled && mBackgroundBlurRadius > 0 ?
                mWindowBackgroundAlphaWithBlur : mWindowBackgroundAlphaNoBlur);
        getWindow().setDimAmount(blursEnabled && mBlurBehindRadius > 0 ?
                mDimAmountWithBlur : mDimAmountNoBlur);

        if (buildIsAtLeastS()) {
            // Set the window background blur and blur behind radii
            getWindow().setBackgroundBlurRadius(mBackgroundBlurRadius);
            getWindow().getAttributes().setBlurBehindRadius(mBlurBehindRadius);
            getWindow().setAttributes(getWindow().getAttributes());
        }
    }

    private static boolean buildIsAtLeastS() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
    }
}

برای ایجاد گوشه‌های گرد برای پنجره، پس‌زمینه پنجره را در res/drawable/window_background.xml به‌عنوان ShapeDrawable با گوشه‌های گرد با شعاع ۲۰ dp به‌صورت زیر تعریف می‌کنیم:

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
    <corners android:radius="20dp"/>
    <solid android:color="#AAAAAA"/>
</shape>

محو کردن پنجره باعث می‌شود محتوای پنجره زیر فعالیت محو شود. تصویر محوشده زیر این پنجره فعالیت کشیده می‌شود، بنابراین پنجره فعالیت باید نیمه‌شفاف باشد تا محوشدگی قابل‌مشاهده باشد. برای نیمه‌شفاف کردن پنجره، R.attr.windowIsTranslucent را در زمینه فعالیت به‌صورت زیر تنظیم می‌کنیم:

<style name="Theme.BlurryDialog" parent="Theme.MaterialComponents.Dialog">
    <item name="android:windowIsTranslucent">true</item>
</style>

سازندگان اصلی محصول و شرکا

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

برای بررسی اینکه آیا دستگاهتان می‌تواند از محو کردن پنجره پشتیبانی کند یا نه، کارهای زیر را انجام دهید:

  • مطمئن شوید دستگاه می‌تواند بار اضافی «واحد پردازش گرافیکی» را مدیریت کند. دستگاه‌های رده پایین‌تر ممکن است نتوانند بار اضافی را تحمل کنند، که می‌تواند باعث افت فریم شود. محو کردن پنجره فقط در دستگاه‌های آزمایش‌شده با قدرت GPU کافی فعال شود.

  • اگر موتور پردازش سفارشی دارید، مطمئن شوید که موتور پردازش شما منطق محو کردن را پیاده‌سازی می‌کند. موتور پردازش پیش‌فرض Android 12 منطق محو کردن را در BlurFilter.cpp پیاده‌سازی می‌کند.

وقتی مطمئن شدید دستگاهتان می‌تواند از محو کردن پنجره پشتیبانی کند، surface flinger sysprop زیر را تنظیم کنید:

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

اعتبارسنجی

برای تأیید اینکه پنجره برنامه‌تان هنگام جابه‌جایی بین حالت‌های فعال بودن محو کردن و غیرفعال بودن محو کردن به‌درستی مدیریت می‌شود، این مراحل را دنبال کنید:

  1. رابط کاربری‌ای را که محو است باز کنید.

  2. با روشن و خاموش کردن محو کردن پنجره، محو کردن پنجره را فعال یا غیرفعال کنید.

  3. تأیید کنید که واسط کاربر پنجره طبق انتظار به حالت محو تغییر می‌کند و از آن خارج می‌شود.

روشن و خاموش کردن محو کردن پنجره

برای آزمایش نحوه ارائه واسط کاربر پنجره با جلوه محو کردن پنجره، محو کردن را بااستفاده از یکی از روش‌های زیر فعال یا غیرفعال کنید:

  • از «گزینه‌های توسعه‌دهندگان»:

    تنظیمات -> سیستم -> گزینه‌های توسعه‌دهندگان -> رندر کردن با شتاب سخت‌افزاری -> مجاز کردن محو کردن در سطح پنجره

  • از پایانه در دستگاه با دسترسی ریشه‌ای:

    adb shell wm disable-blur 1 # 1 disables window blurs, 0 allows them

برای بررسی اینکه آیا دستگاه Android 12+ شما از محو کردن پنجره پشتیبانی می‌کند یا نه و اینکه آیا محو کردن پنجره درحال‌حاضر فعال است یا نه، adb shell wm disable-blur را در دستگاه ریشه‌یابی‌شده اجرا کنید.

عیب‌یابی

از موارد زیر به‌عنوان راهنمایی برای عیب‌یابی درطول اعتبارسنجی استفاده کنید.

محوی کشیده نشده است

  • بررسی کنید که محو کردن درحال‌حاضر فعال باشد و سخت‌افزارتان از آن پشتیبانی کند. به روشن و خاموش کردن محو کردن پنجره مراجعه کنید.

  • حتماً رنگ پس‌زمینه پنجره را نیمه‌شفاف تنظیم کنید. رنگ پس‌زمینه پنجره مات، ناحیه محوشده را پنهان می‌کند.

دستگاه آزمایشی از محو کردن پنجره پشتیبانی نمی‌کند

  • برنامه‌تان را در شبیه‌ساز Android 12 آزمایش کنید. برای راه‌اندازی شبیه‌ساز Android، به راه‌اندازی شبیه‌ساز Android مراجعه کنید. هر دستگاه مجازی Android که با شبیه‌ساز ایجاد می‌کنید از محو کردن پنجره پشتیبانی می‌کند.

بدون گوشه‌های گرد

به‌روزرسانی گزینه توسعه‌دهنده، محو کردن را فعال نمی‌کند

  • بررسی کنید که آیا دستگاه در حالت صرفه‌جویی در مصرف باتری است یا از تونل‌زنی چندرسانه‌ای استفاده می‌کند. در برخی‌از دستگاه‌های تلویزیون، ممکن است محو کردن پنجره درطول بازپخش ویدیو نیز غیرفعال شود.

محو کردن پس‌زمینه به‌صورت تمام‌صفحه اعمال شده است، نه در محدوده پنجره

به‌روزرسانی‌های شنونده روی صفحه اعمال نمی‌شود

  • ممکن است به‌روزرسانی‌های شنونده روی نمونه پنجره قدیمی اعمال شود. بررسی کنید که آیا پنجره درحال ازبین رفتن است و با به‌روزرسانی شنونده مناسب دوباره ایجاد می‌شود یا نه.