如何在 Flutter Stack 中实现同一位置的 widget 的点击传播?

问题描述 投票:0回答:1

我正在 Flutter 中使用 Stack,其中有两个小部件(蓝色和黄色)放置在完全相同的位置且大小相同。蓝色小部件位于底部,黄色小部件位于顶部。zwo widgets

我希望顶部的黄色小部件最初处理点击事件。但是,我希望黄色小部件可以选择决定是否要处理事件或将其传递给其下方的蓝色小部件。

我希望用户能够单击蓝色或黄色三角形。但是,如果用户单击黄色三角形下方的蓝色三角形,我将无法触发蓝色小部件的 onTap 事件。

我怎样才能实现这种行为?具体来说,我希望黄色小部件首先处理单击事件,但如果它决定不处理该事件,我希望该事件传递给它下面的蓝色小部件。

有什么建议或最佳实践来实现这一点吗?

flutter widget click
1个回答
0
投票

试试这个:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: false),
      home: const Home(),
    );
  }
}

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

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  bool _yellowHandlesTap = true;
  void _handleYellowTap() {
    setState(() {
      _yellowHandlesTap = !_yellowHandlesTap;
    });

    if (_yellowHandlesTap) {
      print('Yellow widget handled the tap');
    } else {
      print('Yellow widget passed the tap to Blue widget');
    }
  }

  void _handleBlueTap() {
    print('Blue widget handled the tap');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SizedBox(
          height: 200,
          width: 200,
          child: Stack(
            children: [
              Align(
                alignment: Alignment.centerRight,
                child: ClipPath(
                  clipper: BlueClipper(),
                  child: GestureDetector(
                    onTap: _handleBlueTap,
                    child: Container(
                      height: 200,
                      width: 200,
                      color: Colors.blue,
                      child: CustomPaint(
                        painter: BlueTriangleBorderPainter(),
                      ),
                    ),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.centerRight,
                child: ClipPath(
                  clipper: YellowClipper(),
                  child: GestureDetector(
                    onTap: _handleYellowTap,
                    child: Container(
                      height: 200,
                      width: 200,
                      color: Colors.yellow,
                      child: CustomPaint(
                        painter: YellowTriangleBorderPainter(),
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class BlueClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final x = size.width;
    final y = size.height;
    final path = Path();

    path
      ..moveTo(0, 0)
      ..lineTo(x, 0)
      ..lineTo(0, y);
    path.close();

    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
    return false;
  }
}

class YellowClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final x = size.width;
    final y = size.height;
    final path = Path();
    path
      ..moveTo(x, y)
      ..lineTo(x, 0)
      ..lineTo(0, y);
    path.close();

    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
    return false;
  }
}

class BlueTriangleBorderPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 3
      ..color = Colors.black;

    final path = Path();

    var y = size.height;
    var x = size.width;

    path
      ..moveTo(0, 0)
      ..lineTo(x, 0)
      ..lineTo(0, y);

    path.close();

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

class YellowTriangleBorderPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 3
      ..color = Colors.black;

    final path = Path();

    var y = size.height;
    var x = size.width;

    path
      ..moveTo(x, y)
      ..lineTo(x, 0)
      ..lineTo(0, y);

    path.close();

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

© www.soinside.com 2019 - 2024. All rights reserved.