טשטוש חלונות

ב-Android 12 יש ממשקי API ציבוריים להטמעת אפקטים של טשטוש חלונות, כמו טשטוש רקע וטשטוש מאחורי.

טשטוש חלונות או טשטוש חלונות חוצפים משמשים לטשטוש המסך מאחורי החלון הנתון. יש שני סוגים של טשטוש חלונות, שאפשר להשתמש בהם כדי ליצור אפקטים חזותיים שונים:

  • טשטוש הרקע מאפשר ליצור חלונות עם רקעים מטושטשים, וליצור אפקט של זכוכית מט.

  • התכונה טשטוש מאחור מאפשרת לטשטש את כל המסך מאחורי חלון (תיבת דו-שיח), וכך ליצור אפקט של עומק שדה.

אפשר להשתמש בשני האפקטים בנפרד או בשילוב, כפי שמוצג באיור הבא:

טשטוש רקע בלבד

a

טשטוש רקע בלבד

b

טשטוש מאחור וטשטוש רקע

c

איור 1. טשטוש רקע בלבד (א'), טשטוש רקע מאחורי הנושא בלבד (ב'), טשטוש רקע וטשטוש מאחורי הנושא (ג')

התכונה 'טשטוש חלון' פועלת בכל החלונות, כלומר היא פועלת גם כשיש אפליקציה אחרת מאחורי החלון. האפקט הזה שונה מאפקט הרינדור עם טשטוש, שבו התוכן מטושטש בתוך אותו חלון. טשטוש חלונות שימושי בתיבות דו-שיח, בגיליון תחתון ובחלונות צפים אחרים.

הטמעה

מפתחי אפליקציות

מפתחי האפליקציות צריכים לספק רדיוס טשטוש כדי ליצור אפקט טשטוש. רדיוס הטשטוש קובע את הצפיפות של הטשטוש. ככל שהרדיוס גדול יותר, כך הטשטוש צפוף יותר. ערך טשטוש של 0px פירושו שאין טשטוש. לטשטוש מאחור, רדיוס של 20 פיקסלים יוצר אפקט טוב של עומק שדה, ואילו רדיוס של 80 פיקסלים יוצר אפקט טוב של זכוכית מט. מומלץ להימנע מרדיאנים של טשטוש גדולים מ-150 פיקסלים, כי הם ישפיעו באופן משמעותי על הביצועים.

כדי להשיג את אפקט הטשטוש הרצוי ולשפר את הקריאות, כדאי לבחור ערך של רדיוס הטשטוש עם שכבת צבע שקופה.

טשטוש הרקע

אתם יכולים להשתמש בטשטוש הרקע בחלונות צפים כדי ליצור אפקט של רקע בחלון, שהוא תמונה מטושטשת של התוכן שמתחתיו. כדי להוסיף רקע מטושטש לחלון:

  1. קוראים ל-Window#setBackgroundBlurRadius(int) כדי להגדיר את רדיוס הטשטוש של הרקע. לחלופין, בעיצוב החלון, מגדירים את R.attr.windowBackgroundBlurRadius.

  2. כדי שהחלון יהיה שקוף, מגדירים את הערך של R.attr.windowIsTranslucent ל-true. הטשטוש מצויר מתחת לפני השטח של החלון, ולכן החלון צריך להיות שקוף כדי שהטשטוש יהיה גלוי.

  3. אפשר גם להפעיל את Window#setBackgroundDrawableResource(int) כדי להוסיף drawable של רקע חלון מלבני בצבע שקוף. לחלופין, בעיצוב החלון, מגדירים את R.attr.windowBackground.

  4. בחלון עם פינות מעוגלות, כדי לקבוע את הפינות המעוגלות של האזור המטושטש, מגדירים ShapeDrawable עם פינות מעוגלות בתור drawable של רקע החלון.

  5. טיפול במצבים של טשטוש מופעל ומושבת. מידע נוסף זמין בקטע הנחיות לשימוש בחלון מטושטש באפליקציות.

טשטוש הרקע

הטשטוש מאחור מטשטש את כל המסך שמאחורי החלון. האפקט הזה משמש להפניית תשומת הלב של המשתמש לתוכן החלון על ידי טשטוש כל מה שמופיע במסך מאחורי החלון.

כדי לטשטש את התוכן שמאחורי החלון:

  1. מוסיפים את הערך FLAG_BLUR_BEHIND לדגלי החלון כדי להפעיל את הטשטוש של הרקע. לחלופין, בעיצוב החלון, מגדירים את הערך R.attr.windowBlurBehindEnabled.

  2. קוראים לפונקציה WindowManager.LayoutParams#setBlurBehindRadius כדי להגדיר את רדיוס הטשטוש שמאחורי האובייקט. לחלופין, בעיצוב החלון, מגדירים את הערך R.attr.windowBlurBehindRadius.

  3. אפשר גם לבחור dim amount משלים.

  4. טיפול במצבים של טשטוש מופעל ומושבת. מידע נוסף זמין בקטע הנחיות לשימוש בחלון מטושטש באפליקציות.

הנחיות לשימוש בהחלקה של חלונות באפליקציות

התמיכה בהחלשה של חלונות תלויה בגורמים הבאים:

  • גרסת Android: ממשקי ה-API של טשטוש החלונות זמינים רק ב-Android מגרסה 12 ואילך. בודקים את גרסת Android ב-SDK של המכשיר.

  • ביצועי הגרפיקה: במכשירים עם מעבדי GPU עם ביצועים נמוכים יותר, יכול להיות שלא תהיה תמיכה בהחלשות חלונות.

  • מצב המערכת: שרת המערכת עשוי להשבית באופן זמני את טשטוש החלונות במהלך זמן הריצה, למשל במצב חיסכון בסוללה, במהלך הפעלה של סוגים מסוימים של תוכן וידאו או עקב שינוי מברירת המחדל על ידי מפתח.

כדי שהאפליקציה תהיה תואמת לגרסאות, למכשירים ולמצבי מערכת שונים של Android, יש לפעול לפי ההנחיות הבאות:

  • מוסיפים מאזין באמצעות WindowManager#addCrossWindowBlurEnabledListener כדי לקבל התראות כשהערפול של החלונות מופעל או מושבת. בנוסף, אפשר להשתמש ב-WindowManager#isCrossWindowBlurEnabled כדי לבדוק אם האפקט של טשטוש החלונות מופעל כרגע.

  • מטמיעים שתי גרסאות לרקע החלון, כדי להתאים את מצב הטשטוש של החלון למצב מופעל או מושבת.

    כשהטשטושים מופעלים, הרקע של החלון צריך להיות שקוף כדי שהטשטוש יהיה גלוי. במצב הזה, כשהטשטושים מושבתים, תוכן החלון חופף ישירות לתוכן של החלון שמתחתיו, וכתוצאה מכך קשה יותר לקרוא את התוכן בחלון החופף. כדי למנוע את האפקט הזה, כשהערפול של החלונות מושבת, צריך לשנות את ממשק המשתמש של האפליקציה באופן הבא:

    • כדי לטשטש את הרקע, צריך להגדיל את ערך האלפא של drawable של רקע החלון, כך שהוא יהיה אטום יותר.

    • כדי לטשטש את הרקע, מוסיפים שכבה עם עמעום בעוצמה גבוהה יותר.

דוגמה לטשטוש מאחורי הנושא וטשטוש הרקע

בקטע הזה מוצגת דוגמה לפעילות שבה נעשה שימוש גם בטשטוש של הרקע וגם בטשטוש של הרקע שמאחורי הנושא.

הדוגמה הבאה של MainActivity.java היא תיבת דו-שיח עם רדיוס טשטוש של 20px מאחורי התמונה ורדיוס טשטוש של 80px ברקע. יש לו פינות מעוגלות, שמוגדרות ב-XML ב-drawable של רקע החלון. הוא מטפל בצורה נכונה בגרסאות שונות של 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 עם פינות מעוגלות ברדיוס 20dp באופן הבא:

<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>

יצרני ציוד מקורי (OEM) ושותפים

כדי לטשטש חלונות במכשיר, יצרן הציוד המקורי צריך להצהיר שהמכשיר תומך בטשטוש חלונות.

כדי לבדוק אם המכשיר תומך בהחלשה של חלונות:

  • מוודאים שהמכשיר יכול להתמודד עם העומס הנוסף על ה-GPU. יכול להיות שמכשירים ברמה נמוכה יותר לא יוכלו להתמודד עם העומס הנוסף, וכתוצאה מכך יהיו פריימים חסרים. כדאי להפעיל את טשטוש החלונות רק במכשירים שנבדקו עם מספיק כוח 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 במכשיר עם הרשאת root.

פתרון בעיות

תוכלו להיעזר במדריך הבא לפתרון בעיות במהלך האימות.

ללא טשטוש

  • מוודאים שהאפקטים של טשטוש האובייקטים מופעלים כרגע והחומרה תומכת בהם. עיינו במאמר הפעלה והשבתה של טשטוש חלונות.

  • חשוב להגדיר צבע רקע שקוף לחלון. צבע חלון שקוף מסתיר את האזור המטושטש.

המכשיר לבדיקה לא תומך בהחלשות חלונות

  • בודקים את האפליקציה באמולטור של Android 12. במאמר הגדרת אמולטור Android מוסבר איך מגדירים אמולטור Android. כל מכשיר וירטואלי של Android שיצרתם באמצעות הסימולטור תומך בהחלשות האובייקטים בחלון.

ללא פינות מעוגלות

עדכון האפשרות למפתחים לא מפעיל את האפשרויות להצגת טשטוש

  • בודקים אם המכשיר נמצא במצב חיסכון בסוללה או אם הוא משתמש במנהור מולטימדיה. בחלק ממכשירי הטלוויזיה, יכול להיות שהטשטוש של החלונות יושבת גם במהלך הפעלת הסרטון.

טשטוש הרקע מוצג במסך מלא, ולא בתוך גבולות החלון

העדכונים מהמאזין לא חלים על המסך

  • יכול להיות שהעדכונים של המאזין חלים על מכונה ישנה של חלון. בודקים אם החלון נהרס ונוצר מחדש עם עדכון הנכון של המאזין.