6
votes

Flutter GestureDetector: Comment pincer / dézoomer ou zoomer / dézoomer du texte avec deux doigts?

Je crée un champ de texte comme Texte ou RichText. Et après cela, je veux faire un zoom avant / arrière sur la taille du texte en utilisant le pincement. Pour l'instant, j'ai essayé d'implémenter GestureDetector mais il effectue également un zoom avant / arrière avec un doigt. Et il est vraiment difficile de viser la détection de pincement. Parfois gèle. J'ai ajouté une vidéo qui montre quand, après avoir pincé, elle se fige et s'agrandit soudainement. La deuxième vidéo est avec le cas que l'image ne fait un zoom avant que lorsque je tape sur le texte avec un doigt et que je me déplace vers le coin supérieur gauche. La mise en œuvre idéale est de détecter le pincement et de zoomer / dézoomer toute la zone de texte. Et désactivez le zoom lorsque j'utilise un seul doigt. Pourriez-vous m'envoyer des astuces, un lien ou un code pour résoudre ou où trouver la solution?

body: GestureDetector(
  onScaleUpdate: (details) {
    setState(() {
      _textSize =
          _initTextSize + (_initTextSize * (details.scale * .35));
    });
  },
  onScaleEnd: (ScaleEndDetails details) {
    setState(() {
      _initTextSize = _textSize;
    });
  },
  child: Center(
      child: SizedBox(
    height: _textSize,
    child: FittedBox(
      child: Text("Test"),
    ),
  ))),


2 commentaires

4 Réponses :


0
votes

Solution: zoom avant et arrière à deux doigts.

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

  class TransformText extends StatefulWidget {
    TransformText({Key key}) : super(key: key); // changed

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

  class _TransformTextState extends State<TransformText> {
    double scale = 0.0;

    @override
    Widget build(BuildContext context) {
      final ValueNotifier<Matrix4> notifier = ValueNotifier(Matrix4.identity());

      return Scaffold(
        appBar: AppBar(
          title: Text('Single finger Rotate text'), // changed
        ),
        body: Center(
          child: MatrixGestureDetector(
            onMatrixUpdate: (m, tm, sm, rm) {
              notifier.value = m;
            },
            child: AnimatedBuilder(
              animation: notifier,
              builder: (ctx, child) {
                return Transform(
                  transform: notifier.value,
                  child: Center(
                    child: Stack(
                      children: <Widget>[
                        Container(
                          color: Colors.red,
                          padding: EdgeInsets.all(10),
                          margin: EdgeInsets.only(top: 50),
                          child: Transform.scale(
                            scale:
                                1, // make this dynamic to change the scaling as in the basic demo
                            origin: Offset(0.0, 0.0),
                            child: Container(
                              height: 100,
                              child: Text(
                                "Two finger to zoom!!",
                                style:
                                    TextStyle(fontSize: 26, color: Colors.white),
                              ),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                );
              },
            ),
          ),
        ),
      );
    }
  }


0 commentaires

6
votes

Dans le widget Stateful avec ces configurations

GestureDetector(
  onScaleStart: (details) {
    _baseScaleFactor = _scaleFactor;
  },
  onScaleUpdate: (details) {
    setState(() {
      _scaleFactor = _baseScaleFactor * details.scale;
    });
  },
  child: Container(
    height: MediaQuery.of(context).size.height,
    width: MediaQuery.of(context).size.width,
    color: Colors.red,
    child: Center(
      child: Text(
        'Test',
        textScaleFactor: _scaleFactor,
      ),
    ),
  ),
);

Et n'utilisez setState que lors de la mise à jour, en utilisant le code scaleFactor > sur la propriété textScaleFactor de RichText.

Un seul setState pour reconstruire le widget et stocker le facteur initial lorsque la mise à l'échelle commence

double _scaleFactor = 1.0;
double _baseScaleFactor = 1.0;

La hauteur et la largeur que je mets juste pour agrandir et simuler la zone du détecteur de gestes.


0 commentaires

0
votes

Code complet. J'espère que cela aide.

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final appTitle = 'Demo';

    return MaterialApp(
      title: appTitle,
      home: MyHomePage(title: appTitle),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;

  MyHomePage({Key key, this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body: TransformText());
  }
}

class TransformText extends StatefulWidget {
  TransformText({Key key}) : super(key: key); // changed

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

class _TransformTextState extends State<TransformText> {
  double scale = 0.0;
  double _scaleFactor = 1.0;
  double _baseScaleFactor = 1.0;
  double _savedVal = 1.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('GestureDetector Test'), // changed
      ),
      body: Column(
        children: <Widget>[
          RaisedButton(
              child: Text('get'),
              onPressed: () {
                _savedVal = _scaleFactor;
              }),
          RaisedButton(
              child: Text('set'),
              onPressed: () {
                setState(() {
                  _scaleFactor = _savedVal;
                });
              }),
          Expanded(
            child: Center(
                child: GestureDetector(
              behavior: HitTestBehavior.translucent,
              onScaleStart: (details) {
                _baseScaleFactor = _scaleFactor;
              },
              onScaleUpdate: (details) {
                setState(() {
                  _scaleFactor = _baseScaleFactor * details.scale;
                });
              },
              child: Container(
                height: MediaQuery.of(context).size.height,
                width: MediaQuery.of(context).size.width,
                child: Center(
                  child: Text(
                    'Test',
                    textScaleFactor: _scaleFactor,
                  ),
                ),
              ),
            )),
          ),
        ],
      ),
    );
  }
}


0 commentaires

3
votes

Les ingénieurs logiciels de Google, Gary Qian et Chris Yang, l'ont démontré lors de leur conférence Google Developer Days. La vidéo est visible ici:

Le code est similaire à certaines des autres réponses ici, mais ils ajoutent notamment une pince pour qu'elle ne devienne ni trop grande ni trop petite.

Voici un résumé de leur bulle de texte évolutive:

 entrez la description de l'image ici

Comme la mise à l'échelle est toujours appelée même pour un seul doigt, j'ai ajouté une vérification pour scaleUpdateDetails.scale == 1.0 . Cela signifie que l'interface utilisateur ne sera pas mise à jour s'il n'y a pas de changement d'échelle.

class Bubble extends StatelessWidget {
  @override
  _BubbleState createState() => _BubbleState();
}

class _BubbleState extends State<Bubble> {
  double _fontSize = 20;
  final double _baseFontSize = 20;
  double _fontScale = 1;
  double _baseFontScale = 1;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onScaleStart: (ScaleStartDetails scaleStartDetails) {
        _baseFontScale = _fontScale;
      },
      onScaleUpdate: (ScaleUpdateDetails scaleUpdateDetails) {
        // don't update the UI if the scale didn't change
        if (scaleUpdateDetails.scale == 1.0) {
          return;
        }
        setState(() {
          _fontScale = (_baseFontScale * scaleUpdateDetails.scale).clamp(0.5, 5.0);
          _fontSize = _fontScale * _baseFontSize;
        });
      },
      child: ...
        // descendant with a Text widget that uses the _fontSize
    );
  }
}

Remarques:

  • Utilisez un StatelessWidget afin de pouvoir stocker à tout moment la taille et l'échelle de police actuelles
  • Utilisez deux variables supplémentaires pour vous souvenir de la taille de la police d'origine ainsi que de l'échelle au début du pincement
  • Enveloppez le widget Texte dans un GestureDetector
  • Enregistrez l'échelle d'origine dans onScaleStart
  • Calculez la nouvelle taille de police onScaleUpdate
  • Utilisez setState pour reconstruire le widget avec la nouvelle taille


0 commentaires