Home > Enterprise >  Hello, issue with GestureDetector, Pan and Scale issue
Hello, issue with GestureDetector, Pan and Scale issue

Time:12-21

I've a code that allows me to move text with a finger over an image, and also scale the text using both fingers over the text, but there are two problems and not much about it at google, hope someone can help me, first problem is:

If I uncomment the commented code, I get this error:

*The following assertion was thrown building HomePage(dirty, state: _HomePageState#8b5a9): Incorrect GestureDetector arguments. Having both a pan gesture recognizer and a scale gesture recognizer is redundant; scale is a superset of pan. Just use the scale gesture recognizer. *

If I only use scale, delta(details.delta.dx) is not available in scale, so I get an error.

And the other issue is: When I set textScaleFactor: _scaleFactor, inside my TEXT widget, the text desappears , how can I fix this ? Thanks a lot guys.

import 'package:flutter/material.dart';

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

class TextOverImage extends StatelessWidget {
  const TextOverImage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // Size size = MediaQuery.of(context).size;
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: const Text('Text Over Image Image Example'),
        ),
        body: Center(
          child: Container(
            height: 300,
            width: 300,
            child: Stack(
              children: <Widget>[
                Container(
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(5),
                      color: Colors.blue,
                      image: const DecorationImage(
                          image: NetworkImage(
                              "https://thumbs.dreamstime.com/b/funny-face-baby-27701492.jpg"),
                          fit: BoxFit.fill)),
                ),
                const HomePage()
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

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

class _HomePageState extends State<HomePage> {
  Offset offset = Offset.zero;
  Offset offset2 = Offset.zero;

  double scale = 0.0;
  double _scaleFactor = 1.0;
  double _baseScaleFactor = 1.0;
  double _savedVal = 1.0;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned(
          left: offset.dx,
          top: offset.dy,
          child: Row(
            children: [
              GestureDetector(
                onPanUpdate: (details) {
                  setState(() {
                    offset = Offset(offset.dx   details.delta.dx,
                        offset.dy   details.delta.dy);
                  });
                },

                // behavior: HitTestBehavior.translucent,
                //
                // onScaleStart: (details) {
                //   _baseScaleFactor = _scaleFactor;
                //
                // },
                //
                // onScaleUpdate: (details) {
                //   setState(() {
                //     _scaleFactor = _baseScaleFactor * details.scale;
                //   });
                // },

                child:  SizedBox(
                  width: 300,
                  height: 300,
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Center(

                      child: Text("You Think You Are Funny But You Are Not",

                          // here if I remove _scaleFactor the text is GONE
                          textScaleFactor: _scaleFactor,
                          textAlign: TextAlign.center,
                          style: const TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 18.0,
                              color: Colors.red)),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
        Positioned(
          left: offset2.dx,
          top: offset2.dy,
          child: Row(
            children: [
              GestureDetector(
                onPanUpdate: (details) {
                  setState(() {
                    offset2 = Offset(offset2.dx   details.delta.dx,
                        offset2.dy   details.delta.dy);
                  });
                },
                child: const SizedBox(
                  width: 300,
                  height: 300,
                  child: Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Center(
                      child: Text("xx xxxx x xx   x x xxxxxx",
                          textAlign: TextAlign.center,
                          style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 18.0,
                              color: Colors.red)),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

CodePudding user response:

You can achieve the functionality using MatrixGestureDetector from matrix_gesture_detector package.

Straightforward implementation will be as follows:

class FloatingWidget extends StatefulWidget  {

  final Widget child;

  const FloatingWidget({Key? key, required this.child}) : super(key: key);

  @override
  State<FloatingWidget> createState() => _FloatingWidgetState();
}

class _FloatingWidgetState extends State<FloatingWidget> {

  Matrix4 _transform = Matrix4.identity();

  @override
  Widget build(BuildContext context) => Transform(
    transform: _transform,
    child: MatrixGestureDetector(
      onMatrixUpdate: (matrix, translationDeltaMatrix, scaleDeltaMatrix, rotationDeltaMatrix)  {
        setState(() {
          _transform = matrix;
        });
      },
      child: widget.child,
    ),
  );
}

In your case,

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

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

class TextOverImage extends StatelessWidget {
  const TextOverImage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // Size size = MediaQuery.of(context).size;
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: const Text('Text Over Image Image Example'),
        ),
        body: Center(
          child: SizedBox.fromSize(
            size: const Size(300, 300),
            child: Stack(
              children: <Widget>[
                Container(
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(5),
                      color: Colors.blue,
                      image: const DecorationImage(
                          image: NetworkImage(
                              "https://thumbs.dreamstime.com/b/funny-face-baby-27701492.jpg"),
                          fit: BoxFit.fill)),
                ),
                const HomePage()
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

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

class _HomePageState extends State<HomePage> {

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        FloatingWidget(
          child: Row(
            children: [
              SizedBox.fromSize(
                size: const Size(300, 300),
                child: const Padding(
                  padding: EdgeInsets.all(8.0),
                  child: Center(
                    child: Text("You Think You Are Funny But You Are Not",
                    textAlign: TextAlign.center,
                    style: TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 18.0,
                        color: Colors.red,
                      )
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
        FloatingWidget(
          child: Row(
            children: [
              SizedBox.fromSize(
                size: const Size(300, 300),
                child: const Padding(
                  padding: EdgeInsets.all(8.0),
                  child: Center(
                    child: Text("xx xxxx x xx   x x xxxxxx",
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 18.0,
                        color: Colors.red,
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

Well, scale gesture is a superset of pan gesture and you can get its offset delta as

scaleUpdateDetails.focalPointDelta

I have no idea about the text scale factor problem at this point but it will be irrelevant if you are using Transform widget.

To learn more about Transform widget, I suggest this article from Medium.

  • Related