Flutter技术问询:如何实现仅容器边框模糊且内部区域不受影响
实现Flutter容器边框模糊(内部区域不受影响)
问题说明
现有如下Flutter代码,想要实现仅容器边框模糊,内部白色区域不受模糊影响,尝试使用ShaderMask但无法将模糊效果限定在边框区域:
import 'package:flutter/material.dart'; class A2 extends StatefulWidget { const A2({Key? key}) : super(key: key); @override State<A2> createState() => _A2State(); } class _A2State extends State<A2> { @override Widget build(BuildContext context) { return Scaffold( body: ShaderMask( shaderCallback: ( bounds) { return LinearGradient( colors: [Colors.white.withOpacity(0.05),Colors.white], stops: const [0.0, 0.09], tileMode: TileMode.mirror, begin: Alignment.center, end: Alignment.center ).createShader(bounds); }, child: Container( decoration: BoxDecoration( border: Border.all(color: Colors.red, width: 100), ), ), ) ); } }
解决方案
推荐使用Stack结合ClipPath和BackdropFilter实现精准的边框模糊效果,以下是修改后的完整代码:
import 'package:flutter/material.dart'; import 'dart:ui'; // 导入dart:ui使用ImageFilter class A2 extends StatefulWidget { const A2({Key? key}) : super(key: key); @override State<A2> createState() => _A2State(); } class _A2State extends State<A2> { @override Widget build(BuildContext context) { const borderWidth = 100.0; const containerSize = 300.0; return Scaffold( backgroundColor: Colors.grey[300], // 设置背景色方便查看模糊效果 body: Center( child: Stack( alignment: Alignment.center, children: [ // 1. 底层:红色边框容器(作为模糊的基础) Container( width: containerSize, height: containerSize, decoration: BoxDecoration( border: Border.all(color: Colors.red, width: borderWidth), ), ), // 2. 中间层:仅对边框区域应用模糊滤镜 ClipPath( clipper: _BorderClipper(borderWidth: borderWidth), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), // 调整sigma值控制模糊强度 child: Container( width: containerSize, height: containerSize, color: Colors.transparent, ), ), ), // 3. 顶层:内部内容容器(完全不受模糊影响) Container( width: containerSize - 2 * borderWidth, height: containerSize - 2 * borderWidth, color: Colors.white, child: const Center( child: Text("内部无模糊内容", style: TextStyle(fontSize: 18)), ), ), ], ), ), ); } } // 自定义裁剪器:裁剪出仅边框的区域 class _BorderClipper extends CustomClipper<Path> { final double borderWidth; _BorderClipper({required this.borderWidth}); @override Path getClip(Size size) { // 外层矩形(整个容器) final outerRect = Rect.fromLTWH(0, 0, size.width, size.height); // 内层矩形(减去边框宽度后的区域) final innerRect = Rect.fromLTWH( borderWidth, borderWidth, size.width - 2 * borderWidth, size.height - 2 * borderWidth, ); // 通过PathFillType.evenOdd取两个矩形的差集,即边框区域 return Path() ..addRect(outerRect) ..addRect(innerRect) ..fillType = PathFillType.evenOdd; } @override bool shouldReclip(_BorderClipper oldClipper) { return oldClipper.borderWidth != borderWidth; } }
方案说明
- 三层结构逻辑:
- 底层是原始的红色边框容器,作为模糊效果的载体;
- 中间层通过
_BorderClipper精准裁剪出边框区域,再用BackdropFilter对该区域应用模糊; - 顶层是内部内容容器,完全覆盖在模糊边框之上,不受模糊影响。
- 关键细节:
PathFillType.evenOdd是实现边框裁剪的核心,它会绘制两个矩形的差集区域;- 调整
BackdropFilter的sigmaX和sigmaY可以控制模糊的强度,值越大模糊效果越明显; - 内部容器的尺寸需要减去两倍边框宽度,确保完全贴合边框内部。
内容的提问来源于stack exchange,提问作者Mohammed Hamdan
相关产品推荐
相关产品推荐

