يتم تعتيم النوافذ

في Android 12، تتوفّر واجهات برمجة التطبيقات العامة لتنفيذ تأثيرات تمويه النوافذ، مثل تمويه الخلفية وتمويه الخلفية.

تُستخدَم تمويهات النوافذ أو تمويهات النوافذ المتداخلة لتمويه الشاشة خلف النافذة المحدّدة. هناك نوعان من تمويهات النوافذ، ويمكن استخدامهما لتحقيق تأثيرات مرئية مختلفة:

  • يتيح لك خيار تمويه الخلفية إنشاء نوافذ بخلفيات مموّهة، مما يخلق تأثيرًا زجاجيًا مموهًا.

  • يتيح لك الخيار تمويه الخلف تمويه الشاشة بأكملها خلف نافذة (مربّع حوار)، ما يؤدي إلى عمق تأثير الحقل.

ويمكن استخدام التأثيرَين بشكل منفصل أو مجمّعَين، كما هو موضّح في الشكل التالي:

تمويه الخلفية فقط

a‏

تمويه خلفي فقط

ب

تمويه الخلفية وتمويه الخلفية

ج

الشكل 1: تمويه الخلفية فقط (أ)، تمويه الجزء الخلفي فقط (ب)، تمويه الخلفية والجزء الخلفي (ج)

تعمل ميزة تمويه النوافذ على جميع النوافذ، ما يعني أنّها تعمل أيضًا عند وجود تطبيق آخر خلف النافذة. يختلف هذا التأثير عن تأثير التمويه الذي يؤدي إلى تمويه المحتوى داخل النافذة نفسها. إنّ تمويه النوافذ مفعّل في مربّعات الحوار والأوراق السفلية والنوافذ العائمة الأخرى.

التنفيذ

مطورو التطبيقات

على مطوّري التطبيقات توفير نصف قطر تمويه لإنشاء تأثير تمويه. يتحكّم نصف قطر التمويه في كثافة التمويه، أي كلما زاد نصف القطر، زادت كثافة التمويه. يعني التمويه الذي يبلغ 0 بكسل عدم التمويه. بالنسبة إلى التشويش في الخلف، يوفر نصف القطر 20 بكسل عمقًا جيدًا للحقل، بينما ينتج عن نصف قطر تمويه الخلفية الذي يبلغ 80 بكسل تأثير زجاج بلوري جيد. تجنَّب أن تكون نصف قطر التمويه أعلى من 150 بكسل لأنّ ذلك سيؤثر بشكل كبير في الأداء.

لتحقيق تأثير التمويه المطلوب وزيادة إمكانية القراءة، اختَر قيمة نصف قطر مموّهة تكملها طبقة نصف شفافة من الألوان.

تعتيم الخلفية

استخدِم ميزة تمويه الخلفية في النوافذ العائمة لإنشاء تأثير خلفية للنافذة، وهو صورة تمويهة للمحتوى الأساسي. لإضافة خلفية مموَّهة لنافذتك، عليك اتّباع الخطوات التالية:

  1. يمكنك استدعاء Window#setBackgroundB لإدارةRadius(int) لضبط نصف قطر تمويه الخلفية. أو في مظهر النافذة، اضبط R.attr.windowBackgroundB لإدارةRadius.

  2. اضبط R.attr.windowIsTranslucent على "صحيح" لجعل النافذة شفافة. يتم رسم التمويه تحت سطح النافذة، لذا يجب أن تكون النافذة شفافة للسماح بظهور التمويه.

  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: لا تتوفّر واجهات برمجة التطبيقات الخاصة بميزة تمويه النوافذ إلا على الإصدار 12 من Android والإصدارات الأحدث. تحقَّق من حزمة SDK للجهاز لمعرفة إصدار Android.

  • أداء الرسومات: قد تختار الأجهزة التي تتضمّن وحدات معالجة رسومات ذات أداء أقل عدم إتاحة تمويه النوافذ.

  • حالة النظام: قد يوقف خادم النظام مؤقتًا تمويه النوافذ أثناء وقت التشغيل، على سبيل المثال، أثناء وضع "توفير شحن البطارية" أو أثناء تشغيل أنواع معيّنة من محتوى الفيديو أو بسبب إلغاء مطوّر للإعدادات.

لجعل تطبيقك متوافقًا مع إصدارات Android والأجهزة وحالات النظام، اتّبِع الإرشادات التالية:

  • أضِف مستمعًا من خلال WindowManager#addCrossWindowBlurEnabledListener، لإعلامك عند تفعيل أو إيقاف تمويه النوافذ. بالإضافة إلى ذلك، استخدِم WindowManager#isCrossWindowBlurEnabled لمعرفة ما إذا كان خيار تمويه النوافذ مفعَّلاً حاليًا.

  • نفِّذ نسختين لخلفية النافذة لتلائم حالة تمويه النوافذ المفعَّلة أو غير المفعَّلة.

    عند تفعيل التمويه، يجب أن تكون خلفية النافذة شبه شفافة لإظهار التمويه. في هذه الحالة، عند إيقاف عمليات التمويه، يتداخل محتوى النافذة بشكل مباشر مع محتوى النافذة الأساسية، ما يجعل قراءة النافذة المتداخلة أكثر صعوبة. ولتجنُّب هذا التأثير، عند إيقاف تمويه النوافذ، عليك ضبط واجهة مستخدم التطبيق على النحو التالي:

    • بالنسبة إلى التمويه في الخلفية، يمكنك زيادة قيمة شفافية drawable لخلفية النافذة، ما يجعلها أكثر عتامة.

    • للتعتيم في الخلف، أضِف طبقة خافتة مع زيادة تعتيم الشاشة.

مثال على تمويه الخلفية وتمويه الخلفية

يقدّم هذا القسم مثالاً عمليًا لنشاط يستخدم التمويه الخلفي والخلفية.

في ما يلي مثال على MainActivity.java مربّع حوار يتضمّن تمويهًا خلف نصف قطره 20 بكسل ونصف قطر تمويه الخلفية 80 بكسل. وله زوايا دائرية، محددة في xml في خلفية النافذة، قابلة للرسم. ويعالج بشكلٍ صحيح إصدارات 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 ذات زوايا مستديرة ونصف قطرها 20 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>

المصنّعون الأصليون للأجهزة والشركاء

لتفعيل ميزة التمويه على النوافذ على أحد الأجهزة، على المصنّع الأصلي للجهاز الإفصاح عن أنّ الجهاز يتوافق مع ميزة التمويه على النوافذ.

لمعرفة ما إذا كان جهازك يتيح ميزة تعتيم النوافذ، يمكنك اتّباع الخطوات التالية:

  • تأكَّد من أنّ الجهاز يمكنه تحمّل عبء وحدة معالجة الرسومات الإضافية. قد لا تتمكن الأجهزة ذات الإصدار العادي من معالجة الحِمل الإضافي، ما قد يؤدي إلى إسقاط الإطارات. يجب تفعيل تمويه النوافذ فقط على الأجهزة المُختبَرة التي تمتلك وحدة معالجة رسومات كافية.

  • إذا كان لديك محرّك عرض مخصّص، تأكّد من أنّ محرّك العرض ينفّذ منطق التمويه. ينفِّذ محرك العرض التلقائي الذي يعمل بنظام التشغيل 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 والإصدارات الأحدث متوافقًا مع ميزة التمويه في النوافذ وما إذا كانت هذه الميزة مفعّلة حاليًا، يمكنك تشغيل ملف APK adb shell wm disable-blur على جهاز مزوّد بإذن الوصول إلى الجذر.

تحديد المشاكل وحلّها

يمكنك استخدام ما يلي كدليل لتحديد المشاكل وحلّها أثناء عملية التحقّق.

لم يتم رسم أي تمويه

  • تأكَّد من أنّ ميزة التمويه مفعَّلة حاليًا وأنّ جهازك متوافق معها. راجِع مقالة تفعيل ميزة "تمويه النوافذ" وإيقافها.

  • تأكَّد من ضبط لون خلفية نافذة شفاف. يخفي لون خلفية النافذة المعتم المنطقة المموّهة.

لا يتيح الجهاز الاختباري تمويه النوافذ.

  • اختبِر تطبيقك على محاكي Android 12. ولإعداد محاكي Android، اطّلِع على مقالة إعداد محاكي Android. ويتوافق أي جهاز Android افتراضي تنشئه باستخدام المحاكي مع انبثاق النوافذ.

بدون زوايا مستديرة

لا يؤدي تعديل خيارات المطوّرين إلى تفعيل التمويهات

  • تحقَّق مما إذا كان الجهاز في وضع توفير شحن البطارية أو ما إذا كان يستخدم وضع النفق المتعدد الوسائط. قد يتم أيضًا إيقاف تمويه النوافذ أثناء تشغيل الفيديو على بعض أجهزة التلفزيون.

تم رسم تمويه الخلفية بملء الشاشة، وليس ضمن حدود النافذة

لا يتم تطبيق الإشعارات من المستمع على الشاشة.

  • قد يتم تطبيق تحديثات المستمع على مثيل نافذة قديمة. تحقَّق مما إذا كانت النافذة يتم إتلافها وإعادة إنشائها باستخدام تعديل العميل المناسب.