Android implements dynamic Gaussian blur background effect
1. Project introduction
In modern Android UI,Dynamic Gaussian blur backgroundCommon in:
Blur mask behind dialog or pop-up window
Real-time blur behind side slide menu
Blurred background when scrolling content
Fuzzy background of video/image player
Compared with static blur graphs, dynamic blur can be updated in real time as the content scrolls or changes, making the interface more layered and immersive. But real-time Gaussian blur also brings performance challenges, requiring a trade-off between smoothness and picture clarity.
The goals of this project are:
Provide a universal
BlurView
Custom controls can dynamically blur the views behind them at any API level.Use on API 31+RenderEffect(Hardware acceleration, good performance), used on API 21–30RenderScript(Software/compatible).
Support adjustableFuzzy radius、Downsampling ratio(downsample) andUpdate frequency。
Demonstrate how to quickly integrate in layout: it can be used in a layout file or code in one line.
Take into accountlife cycle, avoid leaks and invalid updates.
2. Related technologies and knowledge
-
RenderEffect(API 31+)
(radiusX, radiusY, )
Directly pass
()
Add real-time Gaussian blur to the control or background.
-
RenderScript and ScriptIntrinsicBlur (API 17+)
Use support mode
renderscriptSupportModeEnabled
,existEnabled in:
android { defaultConfig { renderscriptTargetApi 21 renderscriptSupportModeEnabled true } }
-
ScriptIntrinsicBlur
Accept inputAllocation
, the output is fuzzyAllocation
, copy it backBitmap
。
-
Downsampling
Set the target first
Bitmap
Shrink several times (such as 1/4), and blurring again can greatly improve performance;Finally, the blur graph is stretched back to the original size to display, and the difference is not much different from the naked eye.
-
In every time
BlurView
Capture a snapshot of the underlying content before repainting yourself, generate a blurred picture and apply it.Need to be
onAttachedToWindow()
Register, inonDetachedFromWindow()
Log out.
-
SurfaceView / TextureView / GLSurfaceView
The content of these Views cannot be obtained through the regular method.
Bitmap
; Special treatment or skip.
-
Performance trade-offs
The larger the blur radius and the smaller the sampling scaling, the softer the effect, but the amount of calculation increases;
A reasonable setting is requiredUpdate interval, avoid duplicate blurring every frame.
Ideas for realization
-
Custom controls
BlurView
Inheritance
FrameLayout
, let all subviews be displayed on the blurred map;Draw a blurred snapshot in the background layer;
Supported via custom attributes
blurRadius
、downsampleFactor
、updateInterval
。
-
Layout integration
exist
activity_main.xml
or other layout, put the content inBlurView
After that, orBlurView
Put it on top of the content and set itmatch_parent
, you can mask it.
-
BlurView Internal Logic
-
exist
onAttachedToWindow()
:Determine the API level and initialize the corresponding fuzzy engine (RenderEffect or RenderScript);
register
;
-
exist
OnPreDrawListener
:Every other
updateInterval
ms Get a snapshot of the parent container or the specified target view (getDrawingCache()
or(view)
);Execution blur according to API level: RenderEffect is called directly
setRenderEffect()
;Renderscript GenerationBitmap
;Draw the blur result to
Canvas
;
-
-
Free up resources
-
exist
onDetachedFromWindow()
:Log out
OnPreDrawListener
;Destroy RenderScript
()
;
-
4. Complete code
// ============================================== // document:// Function: Demonstrate the use of dynamic Gaussian blurred background// Includes: layout XML, Gradle configuration, BlurView control source code// ============================================== package ; import ; import ; import ; import ; import ; /* =================================================================== android { compileSdk 33 defaultConfig { applicationId "" minSdk 21 targetSdk 33 // Enable RenderScript compatibility mode renderscriptTargetApi 21 renderscriptSupportModeEnabled true } // ... } dependencies { implementation ':appcompat:1.5.1' implementation ':gson:2.9.0' // If you need JSON parsing } ================================================================== */ /* ==================================== res/layout/activity_main.xml =================================== <?xml version="1.0" encoding="utf-8"?> <!-- Parent layout: Background content --> <FrameLayout xmlns:andro xmlns:app="/apk/res-auto" android: android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 1. Background content example --> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/your_large_image"/> <!-- 2. Dynamic blur mask layer --> < android: android:layout_width="match_parent" android:layout_height="match_parent" app:blurRadius="16" app:downsampleFactor="4" app:updateInterval="100"/> <!-- 3. Front-end UI elements --> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="dynamic Gaussian fuzzy example" android:textSize="24sp" android:textColor="#FFFFFFFF" android:layout_gravity="center"/> </FrameLayout> ======================================================================== */ public class BlurDemoActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle s) { (s); setContentView(.activity_main); // No extra code is required, BlurView will work automatically when attached } } // ============================================== // document:// Function: Universal dynamic Gaussian blur mask control// ============================================== package ; import ; import ; import .*; import ; import .*; import ; import .*; import ; import ; public class BlurView extends FrameLayout { private int blurRadius; // Fuzzy radius private int downsampleFactor; // Downsampling multiple private long updateInterval; // Update interval ms private Bitmap bitmapBuffer; private Canvas bitmapCanvas; private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private boolean useRenderEffect; private RenderScript rs; private ScriptIntrinsicBlur instBlur; private Allocation allocIn, allocOut; private preDrawListener; private long lastUpdateTime = 0; public BlurView(Context c) { this(c, null); } public BlurView(Context c, AttributeSet attrs) { this(c, attrs, 0); } public BlurView(Context c, AttributeSet attrs, int defStyle) { super(c, attrs, defStyle); // Read properties TypedArray a = (attrs, ); blurRadius = (.BlurView_blurRadius, 10); downsampleFactor = (.BlurView_downsampleFactor, 4); updateInterval = (.BlurView_updateInterval, 100); (); // Decide which fuzzy method to use useRenderEffect = .SDK_INT >= Build.VERSION_CODES.S; if (!useRenderEffect) { // Initialize RenderScript Fuzzy rs = (c); instBlur = (rs, Element.U8_4(rs)); (blurRadius); } setWillNotDraw(false); // onDraw allowed } @Override protected void onAttachedToWindow() { (); // Register PreDraw Monitor preDrawListener = () -> { long now = (); if (now - lastUpdateTime >= updateInterval) { lastUpdateTime = now; blurAndInvalidate(); } return true; }; getViewTreeObserver().addOnPreDrawListener(preDrawListener); } @Override protected void onDetachedFromWindow() { (); // Clean up getViewTreeObserver().removeOnPreDrawListener(preDrawListener); if (rs != null) (); } /** Perform blur and redraw yourself */ private void blurAndInvalidate() { // Get a snapshot of the parent container View root = (View) getParent(); if (root == null) return; int width = (); int height = (); if (width == 0 || height == 0) return; int bw = width / downsampleFactor; int bh = height / downsampleFactor; // Initialize cache if (bitmapBuffer == null || ()!=bw || ()!=bh) { bitmapBuffer = (bw, bh, .ARGB_8888); bitmapCanvas = new Canvas(bitmapBuffer); } // Draw root zoom to bitmap (); (1f/downsampleFactor, 1f/downsampleFactor); (bitmapCanvas); (); // Vague if (useRenderEffect) { // API 31+: Set RenderEffect directly on yourself RenderEffect effect = ( blurRadius, blurRadius, ); setRenderEffect(effect); } else { // RenderScript blur if (allocIn!=null) (); if (allocOut!=null) (); allocIn = (rs, bitmapBuffer); allocOut = (rs, ()); (allocIn); (allocOut); (bitmapBuffer); // Copy the fuzzy results to your own bitmap invalidate(); } } @Override protected void onDraw(Canvas canvas) { (canvas); if (!useRenderEffect && bitmapBuffer!=null) { // Draw and zoom back to the screen (); (downsampleFactor, downsampleFactor); (bitmapBuffer, 0, 0, paint); (); } } } // ============================================== // res/values/ (integrated here)// ============================================== /* <resources> <declare-styleable name="BlurView"> <attr name="blurRadius" format="integer"/> <attr name="downsampleFactor" format="integer"/> <attr name="updateInterval" format="integer"/> </declare-styleable> </resources> */
5. Method interpretation
-
Property reading
blurRadius
: Gaussian fuzzy radius (maximum 25);downsampleFactor
: Downsampling ratio, the larger the performance, the better the details;updateInterval
: The minimum interval between two blurs (avoid blurring every frame).
-
Fuzzy engine selection
API 31+ Call
()
, accelerated by system hardware;API 21–30 using RenderScript
ScriptIntrinsicBlur
, executed at the software layer or the compatibility layer.
-
Pre-drawing monitoring
exist
OnPreDrawListener
Get the parent View snapshot and downsample & blur;Called after each update
invalidate()
, triggeronDraw()
。
-
Downsampling and amplification
First press the parent View
1/downsampleFactor
Draw the scale to a small Bitmap, blur it again, and finally inonDraw()
Zoom in and go back;Significantly reduce the amount of fuzzy calculations to ensure smoothness.
-
Lifecycle Management
exist
onAttachedToWindow()
Register to monitor,onDetachedFromWindow()
Log out and destroy RenderScript.Make sure that no longer occupies resources when the View is invisible or destroyed.
6. Project Summary
-
Performance and compatibility
Recommended API 31+ Use
RenderEffect
, no need to create intermediate Bitmap, best performance;API 21–30 Using RenderScript + downsampling can maintain around 30fps on most devices;
Reasonable adjustment
downsampleFactor
(Suggestion 48) andupdateInterval
(Suggested 100200ms).
-
Use scenarios
The dialog box is blurred (only static once for the first time), and the dialog box root view can be wrapped directly in the layout;
The background blurs when scrolling (for example, below the RecyclerView), you can change the
BlurView
Put it on top of the content;The background of the video or animation is blurred, and it needs to be guaranteed
updateInterval
Long enough to avoid over-consuming.
-
Extended
Edge mask: Draw the edge of the gradient mask after blur;
Jitter compensation: Pause the blur update during fast scrolling, and blur again after the scrolling stops;
Multi-area blur: Support blurring a sub-region instead of full screen;
Jetpack Compose: Used in Compose 1.3+
{ renderEffect = … }
Simple implementation;
The above is the detailed content of Android's dynamic Gaussian blur background effect. For more information about Android's Gaussian blur background, please pay attention to my other related articles!
Related Articles
iOS UIButton Click Unresponsive Solution
We often encounter buttons in development, but sometimes we encounter some difficult problems, that is, the button clicks are unresponsive, and the solution is not difficult. Below, the editor of the editor's home takes time to introduce the solution to iOS UIButton clicks without response. Please refer to it if you need it.2017-12-12Android AMS startup details
This article mainly introduces relevant information about Android AMS startup, helping everyone better understand and learn to use Android. Interested friends can learn about it.2021-03-03Implement draggable video control based on SurfaceView
This article mainly introduces the draggable video control based on SurfaceView in detail. The sample code in the article is introduced in detail and has certain reference value. Interested friends can refer to it.2018-04-04Solution to adapt to virtual buttons for Huawei phones based on interface
Below, the editor will share with you a solution to the virtual buttons that are adapted to Huawei phones based on the interface. It has good reference value and hopes it will be helpful to everyone. Let's take a look with the editor2018-01-01An example of the marble effect implemented by Android based on TextView
This article mainly introduces the marble effect implemented by Android based on TextView. It analyzes the relevant skills of Android using TextView to achieve marble effect through attribute settings and function code in the form of a complete example. Friends who need it can refer to it2016-02-02Android realizes music video playback
This article mainly introduces the Android music video playback in detail. The sample code in the article is introduced in detail and has a certain reference value. Interested friends can refer to it.2021-05-05How to remove ListDivider at the bottom of ListView
Below, the editor will bring you a method to remove the ListDivider at the bottom of the ListView. The editor thinks it is quite good, so I will share it with you now and give you a reference. Let's take a look with the editor2017-04-04Baidu Map API prompt 230 Solutions for the failure of scode verification of error app
The author played Baidu map on Android Studio in the past two days and encountered the common "230 errors, APP Scode verification failed". Let me introduce the specific solutions below2016-01-01Some practical layout tips for CoordinatorLayout in Android
Everyone knows that CoordinatorLayout is an "enhanced version" FrameLayout. The following article mainly shares some layout techniques about CoordinatorLayout in Android. The article introduces the example code in detail. Friends who need it can refer to it. Let's take a look together below.2017-06-06Two solutions to Android setting application full screen
In this article, the editor will introduce to you two solutions to Android setting full screen application. If you need it, please refer to it2013-04-04