You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter二维码页面模糊效果iOS兼容问题求助

解决iOS上二维码扫描页全模糊问题

问题原因

Flutter中BackdropFilter在Android和iOS上的渲染逻辑存在差异:

  • Android平台会先执行ClipPath裁剪,再对裁剪后的区域应用模糊效果,因此中心清晰、周围模糊的效果正常。
  • iOS平台则是先对整个屏幕内容应用模糊,再执行ClipPath裁剪,导致模糊效果已经覆盖了中心区域,最终呈现全屏幕模糊。

解决方案

方案1:拆分模糊区域(推荐,兼容性更好)

放弃ClipPath,直接用四个独立的模糊区域覆盖屏幕上下左右部分,中心留空显示二维码扫描视图。这种方式避免了裁剪与模糊的顺序冲突,在双平台都能稳定生效。

示例代码:

Stack(
  children: [
    // 底层二维码扫描视图
    QRView(
      key: qrKey,
      onQRViewCreated: _onQRViewCreated,
      overlay: QrScannerOverlayShape(
        borderColor: Colors.transparent, // 关闭自带的遮罩
        borderRadius: 0,
        borderLength: 0,
        borderWidth: 0,
        cutOutSize: 0,
      ),
    ),
    // 顶部模糊区域
    Positioned(
      top: 0,
      left: 0,
      right: 0,
      height: MediaQuery.of(context).size.height / 2 - 100, // 中心扫描框高度200,计算顶部区域高度
      child: BackdropFilter(
        filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
        child: Container(color: Colors.black.withOpacity(0.3)),
      ),
    ),
    // 底部模糊区域
    Positioned(
      bottom: 0,
      left: 0,
      right: 0,
      height: MediaQuery.of(context).size.height / 2 - 100,
      child: BackdropFilter(
        filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
        child: Container(color: Colors.black.withOpacity(0.3)),
      ),
    ),
    // 左侧模糊区域
    Positioned(
      left: 0,
      top: MediaQuery.of(context).size.height / 2 - 100,
      bottom: MediaQuery.of(context).size.height / 2 - 100,
      width: MediaQuery.of(context).size.width / 2 - 100, // 中心扫描框宽度200,计算左侧区域宽度
      child: BackdropFilter(
        filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
        child: Container(color: Colors.black.withOpacity(0.3)),
      ),
    ),
    // 右侧模糊区域
    Positioned(
      right: 0,
      top: MediaQuery.of(context).size.height / 2 - 100,
      bottom: MediaQuery.of(context).size.height / 2 - 100,
      width: MediaQuery.of(context).size.width / 2 - 100,
      child: BackdropFilter(
        filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
        child: Container(color: Colors.black.withOpacity(0.3)),
      ),
    ),
    // 中心扫描框边框(可选)
    Center(
      child: Container(
        width: 200,
        height: 200,
        decoration: BoxDecoration(
          border: Border.all(color: Colors.white, width: 2),
          borderRadius: BorderRadius.circular(8),
        ),
      ),
    ),
  ],
)

方案2:修复ClipPath与BackdropFilter的层级

通过RepaintBoundary限制模糊的渲染范围,强制iOS平台先裁剪再模糊。但该方案在部分复杂场景下可能仍存在兼容性问题:

示例代码:

Stack(
  children: [
    QRView(
      key: qrKey,
      onQRViewCreated: _onQRViewCreated,
      overlay: QrScannerOverlayShape(
        borderColor: Colors.transparent,
        borderRadius: 0,
        borderLength: 0,
        borderWidth: 0,
        cutOutSize: 0,
      ),
    ),
    RepaintBoundary(
      child: ClipPath(
        clipper: _ScannerOverlayClipper(), // 自定义裁剪器,挖空中心区域
        child: BackdropFilter(
          filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
          child: Container(color: Colors.black.withOpacity(0.3)),
        ),
      ),
    ),
  ],
)

// 自定义裁剪器示例
class _ScannerOverlayClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final centerRect = Rect.fromCenter(
      center: Offset(size.width / 2, size.height / 2),
      width: 200,
      height: 200,
    );
    final screenPath = Path()..addRect(Rect.fromLTWH(0, 0, size.width, size.height));
    final centerPath = Path()..addRect(centerRect);
    // 用屏幕路径减去中心路径,得到周围区域的路径
    return Path.combine(PathOperation.difference, screenPath, centerPath);
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}

内容的提问来源于stack exchange,提问作者Matheus Angelicio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 12:24:53