Flutter: программирование приложения рисования с масштабированием (GestureDetector onScaleUpdate, расчет смещения после масштабирования) - PullRequest
0 голосов
/ 15 марта 2020

В настоящее время я пытаюсь запрограммировать что-то, что вы можете назвать «приложением рисования», используя Flutter. Цель состоит в том, чтобы использовать виджет CustomePainter и пути, чтобы рисовать на изображение. Я понял эту часть, и она работает достаточно хорошо, если я не масштабирую изображение. Но я также хочу сделать его масштабируемым, чтобы приблизиться к изображению, чтобы рисовать более подробно. Я использую Paths, потому что я хочу сделать возможным нажатие внутри Path и получение ответа (используя 'Path.contains').

Проблема, когда я использую масштабирование, состоит в том, что если масштаб меньше, краска доставляется в верхнем левом углу там, где я касаюсь, и когда масштаб больше, она доставляется в нижнем правом углу там, где я касаюсь. В этом моя проблема только в том, что я просчитал смещения. Но я не мог найти лучшую формулу. Также у меня проблема с движением / трансформацией после масштабирования. Если масштабированный объект движется медленнее или быстрее, чем фактическое движение пальца. Мне удалось найти решение (пытаясь понять формулу), которое перемещает объект с правильной скоростью, но начальная позиция - либо внизу справа, либо вверху слева, в зависимости от масштаба.

Я думаю все, что мне нужно, это правильная формула для смещения, которое учитывает масштабирование.

Кроме того, я заметил, что детектор жестов не обнаруживает ничего за пределами начальной области, поэтому, если я уменьшу изображение, нажмите на изображение обнаруживается, но жесты вне изображения игнорируются. Есть ли способ обнаружить все жесты на экране?

Я довольно плохо знаком с Флаттером и программированием в целом, поэтому я мог бы задавать действительно глупые вопросы, но я, к сожалению, не мог найти ответы на эти вопросы. эти проблемы.

В приведенный ниже код я включил оба альтернативных кода, которые я использовал для получения смещения. Оба имеют свои привилегии, и я хотел бы получить начальное позиционирование из одной альтернативы кода и правильное вычисление движения из другой ...

О коде: вы нажимаете значок «жест» в приложении панель для переключения между перемещением содержимого и рисованием содержимого, используйте масштабирование для увеличения и уменьшения масштаба и значок «tra sh» для отмены чертежа

// edit: объяснение кода, добавление сетевого изображения и изменить один значок // edit1: изменить заголовок

import 'dart:ui';

import 'package:flutter/material.dart';

class GesturePaint extends StatefulWidget {
  @override
  _GesturePaintState createState() => _GesturePaintState();
}

class _GesturePaintState extends State<GesturePaint> {
  List<Offset> points = List();

  Offset _startLastOffset = Offset.zero;
  Offset _lastOffset = Offset.zero;
  Offset _currentOffset = Offset.zero;
  double _lastScale = 1.0;
  double _currentScale = 1.0;
  bool _drawable = true;

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('painting app'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.gesture),
            onPressed: (){
              setState(() {
                _drawable = _drawable ? false : true;
              });
              print(_drawable);
            },
          ),
          IconButton(
            icon: Icon(Icons.delete),
            onPressed: (){
              setState(() {
                points.clear();
              });
            },
          ),
        ],
      ),
      body: _buildBody(context),
    );
  }

  Widget _buildBody(BuildContext context){
    return GestureDetector(
      child: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          _transformMatrix4Image(),
          //_transformScaleAndTranslate(),
          _transformMatrix4(),
        ],
      ),
      onScaleStart: _onScaleStart,
      onScaleUpdate: _onScaleUpdate,

    );
  }

  void _onScaleStart(ScaleStartDetails details) {
    print('ScaleStartDetails: $details');

    if(_drawable){
      setState(() {
        points.add((details.localFocalPoint/_currentScale).translate(-_currentOffset.dx,-_currentOffset.dy));
      });
    } else{
      _lastScale = _currentScale;
      _lastOffset = _currentOffset;
      _startLastOffset = details.focalPoint;
    }

  }



  void _onScaleUpdate(ScaleUpdateDetails details) {
    print('ScaleUpdateDetails: $details - Scale: ${details.scale}');

    if (details.scale != 1){
      double currentScale = _lastScale * details.scale;

      setState(() {
        _currentScale = currentScale;
      });

      print('_scale: $_currentScale - _lastScale: $_lastScale');

    } else if(details.scale == 1.0 ) {
      // Calculate offset depending on current Image scaling.
      if(_drawable){
        //draw instead
        setState(() {
          // this does generally not work, i also tried to use FocalPoint, which doesn't work either,
          // and i tried to use (details.localFocalPoint).tranlate, which also didn't work well
          //the following is the closest i come to the initial movement, but the offset is off depending on the scale
          points.add((details.localFocalPoint/_lastScale).translate(-_currentOffset.dx,-_currentOffset.dy));
        });
      } else{
          Offset offsetAdjustedForScale = (_startLastOffset -_lastOffset )/ _lastScale;
          //initial offset correct, but moves at different speeds than finger movement with following code:
          //Offset currentOffset = details.focalPoint - offsetAdjustedForScale*_lastScale;
          //initial offset wrong, but moves with correct speed
          Offset currentOffset = details.focalPoint/_lastScale - offsetAdjustedForScale*_lastScale;

          setState(() {
            _currentOffset = currentOffset;
          });
      }
    }

  }


  Transform _transformMatrix4(){
    Matrix4 _mat = Matrix4.identity()
      ..scale(_currentScale,_currentScale)
      ..translate(_currentOffset.dx,_currentOffset.dy);
    return Transform(
        transform: _mat,
        alignment: FractionalOffset.center,
        child:  PathExample(pointsList: points),
    );
  }

  Transform _transformMatrix4Image(){
    Matrix4 _mat = Matrix4.identity()
      ..scale(_currentScale,_currentScale)
      ..translate(_currentOffset.dx,_currentOffset.dy);
    return Transform(
      transform: _mat,
      alignment: FractionalOffset.center,
      child: Image(
        image: NetworkImage('https://png2.kisspng.com/sh/dde5d7f3f60acef81f7e019f4f65cafb/L0KzQYm3VcA1N6Vxj5H0aYP2gLBuTfJtfZYygtNELX3yhbB7gflvNZNxjddraYLnPcjwjvcuPZJqe9ZqZkS5QIi6VcAvPmIAUKoEOEm0RYO8VMcyQWk9S6sAMT7zfri=/kisspng-blue-jay-mountain-bluebird-wing-5aecdaf4607350.6198898915254719883951.png'),
        fit: BoxFit.cover,
      ),
    );
  }


}







class PathExample extends StatelessWidget {
  PathExample({this.pointsList});
  List<Offset> pointsList;

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: PathPainter(pointsList: pointsList),
    );
  }
}

class PathPainter extends CustomPainter {
  PathPainter({this.pointsList});
  List<Offset> pointsList;

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.stroke
      ..strokeWidth = 8;

    for (int i = 0; i < pointsList.length - 1; i++) {

      Path path = Path();
      if(pointsList[i] != null) path.moveTo(pointsList[i].dx, pointsList[i].dy);

      for(int j = i; j < pointsList.length - 1;   j++ ){
        if (pointsList[j] != null ) {
          path.lineTo(pointsList[j].dx, pointsList[j].dy);
        } if(pointsList[j] == null){
        }

        i = j;
      }
      canvas.drawPath(path, paint);
    }

  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...