您好,GestureDetector、Pan 和 Scale 问题

Posted

技术标签:

【中文标题】您好,GestureDetector、Pan 和 Scale 问题【英文标题】:Hello, issue with GestureDetector, Pan and Scale issue 【发布时间】:2022-01-21 19:09:13 【问题描述】:

我有一个代码,允许我用手指在图像上移动文本,也可以用双指在文本上缩放文本,但是有两个问题,在谷歌上并没有太多,希望有人能提供帮助我,第一个问题是:

如果我取消注释注释的代码,我会收到此错误:

*在构建 HomePage(dirty, state: _HomePageState#8b5a9) 时抛出了以下断言: GestureDetector 参数不正确。 同时拥有平移手势识别器和缩放手势识别器是多余的; scale 是 pan 的超集。 只需使用比例手势识别器。 *

如果我只使用 scale,delta(details.delta.dx) 在 scale 中不可用,所以我得到一个错误。

另一个问题是: 当我在我的 TEXT 小部件中设置 textScaleFactor: _scaleFactor 时,文本消失了,我该如何解决这个问题?非常感谢各位。

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)),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  

【问题讨论】:

【参考方案1】:

您可以使用 matrix_gesture_detector 包中的 MatrixGestureDetector 来实现该功能。

简单的实现如下:

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,
    ),
  );

在你的情况下,

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,
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  

嗯,缩放手势是平移手势的超集,你可以得到它的offset delta as

scaleUpdateDetails.focalPointDelta

目前我不知道文本比例因子问题,但如果您使用Transform 小部件,这将无关紧要。

要了解有关 Transform 小部件的更多信息,我建议来自 Medium 的this article。

【讨论】:

非常感谢朋友,做得很好。 我的荣幸和好运!

以上是关于您好,GestureDetector、Pan 和 Scale 问题的主要内容,如果未能解决你的问题,请参考以下文章

Flutter GestureDetector 和 SmoothStarRaiting

Andorid------手势识别GestureDetector和SimpleOnGestureListener的使用教程(转)——

Flutter 堆叠 GestureDetector 和滑块问题

GestureDetector 完全解析

不要使用 GestureDetector 中的 setstate 方法更改我的容器颜色

GestureDetector 改变子部件的样式属性