Làm mờ cửa sổ

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.

Tính năng làm mờ cửa sổ hoặc làm mờ cửa sổ chéo được dùng để làm mờ màn hình phía sau 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ửa sổ có nền mờ, tạo hiệu ứng kính mờ.

  • Tính năng Làm mờ phía sau cho phép bạn làm mờ toàn bộ màn hình phía sau một cửa sổ (hộp thoại), tạo ra 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ư trong hình sau:

chỉ làm mờ nền

a

chỉ làm mờ phía sau

b

làm mờ phía sau và làm mờ nền

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 như hiệu ứng làm mờ, tức là làm mờ nội dung bên trong cùng một cửa sổ. Việc làm mờ cửa sổ rất hữu ích đối với 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 có nghĩa là không bị 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ờ khá hiệu quả. 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ờ được bổ sung bằng 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 được làm mờ của nội dung cơ bản. Để thêm nền được làm mờ cho cửa sổ, hãy làm như sau:

  1. Gọi Window#setBackgroundBlurSales(int) để đặt bán kính làm mờ nền. Bạn cũng có thể thiết lập R.attr.windowBackgroundBlur hứng trong giao diện cửa sổ.

  2. Đặt R.attr.windowIsTranslucent thành true để làm cho cửa sổ trong suốt. Vết làm mờ được vẽ bên dưới bề mặt cửa sổ, vì vậy, cửa sổ cần được làm trong suốt để có thể nhìn thấy được phần làm mờ.

  3. 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. Bạn cũng có thể đặt R.attr.windowBackground trong giao diện cửa sổ.

  4. Đố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 ShapeDrawablegóc bo tròn làm nền cửa sổ có thể vẽ.

  5. Xử lý các trạng thái đã bật và tắt tính nă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:

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

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

  3. Bạn cũng có thể chọn mức độ mờ bổ sung.

  4. Xử lý các trạng thái đã bật và tắt tính năng làm mờ. Hãy tham khảo phần Nguyên tắc sử dụng tính năng làm mờ cửa sổ trong ứng dụng để biết thêm thông tin.

Hướng dẫn sử dụng tính năng làm mờ cửa sổ trong ứng dụng

Khả năng 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 phiên bản Android của SDK thiết bị.

  • 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 trên 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 tính năng làm mờ cửa sổ hiện đã được bật hay chưa.

  • Triển khai 2 phiên bản cho nền cửa sổ để phù hợp với trạng thái làm mờ cửa sổ đang bật hoặc đã tắt.

    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 tính nă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:

    • Đố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à hiệu ứng 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. Thành phần 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 nhiều phiên bản Android, nhiều thiết bị (có thể không hỗ trợ tính năng làm mờ cửa sổ) và các thay đổi được bật hoặc tắt trong chế độ làm mờ 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.xmlShapeDrawablecá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>

Chế độ 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 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

Để làm mờ cửa sổ trên một thiết bị, OEM cần khai báo rằng thiết bị hỗ trợ tính năng làm mờ cửa sổ.

Để kiểm tra xem thiết bị của bạn có hỗ trợ tính nă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 thêm GPU. 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ó một 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 đả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 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:

  1. Mở giao diện người dùng có hiệu ứng làm mờ.

  2. 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ổ.

  3. 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ị đầu cuối trên một 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ị chạy 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ổ hiện có đang bật hay không, hãy chạy adb shell wm disable-blur trên một thiết bị đã bị can thiệp 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ẽ hình mờ

  • Kiểm tra để đảm bảo tính năng làm mờ hiện đã được bật và phần cứng của bạn có hỗ trợ tính nă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 nội dung 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 tròn

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 không hoặc có đang sử dụng tính năng tạo đường hầm đ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 quá trình phát video.

Làm mờ nền được vẽ trên toàn màn hình, không nằm trong ranh giới cửa sổ

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à được tạo lại bằng bản cập nhật trình nghe phù hợp hay không.