如何使透明图像的特定部分可点击?

Hem*_*non 5 image-processing flutter flutter-layout

我在 Flutter 应用程序中有一个堆栈,它将多个图像堆叠在一起。它们的宽度和高度都相同,并且具有透明背景。

单独来看,它们看起来像这样:

图1 图2

当它们重叠时,它们看起来像这样:

图3

我需要使每张图片的可见部分可点击。我不想与任何图像的透明部分进行任何交互。我尝试过使用 GestureDetector,但由于所有图像的大小相同,因此效果不太好。我该如何实现这一目标?

Khe*_*rel 5

在此输入图像描述

  1. 在任何矢量图形编辑器中圈出图片的边框,我使用的是figma.com,它是免费的。
  2. 将其另存为 svg 文件,打开它并从 svg 复制路径。
  3. 将 svg 路径转换为 ​​Flutter Paths,我使用了path_drawing包。
  4. 使用自定义剪辑器按路径剪辑图像。
  5. 不幸的是,path_drawing 包忽略了路径的开头。所以你需要通过添加偏移量来添加它。
  6. 添加手势检测器。

在此输入图像描述

    import 'package:flutter/material.dart';
    import 'package:path_drawing/path_drawing.dart';

    void main() => runApp(MyApp());

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: Scaffold(
            body: SafeArea(
              child: MyHomePage(),
            ),
          ),
        );
      }
    }

    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }

    class _MyHomePageState extends State<MyHomePage> {
      String clicked = '';

      @override
      Widget build(BuildContext context) {
        return Stack(
          children: <Widget>[
            _getClippedImage(
              clipper: _Clipper(
                svgPath: svgCarPath,
                offset: Offset(66, 157),
              ),
              image: 'assets/image.png',
              onClick: _handleClick('car'),
            ),
            _getClippedImage(
              clipper: _Clipper(
                svgPath: svgManPath,
                offset: Offset(115, 53),
              ),
              image: 'assets/image.png',
              onClick: _handleClick('man'),
            ),
            Positioned(
              child: Text(
                clicked,
                style: TextStyle(fontSize: 30),
              ),
              bottom: 0,
            ),
          ],
        );
      }

      void Function() _handleClick(String clickedImage) {
        return () => setState(() {
              clicked = clickedImage;
            });
      }

      Widget _getClippedImage({
        _Clipper clipper,
        String image,
        void Function() onClick,
      }) {
        return ClipPath(
          clipper: clipper,
          child: GestureDetector(
            onTap: onClick,
            child: Image.asset('assets/image.png'),
          ),
        );
      }
    }

    class _Clipper extends CustomClipper<Path> {
      _Clipper({this.svgPath, this.offset = Offset.zero});

      String svgPath;
      Offset offset;
      @override
      Path getClip(Size size) {
        var path = parseSvgPathData(svgPath);

        return path.shift(offset);
      }

      @override
      bool shouldReclip(CustomClipper oldClipper) {
        return false;
      }
    }

    const svgCarPath =
        'M35 13.7742L46.9628 1.52606L58.8398 5.97996V17.1147L111.544 13.7742L117.111 50.8899L109.688 55.715C108.575 61.2823 103.75 72.417 93.3574 72.417C82.965 72.417 80.4751 64.3753 80.4751 59.4266C68.1032 55.5913 53.5355 53.8592 39.5397 57.5708C35.0128 76.8252 14.4397 76.0591 12.0741 55.715H0.939362V26.7647L12.0741 17.1147L35.8281 13.7742Z';
    const svgManPath =
        'M50.2647 19.9617C50.6461 5.85163 47.5952 0.703364 38.2521 0.703369C32.0776 2.87051 31.0217 6.36354 30.625 14.0016C30.625 14.0016 27.9555 28.1424 30.625 32.8584C33.2945 37.5744 42.1784 35.788 39.3961 40.7456C36.6138 45.7032 27.9555 63.6268 27.9555 63.6268H22.6165C14.7864 70.572 19.1843 79.9011 12.1293 88.7962C3.01255 100.291 -0.77319 103.733 0.879345 106.911L8.12508 109.199L19.1844 96.8046L12.1293 120.258L15.9428 123.499L22.6165 121.402L32.7224 97.9487L39.3961 104.622C36.5995 110.597 32.2267 122.088 37.108 120.258C43.2097 117.97 54.2865 120.258 66.0909 113.394C75.3267 28.4915 49.8834 34.0719 50.2647 19.9617Z';
Run Code Online (Sandbox Code Playgroud)