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-blurmodule - API nesting: All blur properties now require a
blurEffect {}wrapper - Package changes: Blur-related classes moved to
dev.chrisbanes.haze.blurpackage - Removed APIs:
rememberHazeState(blurEnabled)parameter removed - Position strategy: New
HazePositionStrategyconfiguration onHazeState - Renames:
HazeArea.positionOnScreen→position,VisualEffectContext.positionOnScreen→position,VisualEffectContext.rootBoundsOnScreen→rootBounds
What Hasn't Changed:
- Core modifiers (
hazeSource,hazeEffect) signatures remain the same - Platform support unchanged
- Performance characteristics unchanged
HazeEffectScopeproperties likeinputScale,drawContentBehind,canDrawAreaunchanged
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.HazeStyle→dev.chrisbanes.haze.blur.HazeBlurStyle - Change
dev.chrisbanes.haze.HazeTint→dev.chrisbanes.haze.blur.HazeColorEffect - Change
dev.chrisbanes.haze.HazeProgressive→dev.chrisbanes.haze.blur.HazeProgressive - Change
dev.chrisbanes.haze.LocalHazeStyle→dev.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,canDrawAreaoutside theblurEffect {}block
Update rememberHazeState() calls:
- Remove
blurEnabledparameter if present - Move blur enabling logic to
blurEffect { blurEnabled = ... }if needed
Update Material style usage:
- Change
hazeEffect(state, style = ...)tohazeEffect(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 (inhazemodule)BlurVisualEffect- Implementation for blur effects (inhaze-blurmodule)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:
- Check the GitHub Discussions
- Review the updated usage documentation
- See working examples in the sample app
- File an issue on GitHub