Flutter实现带中间文字的Container完整边框(类分割线效果)
实现带内嵌留白文字的完整边框容器
方案一:用Stack快速实现(推荐)
利用Stack将带边框的容器和带背景的文字叠加,文字背景会覆盖下方的边框,形成留白效果,实现简单易维护。
class BorderedTitleContainer extends StatelessWidget { final String title; final Widget child; final Color borderColor; final Color bgColor; final double borderWidth; final double borderRadius; const BorderedTitleContainer({ super.key, required this.title, required this.child, this.borderColor = Colors.grey, this.bgColor = Colors.white, this.borderWidth = 1.0, this.borderRadius = 8.0, }); @override Widget build(BuildContext context) { return Stack( alignment: Alignment.topCenter, children: [ // 底层带边框的容器,顶部预留文字空间 Container( margin: const EdgeInsets.only(top: 12), padding: const EdgeInsets.all(16), decoration: BoxDecoration( border: Border.all(color: borderColor, width: borderWidth), borderRadius: BorderRadius.circular(borderRadius), ), child: child, ), // 上层标题,用背景色覆盖边框 Container( padding: const EdgeInsets.symmetric(horizontal: 8), color: bgColor, child: Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: borderColor, ), ), ), ], ); } }
使用示例
BorderedTitleContainer( title: "用户信息", child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text("姓名: 张三"), SizedBox(height: 8), Text("年龄: 28"), SizedBox(height: 8), Text("邮箱: zhangsan@example.com"), ], ), )
方案二:自定义Painter实现(灵活定制)
如果需要文字在左侧/右侧/底部,或者边框样式更复杂,用CustomPainter可以完全自定义绘制逻辑。
首先定义位置枚举和绘制类:
import 'dart:math' as math; enum TitlePosition { topCenter, leftCenter, rightCenter, bottomCenter } class BorderWithTitlePainter extends CustomPainter { final String title; final Color borderColor; final Color titleBgColor; final double borderWidth; final TextStyle titleStyle; final TitlePosition titlePosition; final double borderRadius; BorderWithTitlePainter({ required this.title, required this.borderColor, required this.titleBgColor, required this.borderWidth, required this.titleStyle, required this.titlePosition, this.borderRadius = 8.0, }); @override void paint(Canvas canvas, Size size) { // 绘制完整边框 final borderPaint = Paint() ..color = borderColor ..strokeWidth = borderWidth ..style = PaintingStyle.stroke; canvas.drawRRect( RRect.fromRectAndRadius( Rect.fromLTWH(0, 0, size.width, size.height), Radius.circular(borderRadius), ), borderPaint, ); // 计算文字尺寸 final textSpan = TextSpan(text: title, style: titleStyle); final textPainter = TextPainter( text: textSpan, textDirection: TextDirection.ltr, )..layout(); final textW = textPainter.width; final textH = textPainter.height; const padding = 8.0; // 根据位置计算文字和背景的偏移 Offset textOffset; Rect bgRect; switch (titlePosition) { case TitlePosition.topCenter: textOffset = Offset((size.width - textW)/2, -textH/2); bgRect = Rect.fromLTWH( (size.width - textW - padding*2)/2, -textH/2, textW + padding*2, textH, ); break; case TitlePosition.leftCenter: textOffset = Offset(-textW/2, (size.height - textH)/2); bgRect = Rect.fromLTWH( -textW/2 - padding, (size.height - textH)/2, textW + padding*2, textH, ); canvas.rotate(-math.pi/2); canvas.translate(-size.height, 0); break; // 可自行扩展其他位置的逻辑 default: textOffset = Offset((size.width - textW)/2, -textH/2); bgRect = Rect.fromLTWH( (size.width - textW - padding*2)/2, -textH/2, textW + padding*2, textH, ); } // 绘制文字背景(覆盖边框) canvas.drawRect(bgRect, Paint()..color = titleBgColor); // 绘制文字 textPainter.paint(canvas, textOffset); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => true; }
使用示例
CustomPaint( painter: BorderWithTitlePainter( title: "高级设置", borderColor: Colors.blue, titleBgColor: Colors.white, borderWidth: 2.0, titleStyle: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.blue, ), titlePosition: TitlePosition.topCenter, ), child: const SizedBox( width: 350, height: 250, child: Padding( padding: EdgeInsets.all(20.0), child: Text("这里是高级设置的内容区域"), ), ), )
为什么分割线组件无法实现?
分割线是单一方向的线条组件,只能实现局部分割效果,无法组合成完整边框,更没法在边框中间实现带背景留白的文字嵌入。而上述两种方案通过叠加或自定义绘制,能轻松实现边框与文字的融合效果。
内容的提问来源于stack exchange,提问作者Maenda
相关产品推荐
相关产品推荐

