การเบลอหน้าต่าง

ใน Android 12 มี API สาธารณะให้ใช้ เพื่อใช้เอฟเฟกต์เบลอหน้าต่าง เช่น เบลอพื้นหลังและเบลอข้างหลัง

การเบลอหน้าต่างหรือการเบลอข้ามหน้าต่างใช้เพื่อเบลอหน้าจอที่อยู่ด้านหลังหน้าต่างที่ระบุ การเบลอหน้าต่างมี 2 ประเภท ซึ่งใช้เพื่อสร้างเอฟเฟกต์ภาพที่แตกต่างกันได้

  • การเบลอพื้นหลังช่วยให้คุณสร้างหน้าต่างที่มีพื้นหลังเบลอ สร้างเอฟเฟกต์กระจกฝ้า

  • เบลอพื้นหลังช่วยให้คุณเบลอทั้งหน้าจอที่อยู่ด้านหลังหน้าต่าง (กล่องโต้ตอบ) เพื่อสร้างเอฟเฟกต์ระยะชัดลึก

คุณใช้เอฟเฟกต์ทั้ง 2 อย่างแยกกันหรือใช้ร่วมกันก็ได้ ดังที่แสดงในรูปต่อไปนี้

เบลอพื้นหลังเท่านั้น

a

เบลอเฉพาะด้านหลัง

b

เบลอพื้นหลังและเบลอพื้นหลัง

รูปที่ 1 เบลอพื้นหลังเท่านั้น (ก), เบลอเฉพาะด้านหลัง (ข), เบลอพื้นหลังและเบลอเฉพาะด้านหลัง (ค)

ฟีเจอร์เบลอหน้าต่างจะทำงานในหน้าต่างต่างๆ ซึ่งหมายความว่าจะทำงานได้แม้ว่าจะมีแอปอื่นอยู่เบื้องหลังหน้าต่างของคุณ เอฟเฟกต์นี้ไม่เหมือนกับเอฟเฟกต์การแสดงผลแบบเบลอ ซึ่งจะเบลอเนื้อหาภายในหน้าต่างเดียวกัน การเบลอหน้าต่างมีประโยชน์สำหรับกล่องโต้ตอบ Bottom Sheet และหน้าต่างลอยอื่นๆ

การใช้งาน

นักพัฒนาแอป

นักพัฒนาแอปต้องระบุรัศมีการเบลอเพื่อสร้างเอฟเฟกต์เบลอ รัศมีการเบลอจะควบคุมความหนาแน่นของการเบลอ กล่าวคือ ยิ่งรัศมีสูง การเบลอก็จะยิ่งหนาแน่น ค่าเบลอ 0 พิกเซลหมายถึงไม่มีการเบลอ สำหรับเบลอพื้นหลัง รัศมี 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. เลือกจำนวนหรี่ที่เสริมกัน (ไม่บังคับ)

  4. จัดการสถานะเปิดและปิดใช้การเบลอแฮนเดิล ดูข้อมูลเพิ่มเติมได้ที่ส่วนหลักเกณฑ์การใช้การเบลอหน้าต่างในแอป

หลักเกณฑ์ในการใช้การเบลอหน้าต่างในแอป

การรองรับการเบลอหน้าต่างขึ้นอยู่กับสิ่งต่อไปนี้

  • เวอร์ชัน Android: API การเบลอหน้าต่างใช้ได้ใน Android 12 ขึ้นไปเท่านั้น ตรวจสอบ SDK ของอุปกรณ์สำหรับเวอร์ชัน Android

  • ประสิทธิภาพกราฟิก: อุปกรณ์ที่มี GPU ประสิทธิภาพต่ำอาจเลือกไม่รองรับการเบลอหน้าต่าง

  • สถานะระบบ: เซิร์ฟเวอร์ระบบอาจปิดเบลอหน้าต่างชั่วคราวใน รันไทม์ เช่น ในโหมดประหยัดแบตเตอรี ขณะเล่นวิดีโอ บางประเภท หรือเนื่องจากการลบล้างของนักพัฒนาแอป

หากต้องการให้แอปของคุณใช้งานได้กับ Android เวอร์ชัน อุปกรณ์ และสถานะระบบต่างๆ ให้ทำตามหลักเกณฑ์ต่อไปนี้

  • เพิ่ม Listener ผ่าน WindowManager#addCrossWindowBlurEnabledListener เพื่อแจ้งให้คุณทราบเมื่อมีการเปิดหรือปิดใช้การเบลอหน้าต่าง นอกจากนี้ ให้ใช้ WindowManager#isCrossWindowBlurEnabled เพื่อค้นหาว่ามีการเปิดใช้การเบลอหน้าต่างอยู่หรือไม่

  • ใช้พื้นหลังหน้าต่าง 2 เวอร์ชันเพื่อให้รองรับสถานะเปิดหรือปิดใช้การเบลอหน้าต่าง

    เมื่อเปิดใช้การเบลอ พื้นหลังของหน้าต่างควรโปร่งแสงเพื่อให้มองเห็นการเบลอ ในสถานะนี้ เมื่อปิดใช้การเบลอ เนื้อหาของหน้าต่างจะ ซ้อนทับกับเนื้อหาของหน้าต่างด้านล่างโดยตรง ทำให้ หน้าต่างที่ซ้อนทับอ่านยากขึ้น หากต้องการหลีกเลี่ยงผลกระทบดังกล่าว เมื่อปิดใช้การเบลอหน้าต่าง ให้ปรับ UI ของแอปดังนี้

    • สําหรับการเบลอพื้นหลัง ให้เพิ่มค่าอัลฟ่าของพื้นหลังหน้าต่าง drawable เพื่อให้ทึบแสงมากขึ้น

    • หากต้องการเบลอพื้นหลัง ให้เพิ่มเลเยอร์หรี่แสงที่มีค่าการหรี่แสงสูงขึ้น

ตัวอย่างการเบลอพื้นหลังและเบลอพื้นหลัง

ส่วนนี้แสดงตัวอย่างการทำงานของกิจกรรมที่ใช้ทั้ง blur behind และการเบลอพื้นหลัง

ตัวอย่างต่อไปนี้ของ MainActivity.java คือกล่องโต้ตอบที่มีรัศมีการเบลอ ด้านหลัง 20 พิกเซลและรัศมีการเบลอพื้นหลัง 80 พิกเซล โดยมี มุมโค้งมนที่กำหนดไว้ใน XML ใน Drawable ของพื้นหลังหน้าต่าง โดยจะจัดการเวอร์ชัน Android ต่างๆ อุปกรณ์ต่างๆ (ที่อาจไม่รองรับการเบลอหน้าต่าง) และการเปลี่ยนแปลงที่เปิดหรือปิดใช้การเบลอรันไทม์ได้อย่างถูกต้อง ซึ่งจะช่วยให้เนื้อหาในกล่องโต้ตอบอ่านได้ในทุกกรณีโดยการปรับค่าอัลฟ่าของ Drawable พื้นหลังของหน้าต่างและปริมาณการหรี่แสงของหน้าต่าง

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>

OEM และพาร์ทเนอร์

หากต้องการให้มีฟีเจอร์เบลอหน้าต่างในอุปกรณ์ OEM ต้องประกาศว่าอุปกรณ์ รองรับการเบลอหน้าต่าง

หากต้องการตรวจสอบว่าอุปกรณ์รองรับการเบลอหน้าต่างหรือไม่ ให้ทำดังนี้

  • ตรวจสอบว่าอุปกรณ์สามารถรับภาระงาน GPU ที่เพิ่มขึ้นได้ อุปกรณ์รุ่นล่าง อาจรับภาระงานที่เพิ่มขึ้นไม่ไหว ซึ่งอาจทำให้เฟรมหลุด เปิดใช้การเบลอหน้าต่างเฉพาะในอุปกรณ์ที่ผ่านการทดสอบและมีกำลัง GPU เพียงพอเท่านั้น

  • หากคุณมีเครื่องมือแสดงผลที่ปรับแต่งเอง โปรดตรวจสอบว่าเครื่องมือแสดงผล ใช้ตรรกะการเบลอ เครื่องมือแสดงผล ของ Android 12 เริ่มต้น ใช้ตรรกะการเบลอใน BlurFilter.cpp

เมื่อตรวจสอบแล้วว่าอุปกรณ์รองรับการเบลอหน้าต่าง ให้ตั้งค่า surface flinger sysprop ดังนี้

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

การตรวจสอบความถูกต้อง

หากต้องการตรวจสอบว่าหน้าต่างแอปมีการจัดการที่เหมาะสมเมื่อสลับระหว่างสถานะเบลอ ที่เปิดใช้และเบลอที่ปิดใช้ ให้ทำตามขั้นตอนต่อไปนี้

  1. เปิด UI ที่มีเบลอ

  2. เปิดหรือปิดใช้การเบลอหน้าต่างโดยเปิดและปิดการเบลอหน้าต่าง

  3. ตรวจสอบว่า UI ของหน้าต่างเปลี่ยนเป็นและออกจากสถานะเบลอตามที่คาดไว้

เปิดและปิดการเบลอหน้าต่าง

หากต้องการทดสอบว่า UI ของหน้าต่างแสดงผลอย่างไรเมื่อมีเอฟเฟกต์เบลอหน้าต่าง ให้เปิดหรือ ปิดใช้การเบลอโดยใช้วิธีใดวิธีหนึ่งต่อไปนี้

  • จากตัวเลือกสำหรับนักพัฒนาแอป

    การตั้งค่า -> ระบบ -> ตัวเลือกสำหรับนักพัฒนาแอป -> การแสดงผลที่เร่งด้วยฮาร์ดแวร์ -> อนุญาตการเบลอระดับหน้าต่าง

  • จากเทอร์มินัลในอุปกรณ์ที่รูท ให้ทำดังนี้

    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 เพื่อให้แน่ใจว่ามีการทำเครื่องหมายหน้าต่างเป็นแบบลอย

  • ตรวจสอบว่าได้ตั้งค่า drawable พื้นหลังของหน้าต่างแล้ว การตั้งค่านี้จะกำหนด เส้นขอบของพื้นที่เบลอ

การอัปเดตจาก Listener จะไม่แสดงบนหน้าจอ

  • การอัปเดต Listener อาจมีผลกับอินสแตนซ์หน้าต่างเก่า ตรวจสอบว่าหน้าต่างถูกทำลายและสร้างใหม่ด้วยการอัปเดต Listener ที่ถูกต้องหรือไม่