Flutter - Получение сенсорного ввода на CustomPainters - PullRequest
0 голосов
/ 25 мая 2018

У меня есть простой CustomPaint / CustomPainter, который рисует сегмент круга (код ниже).Я читал, что не могу использовать GestureDetector, потому что это неправильный виджет, так как лучше всего получить ввод?

У меня будет куча сегментов вместе, поэтому мне нужен пиксель с точностью до пикселяместоположение касания.

Я подумал о двух возможностях:

  • Поместите рисовальщик в SizedBox и получите координаты касания и вручную рассчитайте, находится ли он в пределах пути.Но это будет удвоение кода.
  • Используйте класс Material и пользовательский BorderShape.Это было бы удобно, но мне кажется довольно хакерским.

My CustomPainter:

class _SegmentPainter extends CustomPainter {
  static const offset = -pi/2;
  double start;
  double end;
  double innerRadius;
  double outerRadius;
  Color color;
  _SegmentPainter(this.start, this.end, {this.innerRadius = 0.0, this.outerRadius, this.color});

  @override bool shouldRepaint(CustomPainter oldDelegate) => this == oldDelegate;
  @override bool shouldRebuildSemantics(CustomPainter oldDelegate) => this == oldDelegate;

  @override
  void paint(Canvas canvas, Size size) {
    Path path = new Path();
    path.arcTo(Rect.fromCircle(center: new Offset(0.0, 0.0), radius: outerRadius), offset + start, end-start, true);
    path.relativeLineTo(-cos(offset + end)*(outerRadius-innerRadius), -sin(offset + end)*(outerRadius-innerRadius));
    path.arcTo(Rect.fromCircle(center: new Offset(0.0, 0.0), radius: innerRadius), offset + end, start-end, false);
    path.close();

    canvas.drawPath(path, new Paint()..color = color..style = PaintingStyle.fill);
  }
}

1 Ответ

0 голосов
/ 25 мая 2018

Я согласен, что вы должны поместить CustomPainter внутри виджета, который имеет размер.Это может быть SizedBox, поэтому я использовал это здесь.К счастью, вам не нужно проводить тест на попадание вручную, поскольку CustomPainter может справиться с этим с помощью небольшого рефакторинга.Первое, на что нужно обратить внимание, - это то, что путь не нужно реконструировать для каждой краски () - его можно встроить в конструктор.Это позволяет CustomPainter hitTest просто спрашивать, находится ли касание внутри или вне пути.

class _SegmentPainter extends CustomPainter {
  static const offset = -pi / 2;

  double start;
  double end;
  double innerRadius;
  double outerRadius;
  Color color;

  Path path;

  _SegmentPainter(
      this.start, this.end, this.innerRadius, this.outerRadius, this.color) {
    path = new Path()
      ..arcTo(
          Rect.fromCircle(center: new Offset(0.0, 0.0), radius: outerRadius),
          offset + start,
          end - start,
          true)
      ..relativeLineTo(-cos(offset + end) * (outerRadius - innerRadius),
          -sin(offset + end) * (outerRadius - innerRadius))
      ..arcTo(
          Rect.fromCircle(center: new Offset(0.0, 0.0), radius: innerRadius),
          offset + end,
          start - end,
          false)
      ..close();
  }

  @override
  bool shouldRepaint(_SegmentPainter oldDelegate) {
    return oldDelegate.start != start ||
        oldDelegate.end != end ||
        oldDelegate.innerRadius != innerRadius ||
        oldDelegate.outerRadius != outerRadius ||
        oldDelegate.color != color;
  }

  @override
  bool shouldRebuildSemantics(_SegmentPainter oldDelegate) => true;

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawPath(
        path,
        new Paint()
          ..color = color
          ..style = PaintingStyle.fill);
  }

  @override
  bool hitTest(Offset position) {
    return path.contains(position);
  }
}

class SegmentWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTap: () => print('tap'),
      child: new SizedBox(
        width: 250.0,
        height: 250.0,
        child: new CustomPaint(
          painter: new _SegmentPainter(0.0, 2.8, 150.0, 200.0, Colors.orange),
        ),
      ),
    );
  }
}

Я использовал синтаксис Dart .. (каскадный) для очистки пути.(Я думаю, что ваши should... тесты были отменены.) Я добавил StatelessWidget как дом для SizedBox и GestureDetector.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...