Using with Jetpack Compose
Hi, I would like to use this library in a Jetpack Compose project however I'm not finding any success. Could you provide a simple Composable component that with an AndroidView or a AndroidViewBinding wrap your library? Thank you
Not sure if I understand what problem you're having exactly.
Why can't you wrap it into AndroidView yourself?
Hi, thank you for the reply. I'm trying to create a blurred effect in the TopBar of my app. The app is entirely written in Jetpack Compose.
I tried to wrap everything like this, however I did not understand what should I pass to the method setupWith since I don't have a rootView (or I don't know how to get it).
@Composable
fun TopBar() {
AndroidView(
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
factory = { context ->
BlurView(context).apply {
this.setupWith(this) // <- Here
.setBlurAlgorithm(RenderScriptBlur(context))
.setBlurRadius(20f)
.setBlurAutoUpdate(true)
}
}
)
}
If it's helpful, since it's a TopBar, the content behind is scrollable. Thank you again.
If your composable is written within the Activity, just get a reference to it and do
val decorView = activity.window.decorView
val rootView = decorView.findViewById<ViewGroup>(android.R.id.content)
If you don't have a reference to the Activity, you can cast the context to Activity, though that's a bit hacky and I'm not sure if the preview in AS will be rendered correctly.
You can also just pass the Activity reference to your TopBar Composable
I tried both with casting and passing the MainActivity to my TopBar, but in both cases the application crashes with this error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: io.dachain.dachain, PID: 3146
java.lang.IllegalStateException: Recording currently in progress - missing #endRecording() call?
at android.graphics.RenderNode.beginRecording(RenderNode.java:372)
at android.graphics.RenderNode.beginRecording(RenderNode.java:391)
at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:151)
at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:243)
at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:677)
at android.view.View.draw(View.java:22353)
at android.view.View.draw(View.java:22223)
at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
at android.view.View.draw(View.java:22221)
at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
at android.view.View.draw(View.java:22353)
at eightbitlab.com.blurview.BlockingBlurController.updateBlur(BlockingBlurController.java:122)
at eightbitlab.com.blurview.BlockingBlurController.draw(BlockingBlurController.java:164)
at eightbitlab.com.blurview.BlurView.draw(BlurView.java:51)
at android.view.View.updateDisplayListIfDirty(View.java:21226)
at android.view.View.draw(View.java:22081)
at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
at android.view.View.draw(View.java:22353)
at androidx.compose.ui.platform.AndroidViewsHandler.drawView(AndroidViewsHandler.android.kt:72)
at androidx.compose.ui.platform.AndroidComposeView.drawAndroidView(AndroidComposeView.android.kt:481)
at androidx.compose.ui.viewinterop.AndroidViewHolder$layoutNode$1$coreModifier$1.invoke(AndroidViewHolder.android.kt:235)
at androidx.compose.ui.viewinterop.AndroidViewHolder$layoutNode$1$coreModifier$1.invoke(AndroidViewHolder.android.kt:232)
at androidx.compose.ui.draw.DrawBackgroundModifier.draw(DrawModifier.kt:101)
at androidx.compose.ui.node.ModifiedDrawNode.performDraw(ModifiedDrawNode.kt:102)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:244)
at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.performDraw(DelegatingLayoutNodeWrapper.kt:68)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:244)
at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.performDraw(DelegatingLayoutNodeWrapper.kt:68)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:244)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:244)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:255)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:254)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:1776)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:123)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:254)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:54)
at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:156)
at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:243)
at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:677)
at android.view.View.draw(View.java:22353)
at android.view.View.draw(View.java:22223)
at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
at android.view.View.draw(View.java:22221)
at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
at android.view.View.draw(View.java:22353)
at eightbitlab.com.blurview.BlockingBlurController.updateBlur(BlockingBlurController.java:122)
at eightbitlab.com.blurview.BlockingBlurController$1.onPreDraw(BlockingBlurController.java:56)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1093)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3089)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1952)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8171)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
at android.view.Choreographer.doCallbacks(Choreographer.java:796)
at android.view.Choreographer.doFrame(Choreographer.java:731)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
I/Process: Sending signal. PID: 3146 SIG: 9
My updated code looks like this:
@Composable
fun TopBar(activity: MainActivity) {
val decorView = activity.window.decorView
val rootView = decorView.findViewById<ViewGroup>(android.R.id.content)
val windowBackground = decorView.background;
AndroidView(
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
factory = { context ->
BlurView(context).apply {
this.setupWith(rootView)
.setFrameClearDrawable(windowBackground)
.setBlurAlgorithm(RenderScriptBlur(context))
.setBlurRadius(20f)
.setBlurAutoUpdate(true)
}
}
)
}
Then I guess the BlurView is not compatible with Composable hierarchies. I'm slightly interested in why it happens, so I might check it out later, but most likely this won't be fixed
@LorenzoFerri If you are interested Modifier.blur() is available in Compose 1.1.0-alpha03 on Android 12
@LorenzoFerri If you are interested
Modifier.blur()is available in Compose1.1.0-alpha03on Android 12
I tried that Modifier, but it doesn’t achieve what I need, blurring only the composable itself and not what's behind it.
@LorenzoFerri Did you get this to work using Compose? I am stuck with the same issue!
I've spent some time trying to achieve the blurring effect in Compose using this library and anything else that I was able to find, but I haven't found any solution. So, currently, migrating my project to Compose is put on hold indefinitely.
I haven't found a solution either. But I noticed that using @LorenzoFerri's code stops throwing an error if I don't use a Modifier in the AndroidView section however the blur itself is pretty weird and not the desired effect. So I wonder if it has something to do with that. I'd love to find a solution to this.
It would be really great if BlurView can be used in Jetpack Compose :')
Any updates?
@SecretKeeper I've opened an issue here - https://issuetracker.google.com/issues/232625913 I don't think there's anything reasonable I can do to fix this crash on my side. The Compose's behavior doesn't look right to me in this case.
Star it if you'd like to help
I tried moving the setupWith into update block and it works, but it only renders for the first time..

I tried moving the setupWith into update block and it works
Unfortunately, it's probably some (un)lucky quirk of your particular setup, because there's a fundamental problem preventing it from working correctly. Also, it still crashes for me even with this delayed setup
Version 2.0.2 should fix this problem, but I'm not sure it's going to be working in every scenario. But you can try and let me know how it went
Hi @Dimezis, sorry to comment on the closed issue, but I found this is relavent to my question, I am curious about what if the root view is composable? Basically I have a composable that is ready to be used, I just want its background to be blured, I tried to embed BlurView into AndroidView, but how to integrate composable in this case? Could you shed some lights, thanks!
@Composable
fun HomeBottomBar(){
// Composable goes here
}
@Composable
fun AndroidViewBasedCompose(){
val context = LocalContext.current
val decorView = context.activity.window.decorView
val rootView = decorView.findViewById<ViewGroup>(android.R.id.content). //Where can I get this??? It's a composable in my case
val windowBackground = decorView.background;
AndroidView(
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
factory = { context ->
BlurView(context).apply {
this.setupWith(rootView)
.setFrameClearDrawable(windowBackground)
.setBlurAlgorithm(RenderScriptBlur(context))
.setBlurRadius(20f)
.setBlurAutoUpdate(true)
}
}
)
}
// Utility function for getting activity ref
fun Context.getActivity(): AppCompatActivity? = when (this) {
is AppCompatActivity -> this
is ContextWrapper -> baseContext.getActivity()
else -> null
}
@jianinz I'm not sure if I understand your problem.
val rootView = decorView.findViewById<ViewGroup>(android.R.id.content). //Where can I get this??? It's a composable in my case
android.R.id.content can't be a composable. It's a default ViewGroup present in every Activity.
Your setup looks fine, though I didn't test it.
What's the problem exactly and what happens when you use AndroidViewBasedCompose?
@Dimezis Thanks for your quick response! In the example here https://github.com/Dimezis/BlurView#how-to-use, BlurView will have any child view which will not be blured. In my case, the child view will be a composable, I wonder how to integrate that composable into BlurView?
Should I just do something like:
Box {
HomeBottomBar(
)
AndroidViewBasedCompose()
}
If I use code below
@Composable
fun AndroidViewBasedCompose(){
val context = LocalContext.current
val decorView = context.activity.window.decorView
val rootView = decorView.findViewById<ViewGroup>(android.R.id.content)
val windowBackground = decorView.background
AndroidView(
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
factory = { context ->
BlurView(context).apply {
this.setupWith(rootView)
.setFrameClearDrawable(windowBackground)
.setBlurAlgorithm(RenderScriptBlur(context)) // No longer available in the version 2.0.3
.setBlurRadius(20f)
.setBlurAutoUpdate(true)
}
}
)
}
Box {
HomeBottomBar(
)
AndroidViewBasedCompose()
}
I don't see the blured view, instead I see the mono background colored bottom bar, no blur effect takes into place
Should I just do something like: ...
Yes, although I think the order should be
Box {
AndroidViewBasedCompose()
HomeBottomBar()
}
And the HomeBottomBar has to have a transparent background for the BlurView to be visible.
Edit: On second thought, in this case, the BlurView would also include the bottom bar into its blurred content, so that might not be doable in the end.
On second thought, in this case, the BlurView would also include the bottom bar into its blurred content, so that might not be doable in the end.
Yeah, just tried changing order, in the end the blur view does not show up, is there any ways to include the bottom bar into its blurred content?
in the end the blur view does not show up
As I said, the bottom bar composable has to have a transparent background. I don't know if it's adjustable though
As I said, the bottom bar composable has to have a transparent background. I don't know if it's adjustable though
I set HomeBottomBar's background color as transparent and blur view as purple, unfortunately the result is just transparent HomeBottomBar