في نظام التشغيل Android 12، تتوفّر واجهات برمجة تطبيقات عامة لتنفيذ تأثيرات تمويه النوافذ، مثل تمويه الخلفية والتمويه في الخلفية.
يتم استخدام تمويه النوافذ، أو تمويه النوافذ المتقاطع، لتمويه الشاشة خلف النافذة المحدّدة. هناك نوعان من تمويه النوافذ، ويمكن استخدامهما لتحقيق تأثيرات مرئية مختلفة:
يتيح لك خيار تمويه الخلفية إنشاء نوافذ بخلفيات مموّهة، ما يؤدي إلى إنشاء تأثير زجاجي غير شفاف.
يتيح لك خيار التمويه في الخلف تمويه الشاشة بأكملها خلف نافذة (مربّع حوار)، ما يؤدي إلى إنشاء تأثير عمق المجال.
يمكن استخدام التأثيرَين بشكل منفصل أو دمجهما معًا، كما هو موضّح في الشكل التالي:
![]() a |
![]() b |
![]() c |
الشكل 1. تمويه الخلفية فقط (أ)، التمويه في الخلفية فقط (ب)، تمويه الخلفية والتمويه في الخلفية (ج)
تعمل ميزة تمويه النافذة على مستوى النوافذ، ما يعني أنّها تعمل أيضًا عندما يكون هناك تطبيق آخر خلف نافذتك. لا يشبه هذا التأثير تأثير التمويه الذي يموّه المحتوى داخل النافذة نفسها. تكون تمويهات النوافذ مفيدة لمربّعات الحوار والبطاقات السفلية والنوافذ العائمة الأخرى.
التنفيذ
مطوّرو التطبيقات
على مطوّري التطبيقات تقديم نصف قطر التمويه لإنشاء تأثير التمويه. يتحكّم نصف قطر التمويه في مدى كثافة التمويه، أي أنّه كلما زاد نصف القطر، زادت كثافة التمويه. يعني التمويه بمقدار 0 بكسل عدم التمويه. بالنسبة إلى التمويه في الخلفية، يؤدي استخدام نصف قطر يبلغ 20 بكسل إلى إنشاء تأثير جيد لعمق المجال، بينما يؤدي استخدام نصف قطر يبلغ 80 بكسل إلى إنشاء تأثير جيد للزجاج المطفأ. تجنَّب استخدام نصف قطر للتمويه أكبر من 150 بكسل، لأنّ ذلك سيؤثر بشكل كبير في الأداء.
لتحقيق تأثير التمويه المطلوب وزيادة إمكانية القراءة، اختَر قيمة لنصف قطر التمويه مع طبقة شفافة من اللون.
تعتيم الخلفية
استخدام تمويه الخلفية على النوافذ العائمة لإنشاء تأثير خلفية نافذة وهو عبارة عن صورة مموّهة للمحتوى الأساسي لإضافة خلفية مموَّهة إلى نافذتك، اتّبِع الخطوات التالية:
استخدِم Window#setBackgroundBlurRadius(int) لضبط نصف قطر تعتيم الخلفية. أو في مظهر النافذة، اضبط R.attr.windowBackgroundBlurRadius.
اضبط R.attr.windowIsTranslucent على true لجعل النافذة شفافة. يتم رسم التمويه تحت سطح النافذة، لذا يجب أن تكون النافذة شفافة للسماح بظهور التمويه.
يمكنك اختياريًا استدعاء Window#setBackgroundDrawableResource(int) لإضافة عنصر قابل للرسم لخلفية نافذة مستطيلة بلون شفاف. أو في مظهر النافذة، اضبط R.attr.windowBackground.
بالنسبة إلى نافذة ذات زوايا مستديرة، حدِّد الزوايا المستديرة للمنطقة المموهة من خلال ضبط ShapeDrawable مع زوايا مستديرة كعنصر قابل للرسم لخلفية النافذة.
التعامل مع حالات التمويه المفعّلة وغير المفعّلة راجِع قسم إرشادات استخدام تمويه النافذة في التطبيقات للحصول على مزيد من المعلومات.
التمويه في الخلف
يؤدي التمويه في الخلف إلى تمويه الشاشة بأكملها خلف النافذة. يتم استخدام هذا التأثير لتوجيه انتباه المستخدم نحو محتوى النافذة من خلال تمويه أي شيء على الشاشة خلف النافذة.
لتمويه المحتوى خلف النافذة، اتّبِع الخطوات التالية:
أضِف
FLAG_BLUR_BEHIND
إلى علامات النوافذ لتفعيل التمويه في الخلفية. أو، في مظهر النافذة، اضبط R.attr.windowBlurBehindEnabled.اتّصِل بالرقم
WindowManager.LayoutParams#setBlurBehindRadius
لضبط نصف قطر التمويه في الخلفية. أو، في مظهر النافذة، اضبط R.attr.windowBlurBehindRadius.يمكنك اختياريًا اختيار مقدار التعتيم المكمّل.
التعامل مع حالات التمويه المفعّلة وغير المفعّلة راجِع قسم إرشادات استخدام تمويه النافذة في التطبيقات للحصول على مزيد من المعلومات.
إرشادات لاستخدام تمويه النافذة في التطبيقات
يعتمد توفُّر ميزة تمويه النوافذ على ما يلي:
إصدار Android: لا تتوفّر واجهات برمجة التطبيقات الخاصة بتأثير التمويه على النوافذ إلا على الإصدار 12 من نظام التشغيل Android والإصدارات الأحدث. تحقَّق من حزمة تطوير البرامج (SDK) للجهاز لمعرفة إصدار Android.
أداء الرسومات: قد لا تتيح الأجهزة التي تتضمّن وحدات معالجة رسومات أقل أداءً تأثيرات التمويه في النوافذ.
حالة النظام: قد يوقف خادم النظام مؤقتًا تمويه النوافذ في وقت التشغيل، مثلاً، أثناء وضع توفير البطارية أو أثناء تشغيل أنواع معيّنة من محتوى الفيديو أو بسبب إلغاء المطوّر للإعدادات التلقائية.
للتأكّد من توافق تطبيقك مع جميع إصدارات Android والأجهزة وحالات النظام، اتّبِع الإرشادات التالية:
أضِف أداة معالجة من خلال WindowManager#addCrossWindowBlurEnabledListener، لإعلامك عند تفعيل أو إيقاف تمويه النوافذ. بالإضافة إلى ذلك، استخدِم
WindowManager#isCrossWindowBlurEnabled
للاستعلام عمّا إذا كانت تمويهات النوافذ مفعّلة حاليًا.نفِّذ إصدارَين لخلفية النافذة لاستيعاب حالة التمويه المفعَّل أو غير المفعَّل.
عند تفعيل التمويه، يجب أن تكون خلفية النافذة شفافة جزئيًا لكي يظهر التمويه. في هذه الحالة، عند إيقاف عمليات التعتيم، يتداخل محتوى النافذة مباشرةً مع محتوى النافذة الأساسية، ما يجعل النافذة المتداخلة أقل وضوحًا. لتجنُّب هذا التأثير، عند إيقاف تمويه النوافذ، يجب تعديل واجهة مستخدم التطبيق على النحو التالي:
لتمويه الخلفية، يجب زيادة قيمة قناة ألفا الخاصة بعنصر الرسم الخاص بخلفية النافذة، ما يجعلها أكثر عتامة.
لتمويه الخلفية، أضِف طبقة تعتيم بمقدار تعتيم أعلى.
مثال على التمويه في الخلفية وتمويه الخلفية
يوفر هذا القسم مثالاً عمليًا لنشاط يستخدم كلاً من التمويه في الخلفية والتمويه في الخلفية.
المثال التالي على 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 وحدة بكسل مستقلة الكثافة على النحو التالي:
<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) كافية.
إذا كان لديك محرّك عرض مخصّص، تأكَّد من أنّ محرّك العرض ينفّذ منطق التمويه. يتم تنفيذ منطق التمويه في
BlurFilter.cpp
بواسطة محرك العرض التلقائي في Android 12.
بعد التأكّد من أنّ جهازك يتيح تمويه النوافذ، اضبط sysprop
SurfaceFlinger على ما يلي:
PRODUCT_VENDOR_PROPERTIES += \
ro.surface_flinger.supports_background_blur=1
التحقُّق
للتأكّد من أنّ نافذة تطبيقك تتعامل بشكل سليم عند التبديل بين حالتي التمويه المفعَّل وغير المفعَّل، اتّبِع الخطوات التالية:
افتح واجهة المستخدم التي تتضمّن التمويه.
يمكنك تفعيل تمويه النوافذ أو إيقافه من خلال تفعيل تمويه النوافذ أو إيقافه.
تأكَّد من أنّ واجهة مستخدم النافذة تتغيّر من حالة ضبابية وإليها على النحو المتوقّع.
تفعيل تعتيم النافذة وإيقافه
لاختبار طريقة عرض واجهة مستخدم النافذة مع تأثيرات التمويه، فعِّل التمويه أو أوقِفه باستخدام إحدى الطرق التالية:
من "خيارات المطوّرين":
الإعدادات -> النظام -> خيارات المطوّرين -> العرض المستند إلى تسريع الأجهزة -> السماح بتأثيرات التمويه على مستوى النافذة
من الوحدة الطرفية على جهاز تم عمل روت له:
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 افتراضي تنشئه باستخدام المحاكي مع تمويهات النوافذ.
ما مِن زوايا دائرية
- اضبط عنصرًا قابلاً للرسم لخلفية النافذة لتحديد الزوايا المنحنية. يحدّد هذا العنصر القابل للرسم شكل المنطقة المموهة.
تعديل خيار المطوّرين لا يؤدي إلى تفعيل التمويهات
- تحقَّق مما إذا كان الجهاز في وضع توفير شحن البطارية أو ما إذا كان يستخدم نقل البيانات المتعددة الوسائط. على بعض أجهزة التلفزيون، قد يتم أيضًا إيقاف تمويه النوافذ أثناء تشغيل الفيديو.
تمويه الخلفية على كامل الشاشة، وليس ضمن حدود النافذة
تحقَّق من android:windowIsFloating للتأكّد من وضع علامة على النافذة باعتبارها عائمة.
تأكَّد من ضبط عنصر قابل للرسم لخلفية النافذة. يحدّد هذا الخيار مخطط منطقة التمويه.
لا يتم تطبيق التعديلات من المستمع على الشاشة
- من المحتمل أن يتم تطبيق تعديلات معالج الأحداث على مثيل نافذة قديم. تحقَّق ممّا إذا كان يتم إغلاق النافذة وإعادة إنشائها مع تعديل المستمع المناسب.