ใน Android 12 มี API สาธารณะที่พร้อมใช้งานสำหรับการใช้เอฟเฟกต์การเบลอหน้าต่าง เช่น การเบลอพื้นหลังและการเบลอเบื้องหลัง
การเบลอหน้าต่างหรือการเบลอข้ามหน้าต่างใช้เพื่อเบลอหน้าจอด้านหลังหน้าต่างที่กำหนด การเบลอหน้าต่างมี 2 ประเภท ซึ่งสามารถใช้เพื่อให้ได้เอฟเฟกต์ภาพที่แตกต่างกัน ดังนี้
การเบลอพื้นหลังช่วยให้คุณสร้างหน้าต่างที่มีพื้นหลังเบลอได้ ซึ่งจะสร้างเอฟเฟกต์กระจกฝ้า
เบลอพื้นหลังช่วยให้คุณเบลอทั้งหน้าจอที่อยู่ด้านหลังหน้าต่าง (กล่องโต้ตอบ) ซึ่งจะสร้างเอฟเฟกต์ระยะชัดลึก
คุณจะใช้เอฟเฟกต์ทั้ง 2 แบบแยกกันหรือใช้ร่วมกันก็ได้ ดังที่แสดงในภาพต่อไปนี้
a |
b |
![]() c |
รูปที่ 1 เบลอพื้นหลังเท่านั้น (ก) เบลอเฉพาะด้านหลัง (ข) เบลอพื้นหลังและเบลอด้านหลัง (ค)
ฟีเจอร์เบลอหน้าต่างจะทำงานในหน้าต่างต่างๆ ซึ่งหมายความว่าจะทำงานเมื่อมีแอปอื่นอยู่หลังหน้าต่างด้วย เอฟเฟกต์นี้ไม่เหมือนกับเอฟเฟกต์การแสดงผลแบบเบลอ ซึ่งจะเบลอเนื้อหาภายในหน้าต่างเดียวกัน การเบลอหน้าต่างมีประโยชน์สำหรับกล่องโต้ตอบ, Bottom Sheet และหน้าต่างแบบลอยอื่นๆ
การใช้งาน
นักพัฒนาแอป
นักพัฒนาแอปต้องระบุรัศมีการเบลอเพื่อสร้างเอฟเฟกต์เบลอ รัศมีการเบลอจะควบคุมความหนาแน่นของการเบลอ กล่าวคือ ยิ่งรัศมีสูง การเบลอก็จะยิ่งหนาแน่น การเบลอ 0 พิกเซลหมายความว่าไม่มีการเบลอ สำหรับการเบลอพื้นหลัง รัศมี 20 px จะสร้างเอฟเฟกต์ระยะชัดลึกที่ดี ส่วนรัศมีการเบลอพื้นหลัง 80 px จะสร้างเอฟเฟกต์กระจกฝ้าที่ดี หลีกเลี่ยงรัศมีการเบลอที่สูงกว่า 150 พิกเซล เนื่องจากจะส่งผลต่อประสิทธิภาพอย่างมาก
หากต้องการให้ได้เอฟเฟกต์เบลอที่ต้องการและเพิ่มความสามารถในการอ่าน ให้เลือกค่ารัศมีการเบลอที่เสริมด้วยเลเยอร์สีโปร่งแสง
การเบลอพื้นหลัง
ใช้การเบลอพื้นหลังในหน้าต่างแบบลอยเพื่อสร้างเอฟเฟกต์พื้นหลังของหน้าต่าง ซึ่งเป็นภาพเบลอของเนื้อหาที่อยู่ด้านล่าง หากต้องการเพิ่มพื้นหลังเบลอสำหรับหน้าต่าง ให้ทำดังนี้
เรียกใช้ Window#setBackgroundBlurRadius(int) เพื่อตั้งค่ารัศมีการเบลอพื้นหลัง หรือตั้งค่า R.attr.windowBackgroundBlurRadius ในธีมหน้าต่าง
ตั้งค่า R.attr.windowIsTranslucent เป็นจริงเพื่อให้หน้าต่างโปร่งแสง ระบบจะวาดภาพเบลอใต้พื้นผิวหน้าต่าง ดังนั้นหน้าต่างจึงต้องโปร่งแสงเพื่อให้มองเห็นภาพเบลอได้
หรือจะเรียกใช้ Window#setBackgroundDrawableResource(int) เพื่อเพิ่มทรัพยากรที่ถอนออกได้ของพื้นหลังหน้าต่างสี่เหลี่ยมผืนผ้าที่มีสีโปร่งแสงก็ได้ หรือตั้งค่า R.attr.windowBackground ในธีมหน้าต่าง
สำหรับหน้าต่างที่มีมุมโค้งมน ให้กำหนดมุมโค้งมนสำหรับพื้นที่ที่เบลอโดยตั้งค่า ShapeDrawable ที่มีมุมโค้งมนเป็น Drawable พื้นหลังของหน้าต่าง
จัดการสถานะเปิดใช้และปิดใช้การเบลอ ดูข้อมูลเพิ่มเติมได้ที่ส่วนหลักเกณฑ์การใช้การเบลอหน้าต่างในแอป
เบลอพื้นหลัง
การเบลอพื้นหลังจะเบลอทั้งหน้าจอที่อยู่ด้านหลังหน้าต่าง เอฟเฟกต์นี้ใช้เพื่อดึงดูดความสนใจของผู้ใช้ไปยังเนื้อหาของหน้าต่างโดยการเบลอทุกอย่างบนหน้าจอด้านหลังหน้าต่าง
หากต้องการเบลอเนื้อหาด้านหลังหน้าต่าง ให้ทำตามขั้นตอนต่อไปนี้
เพิ่ม
FLAG_BLUR_BEHINDลงในแฟล็กหน้าต่างเพื่อเปิดใช้การเบลอด้านหลัง หรือตั้งค่า R.attr.windowBlurBehindEnabled ในธีมหน้าต่างเรียกใช้
WindowManager.LayoutParams#setBlurBehindRadiusเพื่อตั้งค่ารัศมีการเบลอพื้นหลัง หรือตั้งค่า R.attr.windowBlurBehindRadius ในธีมหน้าต่างเลือกปริมาณแสงสลัวที่สอดคล้องกัน (ไม่บังคับ)
จัดการสถานะเปิดใช้และปิดใช้การเบลอ ดูข้อมูลเพิ่มเติมได้ที่ส่วนหลักเกณฑ์การใช้การเบลอหน้าต่างในแอป
หลักเกณฑ์ในการใช้การเบลอหน้าต่างในแอป
การรองรับการเบลอหน้าต่างขึ้นอยู่กับสิ่งต่อไปนี้
เวอร์ชัน Android: API การเบลอหน้าต่างใช้ได้ใน Android 12 ขึ้นไปเท่านั้น ตรวจสอบ SDK ของอุปกรณ์เพื่อดูเวอร์ชัน Android
ประสิทธิภาพกราฟิก: อุปกรณ์ที่มี GPU ประสิทธิภาพต่ำอาจเลือกไม่รองรับการเบลอหน้าต่าง
สถานะของระบบ: เซิร์ฟเวอร์ระบบอาจปิดใช้การเบลอหน้าต่างชั่วคราวที่รันไทม์ เช่น ในระหว่างโหมดประหยัดแบตเตอรี่ ขณะเล่นเนื้อหาวิดีโอบางประเภท หรือเนื่องจากการลบล้างของนักพัฒนาแอป
โปรดทำตามหลักเกณฑ์ต่อไปนี้เพื่อให้แอปของคุณเข้ากันได้กับ Android เวอร์ชันต่างๆ อุปกรณ์ และสถานะระบบ
เพิ่ม Listener ผ่าน WindowManager#addCrossWindowBlurEnabledListener เพื่อแจ้งให้คุณทราบเมื่อเปิดหรือปิดใช้การเบลอข้ามหน้าต่าง นอกจากนี้ ให้ใช้
WindowManager#isCrossWindowBlurEnabledเพื่อค้นหาว่ามีการเปิดใช้การเบลอหน้าต่างอยู่หรือไม่ใช้พื้นหลังของหน้าต่าง 2 เวอร์ชันเพื่อรองรับสถานะเปิดใช้หรือปิดใช้การเบลอหน้าต่าง
เมื่อเปิดใช้การเบลอ พื้นหลังของหน้าต่างควรโปร่งแสงเพื่อให้มองเห็นการเบลอได้ ในสถานะนี้ เมื่อปิดใช้การเบลอ เนื้อหาของหน้าต่างจะซ้อนทับกับเนื้อหาของหน้าต่างที่อยู่ด้านล่างโดยตรง ทำให้หน้าต่างที่ซ้อนทับกันอ่านได้ยากขึ้น เพื่อหลีกเลี่ยงผลกระทบดังกล่าว เมื่อปิดใช้การเบลอหน้าต่าง ให้ปรับ UI ของแอปดังนี้
สำหรับการเบลอพื้นหลัง ให้เพิ่มอัลฟ่าของพื้นหลังหน้าต่างที่วาดได้เพื่อให้ทึบแสงมากขึ้น
หากต้องการเบลอพื้นหลัง ให้เพิ่มเลเยอร์หรี่แสงที่มีปริมาณการหรี่แสงสูงขึ้น
ตัวอย่างการเบลอพื้นหลังและเบลอเฉพาะด้านหลัง
ส่วนนี้แสดงตัวอย่างการทำงานของกิจกรรมที่ใช้ทั้งการเบลอพื้นหลังและเบลอฉากหลัง
ตัวอย่างต่อไปนี้ของ MainActivity.java คือกล่องโต้ตอบที่มีรัศมีการเบลอด้านหลัง 20 px และรัศมีการเบลอพื้นหลัง 80 px โดยมีมุมโค้งมนซึ่งกำหนดไว้ใน 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 ที่มีมุมโค้งมนที่มีรัศมี 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
การตรวจสอบ
หากต้องการตรวจสอบว่าหน้าต่างแอปมีการจัดการที่เหมาะสมเมื่อสลับระหว่างสถานะเปิดใช้การเบลอและปิดใช้การเบลอ ให้ทำตามขั้นตอนต่อไปนี้
เปิด UI ที่มีการเบลอ
เปิดหรือปิดใช้การเบลอหน้าต่างโดยเปิดและปิดการเบลอหน้าต่าง
ยืนยันว่า 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 ที่คุณสร้างด้วยโปรแกรมจำลองจะรองรับการเบลอหน้าต่าง
ไม่มีมุมโค้งมน
- ตั้งค่าพื้นหลังของหน้าต่างที่วาดได้เพื่อกำหนดมุมโค้งมน Drawable นี้จะกำหนดโครงร่างของพื้นที่ที่เบลอ
การอัปเดตตัวเลือกสำหรับนักพัฒนาแอปไม่ได้เปิดใช้การเบลอ
- ตรวจสอบว่าอุปกรณ์อยู่ในโหมดประหยัดแบตเตอรี่หรือใช้การสร้างทันเนลแบบมัลติมีเดียหรือไม่ ในอุปกรณ์ทีวีบางรุ่น ระบบอาจปิดใช้การเบลอหน้าต่างระหว่างการเล่นวิดีโอด้วย
การเบลอพื้นหลังจะแสดงแบบเต็มหน้าจอ ไม่ใช่ภายในขอบเขตของหน้าต่าง
ตรวจสอบ android:windowIsFloating เพื่อให้แน่ใจว่าหน้าต่างของคุณได้รับการทำเครื่องหมายเป็นแบบลอย
ตรวจสอบว่าได้ตั้งค่าพื้นหลังของหน้าต่างที่วาดได้แล้ว การตั้งค่านี้จะกำหนดโครงร่างของพื้นที่เบลอ
การอัปเดตจาก Listener จะไม่มีผลบนหน้าจอ
- การอัปเดต Listener อาจมีผลกับอินสแตนซ์หน้าต่างเก่า ตรวจสอบว่าหน้าต่างถูกทำลายและสร้างขึ้นใหม่ด้วยการอัปเดต Listener ที่ถูกต้องหรือไม่
