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

Flutter如何实现点击图片时在点击的精确位置绘制圆形标记

解决方案

核心问题修正点

  • 你当前在onTap回调里直接创建CustomPaint的写法不会生效,Widget只有被加入到Widget树的build返回结构里才会被渲染
  • 普通onTap回调无法获取点击的精确坐标,需要用onTapDown回调获取点击位置
  • 要实现圆形叠加在图片上,需要用Stack组件把图片和绘制图层叠放
  • 点击位置需要用状态变量存储,每次点击更新状态触发重绘

完整修改后代码

import 'package:flutter/material.dart';

class Cible extends StatefulWidget {
  const Cible({super.key});

  @override
  State<Cible> createState() => _CibleState();
}

class _CibleState extends State<Cible> {
  // 存储所有点击的坐标点
  final List<Offset> _tapPoints = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        centerTitle: true,
        title: const Text('My APP'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('点击任意位置生成圆形标记'),
            GestureDetector(
              // 用onTapDown获取精确点击位置
              onTapDown: (details) {
                setState(() {
                  // 存入相对于图片内部的点击坐标
                  _tapPoints.add(details.localPosition);
                });
              },
              child: Stack(
                alignment: Alignment.center,
                children: [
                  // 底层显示图片
                  Image(
                    image: const AssetImage("images/body.png"),
                    width: 280,
                    height: 450,
                  ),
                  // 上层绘制圆形标记
                  CustomPaint(
                    size: const Size(280, 450),
                    painter: CirclePainter(points: _tapPoints),
                  )
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class CirclePainter extends CustomPainter {
  // 接收需要绘制的所有点坐标
  final List<Offset> points;
  final Paint _paint = Paint()
    ..color = Colors.teal
    ..strokeWidth = 15;

  CirclePainter({required this.points});

  @override
  void paint(Canvas canvas, Size size) {
    // 遍历所有点击点绘制圆形
    for (var point in points) {
      canvas.drawCircle(point, 15, _paint);
    }
  }

  @override
  bool shouldRepaint(covariant CirclePainter oldDelegate) {
    // 坐标列表变化时触发重绘
    return oldDelegate.points != points;
  }
}

功能说明

  • 每次点击图片都会在点击位置添加一个青色圆形标记
  • 支持多次点击添加多个标记,如果你只需要保留最后一个标记,点击时把_tapPoints.add换成_tapPoints = [details.localPosition]即可
  • 坐标是相对于图片内部的,不会因为页面其他元素布局变化出现偏移

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 01:24:03