Skip to content

Migrating to Haze 2.0

Haze 2.0 introduces a major architectural refactor that improves modularity and extensibility by introducing a pluggable visual effects system. While this is a breaking change, the migration path is straightforward and the core usage patterns remain familiar.

Overview of Changes

The primary change in v2 is the extraction of blur functionality from the core haze module into a separate haze-blur module. This is part of a new architecture that introduces the VisualEffect interface, allowing Haze to support different types of visual effects beyond just blurring.

Key Changes:

  • New module dependency: Blur functionality now requires the haze-blur module
  • API nesting: All blur properties now require a blurEffect {} wrapper
  • Package changes: Blur-related classes moved to dev.chrisbanes.haze.blur package
  • Removed APIs: rememberHazeState(blurEnabled) parameter removed
  • Position strategy: New HazePositionStrategy configuration on HazeState
  • Renames: HazeArea.positionOnScreenposition, VisualEffectContext.positionOnScreenposition, VisualEffectContext.rootBoundsOnScreenrootBounds

What Hasn't Changed:

  • Core modifiers (hazeSource, hazeEffect) signatures remain the same
  • Platform support unchanged
  • Performance characteristics unchanged
  • HazeEffectScope properties like inputScale, drawContentBehind, canDrawArea unchanged

Dependency Changes

Add the haze-blur Module

In addition to the core haze module, you now need to explicitly add the haze-blur module to use blur effects:

dependencies {
  implementation("dev.chrisbanes.haze:haze:2.0.0-alpha01")
  implementation("dev.chrisbanes.haze:haze-blur:2.0.0-alpha01") // NEW in v2
}

Update Imports

Several blur-related classes have moved to the dev.chrisbanes.haze.blur package:

V1 imports:

import dev.chrisbanes.haze.HazeStyle
import dev.chrisbanes.haze.HazeTint
import dev.chrisbanes.haze.HazeProgressive
import dev.chrisbanes.haze.LocalHazeStyle

V2 imports:

import dev.chrisbanes.haze.blur.HazeBlurStyle
import dev.chrisbanes.haze.blur.HazeColorEffect
import dev.chrisbanes.haze.blur.HazeProgressive
import dev.chrisbanes.haze.blur.LocalHazeBlurStyle
import dev.chrisbanes.haze.blur.blurEffect // NEW: extension function

API Migration

Basic Blur Configuration

All blur-related properties that were previously set directly on HazeEffectScope now need to be wrapped in a blurEffect {} block.

Modifier.hazeEffect(state = hazeState) {
  blurRadius = 20.dp
  colorEffects = listOf(HazeColorEffect.tint(Color.Black.copy(alpha = 0.7f)))
  noiseFactor = 0.15f
}
Modifier.hazeEffect(state = hazeState) {
  blurEffect {  // NEW: wrap blur properties
    blurRadius = 20.dp
    colorEffects = listOf(HazeColorEffect.tint(Color.Black.copy(alpha = 0.7f)))
    noiseFactor = 0.15f
  }
}

Using Material Styles

Modifier.hazeEffect(state = hazeState, style = HazeMaterials.ultraThin())
val ultraThin = HazeMaterials.ultraThin()
Modifier.hazeEffect(state = hazeState) {
  blurEffect {
    style = ultraThin
  }
}

Progressive Blurs

Modifier.hazeEffect(state = hazeState) {
  progressive = HazeProgressive.verticalGradient(startIntensity = 1f, endIntensity = 0f)
}
Modifier.hazeEffect(state = hazeState) {
  blurEffect {
    progressive = HazeProgressive.verticalGradient(startIntensity = 1f, endIntensity = 0f)
  }
}

Masking

Modifier.hazeEffect(state = hazeState) {
  mask = Brush.verticalGradient(...)
}
Modifier.hazeEffect(state = hazeState) {
  blurEffect {
    mask = Brush.verticalGradient(...)
  }
}

Enabling/Disabling Blur

// At the state level (REMOVED in v2)
val hazeState = rememberHazeState(blurEnabled = true)

// At the effect level
Modifier.hazeEffect(state = hazeState) {
  blurEnabled = true
}
// At the state level - parameter removed
val hazeState = rememberHazeState()

// At the effect level - now inside blurEffect {}
Modifier.hazeEffect(state = hazeState) {
  blurEffect {
    blurEnabled = true
  }
}

Foreground Blurring

Modifier.hazeEffect {
  colorEffects = listOf(HazeColorEffect.tint(Color.Black.copy(alpha = 0.5f)))
  progressive = HazeProgressive.verticalGradient(...)
}
Modifier.hazeEffect {
  blurEffect {
    colorEffects = listOf(HazeColorEffect.tint(Color.Black.copy(alpha = 0.5f)))
    progressive = HazeProgressive.verticalGradient(...)
  }
}

Complete API Mapping

V1 Location V2 Location Notes
HazeEffectScope.blurRadius BlurVisualEffect.blurRadius Inside blurEffect {}
HazeEffectScope.tints BlurVisualEffect.colorEffects Inside blurEffect {}
HazeEffectScope.noiseFactor BlurVisualEffect.noiseFactor Inside blurEffect {}
HazeEffectScope.progressive BlurVisualEffect.progressive Inside blurEffect {}
HazeEffectScope.mask BlurVisualEffect.mask Inside blurEffect {}
HazeEffectScope.style BlurVisualEffect.style Inside blurEffect {}
HazeEffectScope.backgroundColor BlurVisualEffect.backgroundColor Inside blurEffect {}
HazeEffectScope.blurredEdgeTreatment BlurVisualEffect.blurredEdgeTreatment Inside blurEffect {}
HazeEffectScope.fallbackTint BlurVisualEffect.fallbackTint Inside blurEffect {}
HazeEffectScope.alpha BlurVisualEffect.alpha Inside blurEffect {}
HazeEffectScope.blurEnabled BlurVisualEffect.blurEnabled Inside blurEffect {}
HazeEffectScope.inputScale HazeEffectScope.inputScale Unchanged - still on scope
HazeEffectScope.drawContentBehind HazeEffectScope.drawContentBehind Unchanged - still on scope
HazeEffectScope.clipToAreasBounds HazeEffectScope.clipToAreasBounds Unchanged - still on scope
HazeEffectScope.canDrawArea HazeEffectScope.canDrawArea Unchanged - still on scope
rememberHazeState(blurEnabled) Removed Use blurEffect { blurEnabled = ... }
HazeArea.positionOnScreen HazeArea.position Renamed
VisualEffectContext.positionOnScreen VisualEffectContext.position Renamed
VisualEffectContext.rootBoundsOnScreen VisualEffectContext.rootBounds Renamed
N/A HazeState.positionStrategy New — configurable position calculation
N/A rememberHazeState(positionStrategy) New parameter, defaults to Auto
dev.chrisbanes.haze.HazeStyle dev.chrisbanes.haze.blur.HazeBlurStyle Renamed + package change
dev.chrisbanes.haze.HazeTint dev.chrisbanes.haze.blur.HazeColorEffect Renamed + package change
dev.chrisbanes.haze.HazeProgressive dev.chrisbanes.haze.blur.HazeProgressive Package change
dev.chrisbanes.haze.LocalHazeStyle dev.chrisbanes.haze.blur.LocalHazeBlurStyle Renamed + package change

Step-by-Step Migration

Update dependencies in your build.gradle.kts:

 implementation("dev.chrisbanes.haze:haze:2.0.0-alpha01")
 implementation("dev.chrisbanes.haze:haze-blur:2.0.0-alpha01") // Add this

Update imports for blur-related classes:

  • Change dev.chrisbanes.haze.HazeStyledev.chrisbanes.haze.blur.HazeBlurStyle
  • Change dev.chrisbanes.haze.HazeTintdev.chrisbanes.haze.blur.HazeColorEffect
  • Change dev.chrisbanes.haze.HazeProgressivedev.chrisbanes.haze.blur.HazeProgressive
  • Change dev.chrisbanes.haze.LocalHazeStyledev.chrisbanes.haze.blur.LocalHazeBlurStyle
  • Add import dev.chrisbanes.haze.blur.blurEffect

Wrap blur properties in blurEffect {}:

  • Find all Modifier.hazeEffect { ... } blocks
  • Wrap blur-related properties in blurEffect { ... }
  • Leave inputScale, drawContentBehind, clipToAreasBounds, canDrawArea outside the blurEffect {} block

Update rememberHazeState() calls:

  • Remove blurEnabled parameter if present
  • Move blur enabling logic to blurEffect { blurEnabled = ... } if needed

Update Material style usage:

  • Change hazeEffect(state, style = ...) to hazeEffect(state) { blurEffect { style = ... } }

Position Strategy

V2 introduces a configurable position calculation strategy that fixes blur misalignment in split-window modes (e.g. Huawei Parallel Space). In most cases, no action is needed — the default Auto strategy handles everything.

If you use HazeArea.positionOnScreen in custom effects, rename to position:

// v1
val pos = area.positionOnScreen

// v2
val pos = area.position

If you implement custom VisualEffects, update VisualEffectContext references:

// v1
context.positionOnScreen
context.rootBoundsOnScreen

// v2
context.position
context.rootBounds

If you need to force screen coordinates (e.g. for a custom cross-window setup):

val state = rememberHazeState(positionStrategy = HazePositionStrategy.Screen)

Understanding the New Architecture

The v2 architecture introduces the VisualEffect interface, which allows Haze to support different types of visual effects:

  • VisualEffect - Core interface for all visual effects (in haze module)
  • BlurVisualEffect - Implementation for blur effects (in haze-blur module)
  • HazeEffectScope.visualEffect - Property that holds the current effect

The blurEffect {} extension function is a convenience API that creates and configures a BlurVisualEffect instance. Under the hood, it sets the visualEffect property on HazeEffectScope.

This architecture enables:

  • Better separation of concerns
  • Potential for custom visual effects in the future
  • Smaller core module for users who don't need blur
  • More maintainable and testable code

Getting Help

If you encounter issues during migration: