Trong Android 12, các API công khai có sẵn để 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 cửa sổ đã cho. Có hai loại hiệu ứng làm mờ cửa sổ, có thể dùng để đạt được các hiệu ứng hình ảnh khác nhau:
Làm mờ nền cho phép bạn tạo 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 ảnh.
Bạn có thể sử dụng riêng hoặc kết hợp hai hiệu ứng này, như 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 nhiều 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ổ của bạn. Hiệu ứng này không giống với hiệu ứng kết xuất làm mờ, vốn làm mờ nội dung bên trong cùng một cửa sổ. Hiệu ứng làm mờ cửa sổ rất hữu ích cho các 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 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 nghĩa là không 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 ảnh 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 một giá trị bán kính làm mờ được bổ sung bằng một lớp màu mờ.
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ổ, tức là hình ảnh làm mờ của nội dung bên dưới. Để 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ổ trở nên mờ. Hiệu ứng làm mờ được vẽ dưới bề mặt cửa sổ, vì vậy cửa sổ cần phải mờ để có thể nhìn thấy hiệu ứng làm mờ.
Nếu muốn, hãy gọi Window#setBackgroundDrawableResource(int) để thêm một đối tượng có thể vẽ nền cửa sổ hình chữ nhật có 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 làm mờ bằng cách đặt ShapeDrawable có góc bo tròn làm nền cho cửa sổ.
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 sẽ 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 vào nội dung cửa sổ bằng cách làm mờ mọi nội dung 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_BEHINDvà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 bán kính làm mờ phía sau. Hoặc trong giao diện cửa sổ, hãy đặt R.attr.windowBlurBehindRadius.Nếu muốn, hãy chọn mức độ mờ bổ sung.
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 của thiết bị để biết phiên bản Android.
Hiệu suất đồ hoạ: Các thiết bị có GPU hiệu suất thấp 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, chẳng hạn như trong chế độ tiết kiệm pin, trong khi phát một số loại nội dung video hoặc do nhà phát triển ghi đè.
Để đảm bảo ứ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 dùng
WindowManager#isCrossWindowBlurEnabledđể truy vấn xem hiệu ứng làm mờ cửa sổ hiện có được bật hay không.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ật hiệu ứng làm mờ, nền cửa sổ phải mờ để có thể nhìn thấy hiệu ứng làm mờ. Ở trạng thái này, khi hiệu ứng làm mờ bị tắt, nội dung cửa sổ sẽ trực tiếp chồng lên nội dung của cửa sổ bên dưới, khiến cửa sổ chồng lên nhau khó đọc hơn. Để tránh hiệu ứng như vậy, khi hiệu ứng 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:
Để làm mờ nền, hãy tăng alpha của nền cửa sổ có thể vẽ, làm cho nền mờ hơn.
Để làm mờ phía sau, hãy thêm một lớp làm mờ có mức độ làm 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ụ minh hoạ 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 đối tượng có thể vẽ nền cửa sổ. Thư viện này xử lý chính xác các phiên bản Android, thiết bị (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. Nó đả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 bằng cách điều chỉnh
alpha có thể vẽ nền cửa sổ và lượng mờ 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 tròn cho cửa sổ, chúng ta xác định nền cửa sổ trong res/drawable/window_background.xml dưới dạng ShapeDrawable có góc 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>
Hiệu ứng làm mờ cửa sổ sẽ làm mờ nội dung của cửa sổ bên dưới hoạt động. Hình ảnh làm mờ được vẽ bên dưới cửa sổ hoạt động này, vì vậy, cửa sổ hoạt động cần phải mờ để có thể nhìn thấy hiệu ứng làm mờ. Để 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ị, 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ó hỗ trợ làm mờ cửa sổ hay không, hãy làm như sau:
Đảm bảo thiết bị có thể xử lý tải GPU bổ sung. Các thiết bị cấp thấp có thể không xử lý được tải bổ sung, dẫn đến tình trạng rớt khung hình. Chỉ bật hiệu ứ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ó một công cụ hiển thị tùy chỉnh, hãy đảm bảo rằng công cụ hiển thị tùy chỉnh 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 đảm bảo rằng thiết bị của bạn có thể hỗ trợ hiệu ứng làm mờ cửa sổ, hãy đặt cờ surface flinger sysprop 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 làm mờ như mong đợi.
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 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 -> Tùy 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ổ
Từ thiết bị đầu cuối 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ủa bạn có hỗ trợ tính năng làm mờ cửa sổ hay không và liệu tính năng làm mờ cửa sổ có đang bật hay không, hãy chạy adb shell wm disable-blur trên thiết bị đã can thiệp hệ thống.
Khắc phục sự cố
Hãy làm theo hướng dẫn sau để khắc phục sự cố trong quá trình xác thực.
Chưa vẽ hiệu ứng làm mờ
Xác minh rằng tính năng làm mờ hiện đang bật và phần cứng của bạn hỗ trợ tính năng này. Tham khảo phần 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ổ mờ. 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ợ hiệu ứ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ợ hiệu ứ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 Tùy chọn cho nhà phát triển không bật hiệu ứng làm mờ
- Kiểm tra xem thiết bị có đang ở chế độ tiết kiệm pin hay không hoặc thiết bị có đang sử dụng đường hầm đa phương tiện hay không. Trên một số thiết bị TV, hiệu ứng làm mờ cửa sổ cũng có thể bị tắt trong khi phát video.
Nền mờ được vẽ toàn màn hình, không nằm trong ranh giới 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ờ.
Thông tin cập nhật từ trình nghe không được áp dụng trên màn hình
- Nội dung 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.
