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

Flutter:如何检测自定义绘制覆盖后屏幕是否完全变白?

问题:检测白色绘制是否完全覆盖初始背景

我在谷歌搜索后,找到的都是从Image中获取颜色像素的方案,这与我的场景不同,这类问题可使用image_pixels插件解决,但这不是我的需求。

我正在开发一个页面,用户可通过手指完成小游戏:擦除屏幕内容,当屏幕完全变为白色时完成测试,本质是覆盖当前页面的所有颜色。

我的问题是不知道如何检测用户绘制的白色是否完全覆盖初始背景。我在谷歌找到一个类似的旧帖子,但无人解答,不确定是否可行。

我尝试过创建橡皮擦对象,但遇到BlendMode.clear无法生效的问题,且我不想通过Offset位置获取像素颜色,而是希望编写条件判断整个页面是否完全变白。


CustomPainter代码

class ScreenCheckPainter extends CustomPainter {
  final List<Sketch> points;

  ScreenCheckPainter({required this.points});

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 65.0
      ..style = PaintingStyle.stroke;

    canvas.saveLayer(Rect.largest, Paint());

    for (Sketch sketch in points) {
      final point = sketch.points;

      final path = Path();
      path.moveTo(point.first.dx, point.first.dy);

      for (int i = 0; i < point.length - 1; ++i) {
        final p0 = point[i];
        final p1 = point[i + 1];

        path.quadraticBezierTo(
          p0.dx,
          p0.dy,
          (p0.dx + p1.dx) / 2,
          (p0.dy + p1.dy) / 2,
        );
        canvas.drawCircle(point[i], 10, paint..color = Colors.white);
      }

      canvas.drawPath(path, paint..color = Colors.white);
    }
    canvas.restore();
  }

  @override
  bool shouldRepaint(ScreenCheckPainter oldDelegate) {
    return oldDelegate.points != points;
  }
}

UI代码

class ScreenCheckPage extends ConsumerStatefulWidget {
  const ScreenCheckPage({super.key});

  @override
  ConsumerState<ConsumerStatefulWidget> createState() =>
      _ScreenCheckPageState();
}

class _ScreenCheckPageState extends ConsumerState<ScreenCheckPage> {
  final List<Offset> points = <Offset>[];

  Offset localPos = const Offset(-1, -1);

  @override
  Widget build(
    BuildContext context,
  ) {
    Widget buildCurrentPath(BuildContext context, GetSketch currentSketch,
        GetSketchList currentListSketch) {
      int _pointers = 0;
      var countdown = ref.watch(testCountdownProvider);

      return GestureDetector(
        onPanDown: (details) {
          final box = context.findRenderObject() as RenderBox;
          final offset = box.globalToLocal(details.localPosition);

          setState(
            () {
              localPos = details.localPosition;
              currentSketch.updateCurrentSketch(Sketch(points: [offset]));
              _pointers++;
            },
          );

          //debugPrint(currentSketch.currentSketch.toString());
        },
        onPanUpdate: (details) {
          final box = context.findRenderObject() as RenderBox;
          final offset = box.globalToLocal(details.localPosition);
      

          final points =
              List<Offset>.from(ref.read(getSketchProvider)?.points ?? [])
                ..add(offset);

          setState(
            () {
              localPos = details.localPosition;
              currentSketch.updateCurrentSketch(Sketch(points: points));
              _pointers--;
            },
          );

          //debugPrint(currentSketch.currentSketch.toString());
        },
        onPanEnd: (details) {
          setState(
            () {
              currentListSketch
                  .updateCurrentListSketch(ref.read(getSketchProvider)!);
            },
          );
        },
        child: IgnorePointer(
          ignoring: _pointers > 1,
          child: _pointers > 1
              ? null
              : SizedBox(
                height: MediaQuery.of(context).size.height,
                width: MediaQuery.of(context).size.width,
                child: CustomPaint(
                  isComplex: true,
                  willChange: true,
                  painter: ScreenCheckPainter(
                    points: ref.read(getSketchProvider) == null
                        ? []
                        : [ref.read(getSketchProvider)!],
                  ),
                  child: Container(
                    alignment: Alignment.bottomCenter,
                    margin: const EdgeInsets.only(bottom: 50),
                  ),
                ),
              ),
        ),
      );
    }

    Widget buildAllPath(BuildContext context, GetSketchList currentListSketch) {
      return SizedBox(
        height: MediaQuery.of(context).size.height,
        width: MediaQuery.of(context).size.width,
        child: CustomPaint(
          foregroundPainter: ScreenCheckPainter(
            points: ref.read(getSketchListProvider),
          ),
        ),
      );
    }

    final GetSketch currentSketch = ref.watch(getSketchProvider.notifier);
    final GetSketchList currentListSketch =
        ref.watch(getSketchListProvider.notifier);

    return RepaintBoundary(
      child: Stack(
        children: [
          const Image(
            image: AssetImage("assets/design/ambercolor.png"), 
            fit: BoxFit.cover,
            height: double.infinity,
            width: double.infinity,
            alignment: Alignment.center,
          ),
          buildAllPath(context, currentListSketch),
          buildCurrentPath(context, currentSketch, currentListSketch),
        ],
      ),
    );
  }
}

Riverpod状态代码

@riverpod
class GetSketch extends _$GetSketch {
 Sketch? _currentSketch;
 Sketch? get currentSketch => _currentSketch;

 @override
 Sketch? build() {
   return currentSketch;
 }

 void updateCurrentSketch(Sketch newSketchPos) {
   state = newSketchPos;
 }

 Sketch? getCurrentSketch() {
   return state;
 }
}

@riverpod
class GetSketchList extends _$GetSketchList {
 final List<Sketch> _currentListSketch = [];
 List<Sketch> get currentListSketch => _currentListSketch;

 @override
 List<Sketch> build() {
   return currentListSketch;
 }

 void updateCurrentListSketch(Sketch newSketchData) {
   state = [...state, newSketchData];
 }

 List<Sketch> getListOfSketch() {
   
   return state;
 }
}

Model代码

class Sketch {
 final List<Offset> points;

 Sketch({required this.points});
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 02:36:04