乐于分享
好东西不私藏

Expo 毛玻璃头部组件,终于有人把 iOS 和 Android 统一了

Expo 毛玻璃头部组件,终于有人把 iOS 和 Android 统一了
做过 App 毛玻璃效果的同学,大概都踩过这两个坑:

iOS 上用 UIVisualEffectView,效果漂亮,但 Android 那边要么性能差、要么效果不对——得用不同方案分别适配,写两套代码,维护两套效果。

Android 11 之后原生支持毛玻璃,但低版本系统又得找第三方库兼容。团队小的时候,光一个头部模糊就搞得人仰马翻。

今天介绍的这个开源项目,叫 variable-header-blur。一个组件,iOS 和 Android 原生毛玻璃,代码一样效果一致。

https://github.com/hewad-mubariz/variable-header-blur

Demo

iOS

已关注
关注
重播 分享

Android

已关注
关注
重播 分享

先说它能做什么

variable-header-blur 是一个 Expo 模块,专注于 App 头部导航栏的毛玻璃效果。

它做的事很简单:给你一个可配置的毛玻璃头部组件,iOS 和 Android 共用一套代码,原生实现,效果统一。

import { VariableHeaderBlurView } from"variable-header-blur";<VariableHeaderBlurViewheaderHeight={HEADER_TOTAL_HEIGHT}maxBlurRadius={16}tintOpacityTop={0.3}tintOpacityMiddle={0.1}style={{position: "absolute", top:0left:0right:0 }}>  {/* Header content */}</VariableHeaderBlurView>;

就这么多。把毛玻璃头部当成一个容器,往里塞你的导航栏内容,剩下的它自己搞定。

核心:渐进式模糊

这个组件最大的特点,是渐进式模糊——从顶部到底部,模糊强度逐渐减弱。

这不是普通的"整块模糊",而是模拟真实毛玻璃材质的光学特性:越靠上、越靠近光源,模糊越强;越往下,内容越清晰。

这个效果在 iOS 原生支持——用 UIVisualEffectView 配合私有的 variableBlur 滤镜实现。Android 则用 chrisbanes/haze 库,在 Compose 里跑同样的渐进式模糊管线。

两个平台最终呈现的视觉效果基本一致——这对 UI 一致性要求高的 App 来说,是实打实的减负。


iOS 和 Android,各用什么方案

项目在两个平台用了不同的底层实现,但都达到了相近的视觉目标:

iOS 方案

基于 nikstar/VariableBlur,用 UIVisualEffectView 承载苹果私有的 variableBlur 滤镜。梯度遮罩(gradient mask)驱动每个像素的模糊强度,实现真正的渐进式模糊。SwiftUI 组件包装在 Expo ExpoView 里,暴露给 React Native 使用。

Android 方案

用 chrisbanes/haze 的管线,在 Compose 原生视图里运行:

  • hazeSource(state)
     标记内容源图层
  • hazeEffect(state)
     应用模糊 + 色调
  • HazeProgressive.verticalGradient(...)
     控制渐进式模糊衰减

外加一层 Canvas 渐变,让色调过渡和模糊强度对齐。整体效果接近 iOS 的原生表现。

几个关键配置

组件提供了一组 Props,精准控制模糊效果:

Prop
平台
说明
默认值
headerHeight
双平台
模糊头部区域高度
maxBlurRadius
双平台
最大模糊强度
iOS 15 / Android 16
tintOpacityTop
双平台
顶部色调不透明度
iOS 0.4 / Android 0.3
tintOpacityMiddle
双平台
中间色调不透明度
0.1
tintColor
仅 Android
色调颜色
progressiveStartY
仅 Android
渐进模糊起始 Y
progressiveEndY
仅 Android
渐进模糊结束 Y

可以看到,Android 多了几个高级调参项——tintColorprogressiveStartYprogressiveEndY——给需要精细控制效果的开发者留了口子。

局限性和门槛

这个模块包含自定义原生代码,不支持 Expo Go,必须用 development build:

npx expo prebuildnpx expo run:iosnpx expo run:android

换句话说:适合正经做 App 项目的团队,不适合快速原型预览。

但如果你本来就用 Expo 做生产级 App,这个门槛就不是门槛——只是顺手的事。


技术细节值得单独说

整个架构设计很干净:

src/VariableHeaderBlurView.tsx   → 暴露原生视图管理器ios/VariableHeaderBlurView.swift → iOS 毛玻璃 + 渐变遮罩android/VariableHeaderBlurView.kt → Android Haze 渐进模糊 + 色调渐变

原生 Props 通过 VariableHeaderBlurModule 在双平台映射,React Native 这侧只管用 Props 调用,不用关心底层实现。

这种架构的好处:视图逻辑和平台实现完全分离,后续如果要加新平台,或者调整某平台的模糊算法,不影响另一侧,也不影响 React Native 调用侧。

你可以从哪里开始

如果你现在正在做 Expo App 的头部导航,或者正好在调研毛玻璃实现方案:

  1. 去 GitHub 页面看一下 Demo 视频(iOS 和 Android 各有一个)
  2. Clone 项目,看 src/VariableHeaderBlurView.tsx 的 Props 定义
  3. 按文档步骤在自己的 Expo 项目里引入
# 1. 把模块放进项目modules/variable-header-blur# 2. 加到 package.json"variable-header-blur""file:./modules/variable-header-blur"# 3. yarn install 然后 prebuildnpx expo prebuild

原生毛玻璃这件事,iOS 和 Android 一直有两套实现思路。

variable-header-blur 的价值,不是造了个新轮子——是把这两套思路在 Expo 体系里接起来了,让你好歹用一套代码。

如果你正被双端毛玻璃效果折磨,这个项目值得一试。

项目地址:https://github.com/hewad-mubariz/variable-header-blur

如果身边有做 Expo 开发的朋友,这篇可以转给他看看。