如何实现Flutter中如图所示的Container组件?三角区域实现无思路
实现右上角带三角信息区域的Container组件
方法1:用ClipPath自定义裁剪路径
直接把Container的右上角裁剪成三角形,再通过Stack定位文字到三角区域,适合三角和主容器同色的场景。
先定义自定义裁剪器:
class TriangleClipper extends CustomClipper<Path> { @override Path getClip(Size size) { final path = Path(); // 绘制容器轮廓,右上角切出三角 path.lineTo(0, size.height); path.lineTo(size.width, size.height); path.lineTo(size.width, 0); path.lineTo(size.width - 60, 0); // 三角左边界,可调整数值改变三角大小 path.lineTo(0, 0); path.close(); return path; } @override bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false; }
组装组件:
import 'dart:math'; Container( width: 300, height: 180, child: ClipPath( clipper: TriangleClipper(), child: Container( color: Colors.blueGrey[800], child: Stack( children: [ // 背景图(可选) Positioned.fill( child: Opacity( opacity: 0.3, child: Image.network( 'https://picsum.photos/300/180', fit: BoxFit.cover, ), ), ), // 三角区域文字 Positioned( top: 0, right: 0, child: SizedBox( width: 60, height: 60, child: Transform.rotate( angle: -pi / 4, // 顺时针旋转45度 origin: const Offset(30, 30), // 以中心点为旋转轴 child: Column( mainAxisAlignment: MainAxisAlignment.center, children: const [ Text('科幻', style: TextStyle(color: Colors.white, fontSize: 12)), Text('2023', style: TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold)), ], ), ), ), ), // 底部标题 const Positioned( left: 16, bottom: 16, child: Text('星际穿越', style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)), ), ], ), ), ), )
方法2:用Stack叠加独立三角组件
不需要裁剪主容器,直接在右上角叠加一个三角形状的Widget,适合三角和主容器不同色的场景,灵活性更高。
先定义三角Widget:
import 'dart:math'; class TriangleWidget extends StatelessWidget { final Color color; final Widget child; const TriangleWidget({super.key, required this.color, required this.child}); @override Widget build(BuildContext context) { return SizedBox( width: 80, height: 80, child: Stack( children: [ CustomPaint(painter: TrianglePainter(color: color)), Positioned( top: 10, right: 10, child: Transform.rotate( angle: -pi / 4, child: child, ), ), ], ), ); } } class TrianglePainter extends CustomPainter { final Color color; TrianglePainter({required this.color}); @override void paint(Canvas canvas, Size size) { final paint = Paint()..color = color; final path = Path(); path.moveTo(size.width, 0); path.lineTo(size.width, size.height); path.lineTo(0, 0); path.close(); canvas.drawPath(path, paint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; }
组装组件:
Container( width: 300, height: 180, color: Colors.blueGrey[800], child: Stack( children: [ // 背景图(可选) Positioned.fill( child: Opacity( opacity: 0.3, child: Image.network( 'https://picsum.photos/300/180', fit: BoxFit.cover, ), ), ), // 右上角三角组件 const Positioned( top: 0, right: 0, child: TriangleWidget( color: Colors.orange, child: Column( children: [ Text('科幻', style: TextStyle(color: Colors.white, fontSize: 12)), Text('2023', style: TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold)), ], ), ), ), // 底部标题 const Positioned( left: 16, bottom: 16, child: Text('星际穿越', style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)), ), ], ), )
关键调整点
- 三角大小:修改Clipper的偏移量(方法1)或TriangleWidget的宽高(方法2)即可调整。
- 文字位置:通过
Positioned的top/right参数和Transform.rotate的origin参数,让文字在三角内居中。 - 颜色适配:方法2可单独设置三角背景色,不受主容器颜色影响。
内容的提问来源于stack exchange,提问作者Eduardo Latchizy
相关产品推荐
相关产品推荐

