Làm mờ cửa sổ

Trong Android 12, bạn có thể sử dụng các API công khai cho triển khai các 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ổ đã cho. Có hai loại làm mờ cửa sổ, có thể được sử dụng để đạt được các hiệu ứng khác nhau hiệu ứng hình ảnh:

  • Tính năng Làm mờ nền cho phép bạn tạo các cửa sổ có nền được làm mờ, tạo ra hiệu ứng kính mờ.

  • Tính năng Làm mờ phía sau giú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 hiệu ứng độ sâu trường ảnh.

Hai hiệu ứng này có thể được sử dụng riêng biệt hoặc kết hợp, 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 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 làm mờ để 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ổ 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 của vùng làm mờ, tức là bán kính càng cao, hiệu ứng mờ càng dày đặc. Độ mờ 0 px có nghĩa là không bị mờ. Để làm mờ phía sau, bán kính 20 px tạo ra hiệu ứng độ sâu trường ảnh tốt, trong khi nền làm mờ bán kính 80 px sẽ tạo ra hiệu ứng kính mờ tốt. Tránh làm mờ bán kính lớn 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 hiệu ứng làm mờ được bổ sung bằng một lớp màu trong suốt.

Làm mờ nền

Dùng hiệu ứng làm mờ nền trên cửa sổ nổi để tạo hiệu ứng nền cho 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) thành đặ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. Phần làm mờ được vẽ dưới cửa sổ bề mặt nên cửa sổ cần được làm mờ để có thể nhìn thấy hiệu ứng làm mờ.

  3. (Không bắt buộc) Bạn có thể gọi Window#setBackgroundDrawableResource(int) để thêm nền cửa sổ hình chữ nhật có thể vẽ được bằng 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 các góc tròn cho vùng làm mờ bằng cách đặt ShapeDrawablegóc tròn làm đối tượng có thể vẽ trong nền cửa sổ.

  5. Xử lý các trạng thái đã bật và tắt tính năng làm mờ. Tham khảo Hướng dẫn sử dụng tính năng làm mờ cửa sổ trong ứng dụng để biết thêm thông tin.

Làm mờ phía sau

Vết 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 sử dụng để hướng sự chú ý của người dùng vào nội dung trong 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ổ, đặt R.attr.windowBlurBehindEnabled.

  2. Gọi WindowManager.LayoutParams#setBlurBehindRadius tới đặt làm mờ phía sau bán kính. Hoặc, trong giao diện cửa sổ, đặt R.attr.windowBlurPhíClasses.

  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ờ. Tham khảo Hướng dẫn 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 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 và cao hơ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 làm mờ cửa sổ hỗ trợ.

  • 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ổ tại thời gian chạy, ví dụ: trong chế độ tiết kiệm pin, trong khi phát các loại nội dung video hoặc do ghi đè của nhà phát triển.

Để ứ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 một 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, sử dụng WindowManager#isCrossWindowBlurEnabled để truy vấn liệu tính năng làm mờ cửa sổ hiện có đang bật hay không.

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

    Khi bật tính năng làm mờ, nền cửa sổ phải được trong suốt để hiệu ứng làm mờ có thể nhìn thấy. Ở trạng thái này, khi tính năng làm mờ bị tắt, nội dung trong cửa sổ trùng lặp trực tiếp với nội dung của cửa sổ cơ bản, làm cho cửa sổ chồng chéo khó đọc hơn. Để tránh hiệu ứng tương tự, khi cửa sổ bị làm mờ 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 giá trị alpha của nền cửa sổ đối tượng có thể vẽ, làm cho đối tượng đó mờ hơn.

    • Để làm mờ phía sau, hãy thêm một lớp tối có độ tối 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ề cách hoạt động của một hoạt động sử dụng cả hiệu ứng làm mờ hậu trường và làm mờ nền.

Ví dụ sau về MainActivity.java là một hộp thoại có hiệu ứng làm mờ sau bán kính 20 px và bán kính làm mờ nền là 80 px. Có các góc tròn, được xác định trong tệp xml trong đối tượng có thể vẽ ở nền cửa sổ. Chính xác xử lý các phiên bản Android khác nhau, 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 được bật hoặc tắt trong thời gian chạ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 alpha có thể vẽ trong nền cửa sổ và mức độ tối 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 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 ShapeDrawablecác góc tròn có 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. Chiến lược phát hành đĩa đơn hình ảnh được làm mờ sẽ đượ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 trong suốt để cho phép làm mờ hiển thị. Để làm cho cửa sổ trong suốt, chúng ta đặt R.attr.windowIsTranslucent trong chủ đề hoạt động như sau:

<style name="Theme.BlurryDialog" parent="Theme.MaterialComponents.Dialog">
    <item name="android:windowIsTranslucent">true</item>
</style>

OEM 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ợ 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. Thiết bị cấp thấp hơn có thể không xử lý được tải thêm, điều này có thể làm rớt khung hình. Chỉ bật tính năng làm mờ cửa sổ trên các thiết bị được thử nghiệm có đủ năng lượng 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ờ. Android 12 mặc định công cụ kết xuất 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ợ tính năng làm mờ cửa sổ, hãy đặt các cử chỉ hất giao diện sysprop:

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 xử lý đúng cách khi chuyển đổi giữa chế độ làm mờ đã bật và làm mờ trạng thái đã tắt, 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 chế độ làm mờ cửa sổ bằng cách bật và tắt chế độ làm mờ cửa sổ.

  3. Xác minh rằng giao diện người dùng cửa sổ thay đổi sang và từ trạng thái được làm mờ như dự kiến.

Bật và tắt chế độ 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 pháp 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 có 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
    

Cách kiểm tra xem thiết bị chạy Android 12 trở lên có hỗ trợ cửa sổ hay không 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 một thiết bị bị can thiệp hệ thống.

Khắc phục sự cố

Hãy làm theo hướng dẫn 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. Hãy tham khảo bài viết Bật và tắt chế độ làm mờ cửa sổ.

  • Đảm bảo bạn thiết lập màu nền trong suốt cho cửa sổ. Cửa sổ mờ màu nền giúp ẩn vùng bị làm mờ.

Thiết bị thử nghiệm không hỗ trợ tính năng làm mờ cửa sổ

  • Kiểm thử ứng dụng của bạn 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ợ cửa sổ làm mờ.

Không có góc tròn

Việc cập nhật tuỳ chọn cho nhà phát triển sẽ 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ạo đường hầm đa phương tiện. 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 phải hay không cập nhật trình nghe.