首页 > 解决方案 > 自定义小部件引发事件在颤动中不起作用

问题描述

我需要一个自定义小部件来在我的页面上绘制垂直和水平线,我可以在运行时调整小部件的大小。我将 DrawLine 的 GestureDetector 与油漆和画布结合起来,所以我有一个名为Line的类,我可以在这个类上绘制我的线条

所以我在颤振中创建了一个自定义小部件,用于在运行时绘制具有调整大小属性的垂直线

我在颤振上写了这段代码


import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  double height = 300;
  double top = 0;
  double left = 200;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Text Overflow Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: Stack(
          children: <Widget>[
            new DrawLineClass(top: 50, left: 100, height: 400),
            new DrawLineClass(top: 100, left: 50, height: 300),
            new DrawLineClass(top: 150, left: 150, height: 300),
          ],
        ),
      ),
    );
  }
}

const double ballDiameter = 20.0;
const double strokeWidth = 10.0;

class DrawLineClass extends StatefulWidget {
  DrawLineClass({Key key, this.top, this.left, this.height}) : super(key: key);

  double height;
  double top;
  double left;

  @override
  _DrawLineClassState createState() => _DrawLineClassState();
}

class _DrawLineClassState extends State<DrawLineClass> {
  @override
  Widget build(BuildContext context) {
    return new Stack(
      children: <Widget>[
        Line(start: {"x": widget.left, "y": widget.top}, end: {"x": widget.left, "y": widget.height}),
        // top middle
        Positioned(
          top: widget.top - ballDiameter / 2,
          left: widget.left - ballDiameter / 2,

          child: new ManipulatingBall(
            onDrag: (dx, dy) {
              setState(() {
                widget.top = widget.top + dy;
              });
            },
          ),
        ),
        // bottom center
        Positioned(
          top: widget.height - ballDiameter / 2,
          left: widget.left - ballDiameter / 2,
          child: new ManipulatingBall(
            onDrag: (dx, dy) {
              var newHeight = widget.height + dy;

              setState(() {
                widget.height = newHeight > 0 ? newHeight : 0;
              });
            },
          ),
        ),
      ],
    );
  }
}

class ManipulatingBall extends StatefulWidget {
  ManipulatingBall({Key key, this.onDrag}) : super(key: key);

  Function onDrag;

  @override
  _ManipulatingBallState createState() => _ManipulatingBallState();
}

class _ManipulatingBallState extends State<ManipulatingBall> {
  double initX;
  double initY;

  _handleDrag(details) {
    setState(() {
      initX = details.globalPosition.dx;
      initY = details.globalPosition.dy;
    });
  }

  _handleUpdate(details) {
    var dx = details.globalPosition.dx - initX;
    var dy = details.globalPosition.dy - initY;
    initX = details.globalPosition.dx;
    initY = details.globalPosition.dy;
    widget.onDrag(dx, dy);
  }

  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      behavior: HitTestBehavior.deferToChild,
      onPanStart: _handleDrag,
      onPanUpdate: _handleUpdate,
      child: Container(
        width: ballDiameter,
        height: ballDiameter,
        decoration: BoxDecoration(
          color: Colors.blue.withOpacity(0.5),
          shape: BoxShape.circle,
        ),
      ),
    );
  }
}

class Line extends StatefulWidget {
  final Map<String, double> start;
  final Map<String, double> end;
  Line({this.start, this.end});

  @override
  _LineState createState() => _LineState();
}

class _LineState extends State<Line> with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      size: Size(MediaQuery.of(context).size.width,
          MediaQuery.of(context).size.height),
      painter: DrawLine(start: widget.start, end: widget.end),
    );
  }
}

class DrawLine extends CustomPainter {
  Map<String, double> start;
  Map<String, double> end;
  DrawLine({this.start, this.end});

  @override
  void paint(Canvas canvas, Size size) {
    Paint line = new Paint()
      ..color = Colors.red
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.fill
      ..strokeWidth = strokeWidth;
    canvas.drawLine(Offset(start["x"], start["y"]), Offset(end["x"], end["y"]), line);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return true;
  }
}

我在我的页面上画了 3 行但只有最新的行可以调整大小有
什么问题?

标签: fluttereventscustom-widgets

解决方案


每一行都画在整个屏幕上,第三行覆盖第一行和第二行,第一行和第二行都不能接收到 GestureDetector 的事件。相反,您可以使用 LayoutBuidler 以相对位置而不是全局位置绘制线条。


推荐阅读