Trong Android 12, có các API công khai để triển khai hiệu ứng làm mờ cửa sổ, chẳng hạn như làm mờ nền và làm mờ phía sau.
Làm mờ cửa sổ hoặc làm mờ nhiều cửa sổ được dùng để làm mờ màn hình phía sau một cửa sổ nhất định. Có hai loại hiệu ứng làm mờ cửa sổ, có thể dùng để tạo ra các hiệu ứng hình ảnh khác nhau:
Làm mờ nền cho phép bạn tạo các cửa sổ có nền mờ, tạo hiệu ứng kính mờ.
Làm mờ phía sau cho phép bạn làm mờ toàn bộ màn hình phía sau cửa sổ (hộp thoại), tạo hiệu ứng độ sâu trường.
Bạn có thể sử dụng riêng hoặc kết hợp hai hiệu ứng này, như minh hoạ trong hình sau:
![]() a |
![]() b |
![]() c |
Hình 1. Chỉ làm mờ nền (a), chỉ làm mờ phía sau (b), làm mờ nền và làm mờ phía sau (c)
Tính năng làm mờ cửa sổ hoạt động trên các cửa sổ, tức là tính năng này cũng hoạt động khi có một ứng dụng khác ở phía sau cửa sổ. Hiệu ứng này không giống với hiệu ứng kết xuất làm mờ, làm mờ nội dung bên trong cùng một cửa sổ. Tính năng làm mờ cửa sổ rất hữu ích cho hộp thoại, bảng dưới cùng và các cửa sổ nổi khác.
Triển khai
Nhà phát triển ứng dụng
Nhà phát triển ứng dụng phải cung cấp bán kính làm mờ để tạo hiệu ứng làm mờ. Bán kính làm mờ kiểm soát độ đậm nhạt của hiệu ứng làm mờ, tức là bán kính càng cao thì hiệu ứng làm mờ càng đậm. Độ mờ 0 px có nghĩa là không có độ mờ. Đối với hiệu ứng làm mờ phía sau, bán kính 20 px sẽ tạo ra hiệu ứng độ sâu trường tốt, trong khi bán kính làm mờ nền 80 px sẽ tạo ra hiệu ứng kính mờ tốt. Tránh bán kính làm mờ cao hơn 150 px vì điều này sẽ ảnh hưởng đáng kể đến hiệu suất.
Để đạt được hiệu ứng làm mờ mong muốn và tăng khả năng đọc, hãy chọn giá trị bán kính làm mờ bổ sung với một lớp màu trong suốt.
Làm mờ nền
Sử dụng hiệu ứng làm mờ nền trên cửa sổ nổi để tạo hiệu ứng nền cửa sổ, đó là hình ảnh mờ của nội dung cơ bản. Để thêm nền mờ cho cửa sổ, hãy làm như sau:
Gọi Window#setBackgroundBlurRadius(int) để đặt bán kính làm mờ nền. Hoặc trong giao diện cửa sổ, hãy đặt R.attr.windowBackgroundBlurRadius.
Đặt R.attr.windowIsTranslucent thành true để làm cho cửa sổ có độ mờ. Hiệu ứng làm mờ được vẽ bên dưới bề mặt cửa sổ, vì vậy, cửa sổ cần phải trong suốt để có thể nhìn thấy hiệu ứng làm mờ.
Bạn có thể gọi Window#setBackgroundDrawableResource(int) để thêm một nền cửa sổ hình chữ nhật có thể vẽ với màu trong suốt. Hoặc trong giao diện cửa sổ, hãy đặt R.attr.windowBackground.
Đối với cửa sổ có góc bo tròn, hãy xác định góc bo tròn cho vùng bị làm mờ bằng cách đặt ShapeDrawable có góc bo tròn làm nền cửa sổ có thể vẽ.
Xử lý trạng thái bật và tắt hiệu ứng làm mờ. Hãy tham khảo phần Nguyên tắc sử dụng hiệu ứng làm mờ cửa sổ trong ứng dụng để biết thêm thông tin.
Làm mờ phía sau
Hiệu ứng làm mờ phía sau làm mờ toàn bộ màn hình phía sau cửa sổ. Hiệu ứng này được dùng để hướng sự chú ý của người dùng đến nội dung cửa sổ bằng cách làm mờ mọi thứ trên màn hình phía sau cửa sổ.
Để làm mờ nội dung phía sau cửa sổ, hãy làm theo các bước sau:
Thêm
FLAG_BLUR_BEHIND
vào cờ cửa sổ để bật tính năng làm mờ phía sau. Hoặc trong giao diện cửa sổ, hãy đặt R.attr.windowBlurBehindEnabled.Gọi
WindowManager.LayoutParams#setBlurBehindRadius
để đặt độ mờ phía sau bán kính. Hoặc trong giao diện cửa sổ, hãy đặt R.attr.windowBlurBehindRadius.Bạn có thể chọn số lượng kích thước bổ sung (không bắt buộc).
Xử lý trạng thái bật và tắt hiệu ứng làm mờ. Hãy tham khảo phần Nguyên tắc sử dụng hiệu ứng làm mờ cửa sổ trong ứng dụng để biết thêm thông tin.
Nguyên tắc sử dụng hiệu ứng làm mờ cửa sổ trong ứng dụng
Việc hỗ trợ làm mờ cửa sổ phụ thuộc vào những yếu tố sau:
Phiên bản Android: API làm mờ cửa sổ chỉ có trên Android 12 trở lên. Kiểm tra SDK thiết bị để biết phiên bản Android.
Hiệu suất đồ hoạ: Các thiết bị có GPU kém hiệu quả hơn có thể chọn không hỗ trợ hiệu ứng làm mờ cửa sổ.
Trạng thái hệ thống: Máy chủ hệ thống có thể tạm thời tắt tính năng làm mờ cửa sổ trong thời gian chạy, ví dụ: trong chế độ tiết kiệm pin, trong khi phát một số loại nội dung video nhất định hoặc do nhà phát triển ghi đè.
Để ứng dụng của bạn tương thích với các phiên bản Android, thiết bị và trạng thái hệ thống, hãy làm theo các nguyên tắc sau:
Thêm trình nghe thông qua WindowManager#addCrossWindowBlurEnabledListener để thông báo cho bạn khi tính năng làm mờ cửa sổ được bật hoặc tắt. Ngoài ra, hãy sử dụng
WindowManager#isCrossWindowBlurEnabled
để truy vấn xem tính năng làm mờ cửa sổ hiện đã được bật hay chưa.Triển khai hai phiên bản cho nền cửa sổ, để phù hợp với trạng thái bật hoặc tắt của hiệu ứng làm mờ cửa sổ.
Khi bạn bật tính năng làm mờ, nền cửa sổ phải trong suốt để làm mờ hiển thị. Ở trạng thái này, khi hiệu ứng làm mờ bị tắt, nội dung cửa sổ sẽ chồng trực tiếp lên nội dung của cửa sổ cơ bản, khiến cửa sổ chồng lên khó đọc hơn. Để tránh hiệu ứng như vậy, khi chế độ làm mờ cửa sổ bị tắt, hãy điều chỉnh giao diện người dùng của ứng dụng như sau:
Đối với hiệu ứng làm mờ nền, hãy tăng độ đậm nhạt của nền cửa sổ có thể vẽ để làm cho nền trở nên mờ hơn.
Để làm mờ phía sau, hãy thêm một lớp làm mờ với độ mờ cao hơn.
Ví dụ về hiệu ứng làm mờ phía sau và làm mờ nền
Phần này cung cấp ví dụ về một hoạt động sử dụng cả hiệu ứng làm mờ phía sau và làm mờ nền.
Ví dụ sau đây về MainActivity.java
là một hộp thoại có bán kính làm mờ phía sau là 20 px và bán kính làm mờ nền là 80 px. Cửa sổ này có các góc bo tròn, được xác định trong tệp xml trong nền cửa sổ có thể vẽ. Thư viện này xử lý chính xác các phiên bản Android, các thiết bị khác nhau (có thể không hỗ trợ làm mờ cửa sổ) và các thay đổi về việc bật hoặc tắt tính năng làm mờ trong thời gian chạy. Phương thức này đảm bảo rằng nội dung hộp thoại có thể đọc được trong bất kỳ điều kiện nào trong số đó bằng cách điều chỉnh độ đậm nhạt của nền cửa sổ có thể vẽ và độ mờ của cửa sổ.
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;
}
}
Để tạo các góc bo tròn cho cửa sổ, chúng ta xác định nền cửa sổ trong res/drawable/window_background.xml
là ShapeDrawable có các góc bo tròn với bán kính 20 dp như sau:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<corners android:radius="20dp"/>
<solid android:color="#AAAAAA"/>
</shape>
Tính năng làm mờ cửa sổ làm mờ nội dung của cửa sổ bên dưới hoạt động. Hình ảnh mờ được vẽ dưới cửa sổ hoạt động này, vì vậy, cửa sổ hoạt động cần phải trong suốt để cho phép hình ảnh mờ hiển thị. Để làm cho cửa sổ mờ, chúng ta đặt R.attr.windowIsTranslucent trong giao diện hoạt động như sau:
<style name="Theme.BlurryDialog" parent="Theme.MaterialComponents.Dialog">
<item name="android:windowIsTranslucent">true</item>
</style>
Nhà sản xuất thiết bị gốc và đối tác
Để có hiệu ứng làm mờ cửa sổ trên thiết bị, nhà sản xuất thiết bị gốc (OEM) cần khai báo rằng thiết bị hỗ trợ hiệu ứng làm mờ cửa sổ.
Để kiểm tra xem thiết bị của bạn có thể hỗ trợ hiệu ứng làm mờ cửa sổ hay không, hãy làm như sau:
Đảm bảo rằng thiết bị có thể xử lý tải GPU bổ sung. Các thiết bị cấp thấp hơn có thể không xử lý được tải bổ sung, điều này có thể gây ra hiện tượng bỏ khung hình. Chỉ bật tính năng làm mờ cửa sổ trên các thiết bị được kiểm thử có đủ công suất GPU.
Nếu bạn có công cụ kết xuất tuỳ chỉnh, hãy đảm bảo rằng công cụ kết xuất của bạn triển khai logic làm mờ. Công cụ kết xuất mặc định của Android 12 triển khai logic làm mờ trong
BlurFilter.cpp
.
Sau khi bạn đảm bảo rằng thiết bị của mình có thể hỗ trợ hiệu ứng làm mờ cửa sổ, hãy đặt sysprop
trình truyền tải giao diện sau:
PRODUCT_VENDOR_PROPERTIES += \
ro.surface_flinger.supports_background_blur=1
Xác nhận kết quả
Để xác thực rằng cửa sổ ứng dụng của bạn có cách xử lý thích hợp khi chuyển đổi giữa trạng thái bật và tắt hiệu ứng làm mờ, hãy làm theo các bước sau:
Mở giao diện người dùng có hiệu ứng làm mờ.
Bật hoặc tắt hiệu ứng làm mờ cửa sổ bằng cách bật và tắt hiệu ứng làm mờ cửa sổ.
Xác minh rằng giao diện người dùng của cửa sổ thay đổi sang và từ trạng thái mờ như dự kiến.
Bật và tắt tính năng làm mờ cửa sổ
Để kiểm thử cách giao diện người dùng cửa sổ hiển thị với hiệu ứng làm mờ cửa sổ, hãy bật hoặc tắt tính năng làm mờ bằng một trong các phương thức sau:
Trong phần Tuỳ chọn cho nhà phát triển:
Cài đặt -> Hệ thống -> Tuỳ chọn cho nhà phát triển -> Kết xuất tăng tốc phần cứng -> Cho phép làm mờ ở cấp cửa sổ
Trên thiết bị đã bị can thiệp hệ thống:
adb shell wm disable-blur 1 # 1 disables window blurs, 0 allows them
Để kiểm tra xem thiết bị Android 12 trở lên có hỗ trợ tính năng làm mờ cửa sổ hay không và tính năng làm mờ cửa sổ hiện có được bật hay không, hãy chạy adb shell wm disable-blur
trên thiết bị đã bị can thiệp vào hệ thống.
Khắc phục sự cố
Hãy tham khảo hướng dẫn sau đây để khắc phục sự cố trong quá trình xác thực.
Không vẽ hiệu ứng làm mờ
Xác minh rằng hiệu ứng làm mờ hiện đang bật và phần cứng của bạn hỗ trợ hiệu ứng này. Tham khảo bài viết Bật và tắt tính năng làm mờ cửa sổ.
Đảm bảo bạn đặt màu nền cửa sổ trong suốt. Màu nền cửa sổ mờ sẽ ẩn vùng bị làm mờ.
Thiết bị kiểm thử không hỗ trợ tính năng làm mờ cửa sổ
- Kiểm thử ứng dụng trên trình mô phỏng Android 12. Để thiết lập trình mô phỏng Android, hãy tham khảo bài viết Thiết lập trình mô phỏng Android. Mọi thiết bị Android ảo mà bạn tạo bằng trình mô phỏng đều hỗ trợ tính năng làm mờ cửa sổ.
Không có góc bo tròn
- Đặt nền cửa sổ có thể vẽ để xác định các góc bo tròn. Đối tượng có thể vẽ này xác định đường viền của vùng bị làm mờ.
Việc cập nhật tuỳ chọn cho nhà phát triển không bật tính năng làm mờ
- Kiểm tra xem thiết bị có đang ở chế độ tiết kiệm pin hay không hoặc có đang sử dụng tính năng chuyển tiếp nội dung đa phương tiện hay không. Trên một số thiết bị TV, tính năng làm mờ cửa sổ cũng có thể bị tắt trong khi phát video.
Làm mờ nền được vẽ toàn màn hình, không nằm trong giới hạn cửa sổ
Kiểm tra android:windowIsFloating để đảm bảo cửa sổ của bạn được đánh dấu là nổi.
Đảm bảo bạn đã đặt nền cửa sổ có thể vẽ. Chế độ cài đặt này xác định đường viền của vùng làm mờ.
Nội dung cập nhật từ trình nghe không được áp dụng trên màn hình
- Các bản cập nhật trình nghe có thể đang được áp dụng cho một thực thể cửa sổ cũ. Kiểm tra xem cửa sổ có bị huỷ và tạo lại bằng bản cập nhật trình nghe phù hợp hay không.