chrisbanes / haze

A blurring modifier for Compose Multiplatform / Jetpack Compose
https://chrisbanes.github.io/haze/
Apache License 2.0
1.03k stars 27 forks source link

iOS native view is not rendered when haze is applied #239

Closed colin-weng-s closed 2 months ago

colin-weng-s commented 2 months ago

Information

I want to blur all the contents on the screen below a snackbar, on Android it works, but on iOS, when there are composables that contain implemented iOS native views, they are not rendered. The blur effect itself is correct.

Expected Behavior

on Android, it works.

Screen_recording_20240620_193618.webm

Actual Behavior

on iOS, the Toggle is broken only during haze is used.

https://github.com/chrisbanes/haze/assets/167203772/113ecdb1-3333-4010-abbd-c601b09c200a

Steps to Reproduce the Problem

  1. implement a native iOS view:
// ThemedSwitch.ios.kt
@Composable
actual fun ThemedSwitch(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
) {
    val appContext = koinInject<AppContext>()
    val viewModel = remember { SwitchViewModel(onCheckedChange) }
    LaunchedEffect(checked) {
        viewModel.isChecked = checked
    }
    UIKitViewController(
        modifier = Modifier.size(55.dp, 33.dp),
        factory = { appContext.uiViewControllerContext.componentFactories.switchFactory(viewModel) },
        update = {},
    )
}
struct SwitchView: View {
    @ObservedObject var viewModel: SwitchViewModelWrapper

    var body: some View {
        Toggle("", isOn: $viewModel.isChecked)
            .tint(Color(uiColor: ColorHelper().toUIColor(color: Colors().brandNormal)))
            .labelsHidden()
            .padding()
    }
}

View model implementations are omitted because it's not related, I think. If you need it please tell me.

  1. Use haze for the snackbar

// App composable
AppTheme {
    GuardSignIn { isLoggedIn ->
        val initialScreen = remember(isLoggedIn) {
            if (isLoggedIn) MainScreen.createHome() else SignInScreen
        }
        Box(
            modifier = Modifier.fillMaxSize()
                .background(brush = Colors.gradientBackground)
                .haze(koinInject()) // the app-wide HazeState
        ) {
           // screen contents that need to be blurred
        }
    }

    koinInject<SnackbarController>().Compose()
}

// SnackbarController.Compose()
Box(
    modifier = Modifier
        .padding(16.dp)
        .fillMaxWidth()
        .height(56.dp)
        .hazeChild(koinInject<HazeState>(), shape = shape, style = HazeStyle(blurRadius = 10.dp))
        .shadow(elevation = 8.dp, shape = shape),
) {
  // contents
}
chrisbanes commented 2 months ago

This is basically a side effect of how UiKit views rendered in Compose Multiplatform iOS. Not much we can do about this, as they're not actually drawn in Compose (CMP punches a hole through the Compose content and draws them behind).

rschattauer commented 3 weeks ago

@chrisbanes , is that something 0.9 is fixing or is there no possibility for this topic?

chrisbanes commented 3 weeks ago

I haven't tried, but it might help

rschattauer commented 3 weeks ago

@chrisbanes I tried it and it seems 0.9.0-alpha07 works somewhat-ish, just materials wasn't something I could use as it was showing some weird effects (almost fully translucent). Here is a SwiftUI map in the background within a Scaffold with Floating Action Buttons with custom HazeStyle.

style = HazeStyle(
     backgroundColor = FloatingActionButtonDefaults.containerColor,
    tint = FloatingActionButtonDefaults.containerColor.copy(alpha = 0.3f),
    blurRadius = 148.dp,
),

The thing is that this looks different on iOS and Android and also I would assume that with such a high blurRadius I wouldn't see any text through at all, but it's readable on iOS (Android expected as low Android version). Am I missing the blur fully? It just changes opacity going higher. (look at the bottom FAB, I was playing around with that one)

Screenshot 2024-08-18 at 09 22 02

Should I create a new issue or do you want to use this here?

chrisbanes commented 3 weeks ago

My guess is that the map content isn't actually being drawn in the blur on iOS, and what you're seeing is the white background being blurred.

I need a sample to see what's really happening though. If someone wants to send a PR for a quick MapView sample, that would help speed things up. Otherwise I'll see if I can find some time.

rschattauer commented 2 weeks ago

@chrisbanes , would a testing repository with map + haze also help? I could set that up quickly.

chrisbanes commented 2 weeks ago

Yeah that would work, or a PR adding it to the samples in this repo. Either works.

rschattauer commented 2 weeks ago

https://github.com/rschattauer/compose_multiplatform/ Branch: broken-haze-on-map Feel free to copy stuff as you wish into haze as a sample.

In the README it's stated on how to add your private MapBox keys. There is val useUIKitInsteadOfSwiftUI = false that you can make true to also see the same (not working) effect on UIKitView instead of UIKitViewController if that even makes a difference. On the home and map screen you will find a top bar that has the haze effect activated.

Android:

Screenshot 2024-08-21 at 13 51 09 Screenshot 2024-08-21 at 13 51 14

iOS:

Screenshot 2024-08-21 at 13 56 08 Screenshot 2024-08-21 at 13 56 15

If there is anything else I can help you with, please let me know.