Flutter:如何让LinePainter基于手机屏幕坐标而非容器坐标绘制线条?
Flutter:如何让LinePainter基于手机屏幕坐标而非容器坐标绘制线条?
嘿,我懂你现在的困扰——默认情况下CustomPainter的画布是跟着父容器的局部坐标走的,要改成用屏幕全局坐标来画线确实需要做一点坐标转换的工作,我来给你捋捋具体步骤:
首先,你需要拿到承载绘制内容的容器和屏幕全局坐标之间的转换关系,这里我们可以用GlobalKey来定位你的绘制容器:
- 先定义一个全局key,用来定位你的绘制容器:
final GlobalKey _paintContainerKey = GlobalKey();
- 在你的
build方法里,把这个key绑定到承载CustomPaint的父容器上(比如你代码里的Row或者外层的容器):
@override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; final center = Offset(size.width / 2, size.height / 2); return Row( key: _paintContainerKey, // 绑定key crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ // 你的RichText和其他组件... CustomPaint( painter: LinePainter( containerKey: _paintContainerKey, // 这里传入你要画的全局坐标点,比如屏幕中心 globalStart: Offset(size.width * 0.2, size.height * 0.2), globalEnd: center, ), ), ], ); }
- 修改你的
LinePainter类,让它能接收全局坐标和容器key,然后在paint方法里把全局坐标转换成容器的局部坐标:
class LinePainter extends CustomPainter { final Offset globalStart; final Offset globalEnd; final GlobalKey containerKey; LinePainter({ required this.globalStart, required this.globalEnd, required this.containerKey, }); @override void paint(Canvas canvas, Size size) { // 获取容器的渲染对象,用来做坐标转换 final renderBox = containerKey.currentContext?.findRenderObject() as RenderBox?; if (renderBox == null) return; // 把屏幕全局坐标转换成容器的局部坐标 final localStart = renderBox.globalToLocal(globalStart); final localEnd = renderBox.globalToLocal(globalEnd); // 定义画笔属性 final paint = Paint() ..color = Colors.black ..strokeWidth = 2 ..style = PaintingStyle.stroke; // 用转换后的局部坐标画线 canvas.drawLine(localStart, localEnd, paint); } @override bool shouldRepaint(covariant LinePainter oldDelegate) { // 当坐标变化时重绘 return oldDelegate.globalStart != globalStart || oldDelegate.globalEnd != globalEnd; } }
如果是需要动态绘制(比如用户触摸屏幕画线),你可以在GestureDetector的触摸事件里直接拿到全局坐标,再更新给Painter:
GestureDetector( onPanStart: (details) { setState(() { _startPoint = details.globalPosition; // 获取触摸起始的全局坐标 }); }, onPanUpdate: (details) { setState(() { _currentPoint = details.globalPosition; // 更新当前触摸的全局坐标 }); }, child: CustomPaint( painter: LinePainter( containerKey: _paintContainerKey, globalStart: _startPoint, globalEnd: _currentPoint, ), child: // 你的现有组件 ), )
要注意的是,如果你的容器有滚动、缩放或者其他变换(比如Transform组件),globalToLocal方法会自动处理这些变换带来的坐标偏移,所以不用额外操心~
备注:内容来源于stack exchange,提问作者Snork Maiden
相关产品推荐
相关产品推荐

