【问题标题】:Flutter cursor wheel widget auto positioning with animation颤动光标轮小部件自动定位动画
【发布时间】:2020-06-30 17:28:35
【问题描述】:

我有一个用于光标滚轮小部件的颤振代码。

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: RotateText(),
    );
  }
}

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

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

class _RotateTextState extends State < RotateText > {
  double finalAngle = 0.0;
  double offsetAngle = 0.0;

  @override
  Widget build(BuildContext context) {
    return _defaultApp(context);
  }

  _defaultApp(BuildContext context) {
    var radius = 300.0;
    var left = MediaQuery.of(context).size.width / 2 - radius;
    var size = 1.6 * radius;
    var place = 60;
    var item = 100.0;
    var distance = 180;
    
    return Scaffold(
      appBar: AppBar(
        title: Text('Single finger Rotate text'), // changed
      ),
      body: new Stack(
        children: <Widget>[
          Positioned(
            left: left,
            bottom: place - radius,
            child: Container(
              width: 2 * radius,
              height: 2 * radius,
              decoration: new BoxDecoration(
                shape: BoxShape.circle,
                color: Colors.grey,
              ),
              child: LayoutBuilder(
                builder: (context, constraints) {
                  return GestureDetector(
                    behavior: HitTestBehavior.translucent,
                    onPanStart: (details) {
                      Offset centerOfGestureDetector = Offset(constraints.maxWidth / 2, constraints.maxHeight / 2);
                      final touchPositionFromCenter = details.localPosition - centerOfGestureDetector;
                      offsetAngle = touchPositionFromCenter.direction - finalAngle;
                    },
                    onPanUpdate: (details) {
                      Offset centerOfGestureDetector = Offset(constraints.maxWidth / 2, constraints.maxHeight / 2);
                      final touchPositionFromCenter = details.localPosition - centerOfGestureDetector;
                      setState(() {
                        finalAngle = touchPositionFromCenter.direction - offsetAngle;
                      });
                    },
                    child: Transform.rotate(
                      angle: finalAngle,
                      child: Icon(
                        Icons.settings,
                        color: Colors.white,
                        size: size,
                      ),
                    ),
                  );
                },
              ),
            )
          ),
          Positioned(
            left: left + radius / 2 + item + distance * cos(finalAngle - pi / 2),
            bottom: place - item / 2 - distance * sin(finalAngle - pi / 2),
            child: Container(
              height: item,
              width: item,
              child: Image.network(
                'https://picsum.photos/250?image=9',
              ),
            )
          ),
        ]
      )
    );
  }
}

它可以正常工作并通过拖动旋转,但我不会停留在一个带有动画的菜单项上并自动校准。

当它在径向区域范围内时,如何使其旋转(使用 finalAngle 浮点数)以重新定位在项目的中心?

谢谢。

【问题讨论】:

    标签: flutter


    【解决方案1】:

    您应该使用AnimationController 为项目的位置设置动画,并且您必须在 onPanEnd 方法中设置菜单项的正确位置, 我彻底检查了您的代码,最后将其修复如下:

    import 'dart:math';
    
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: RotateText(),
        );
      }
    }
    
    class RotateText extends StatefulWidget {
      RotateText({Key key}) : super(key: key); // changed
    
      @override
      _RotateTextState createState() => _RotateTextState();
    }
    
    class _RotateTextState extends State<RotateText>
        with SingleTickerProviderStateMixin {
      double finalAngle = 0.0;
      double offsetAngle = 0.0;
    
      Tween<double> _tween;
      Animation<double> _animation;
      AnimationController _animationController;
    
      @override
      void initState() {
        super.initState();
        _animationController =
            AnimationController(duration: Duration(milliseconds: 700), vsync: this);
        _tween = Tween(begin: 0.0, end: finalAngle);
        _animation = _tween.animate(CurvedAnimation(
            parent: _animationController, curve: Curves.easeOut))
          ..addListener(() {
            setState(() {});
          });
      }
    
      void updateFinalAngle(double angle, [bool withDuration = false]) {
        _tween.begin = _tween.end;
        _animationController.reset();
        _tween.end = angle;
        _animationController.forward();
      }
    
      @override
      Widget build(BuildContext context) {
        return _defaultApp(context);
      }
    
      _defaultApp(BuildContext context) {
        var radius = 300.0;
        var left = MediaQuery.of(context).size.width / 2 - radius;
        var size = 1.6 * radius;
        var place = 60;
        var item = 100.0;
        var distance = 180;
    
        return Scaffold(
            appBar: AppBar(
              title: Text('Single finger Rotate text'), // changed
            ),
            body: Stack(children: <Widget>[
              Positioned(
                  left: left,
                  bottom: place - radius,
                  child: Container(
                    width: 2 * radius,
                    height: 2 * radius,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      color: Colors.grey,
                    ),
                    child: LayoutBuilder(
                      builder: (context, constraints) {
                        return GestureDetector(
                          behavior: HitTestBehavior.translucent,
                          onPanStart: (details) {
                            Offset centerOfGestureDetector = Offset(
                                constraints.maxWidth / 2,
                                constraints.maxHeight / 2);
                            final touchPositionFromCenter =
                                details.localPosition - centerOfGestureDetector;
                            offsetAngle =
                                touchPositionFromCenter.direction - finalAngle;
                          },
                          onPanUpdate: (details) {
                            Offset centerOfGestureDetector = Offset(
                                constraints.maxWidth / 2,
                                constraints.maxHeight / 2);
                            final touchPositionFromCenter =
                                details.localPosition - centerOfGestureDetector;
                            setState(() {
                              finalAngle =
                                  touchPositionFromCenter.direction - offsetAngle;
                              updateFinalAngle(finalAngle);
                            });
                          },
                          onPanEnd: (detail) {
                            double fixedAngle = _calcFinalAngle(finalAngle);
                            finalAngle = fixedAngle;
                            updateFinalAngle(finalAngle, true);
                          },
                          child: Transform.rotate(
                            angle: _animation.value,
                            child: Icon(
                              Icons.settings,
                              color: Colors.white,
                              size: size,
                            ),
                          ),
                        );
                      },
                    ),
                  )),
              Positioned(
                  left: left +
                      radius / 2 +
                      item +
                      distance * cos(_animation.value - pi / 2),
                  bottom:
                      place - item / 2 - distance * sin(_animation.value - pi / 2),
                  child: Container(
                    height: item,
                    width: item,
                    child: Image.network(
                      'https://picsum.photos/250?image=9',
                    ),
                  )),
            ]));
      }
    
      double _calcFinalAngle(double radianAngle) {
        int degreeAngle =
            double.parse((radianAngle * (180 / pi)).toStringAsFixed(2)).round();
    
        int criticalAngle = 60;
        int criticalOffset = 30;
        bool isNegative = false;
        if (degreeAngle < 0) isNegative = true;
        degreeAngle = degreeAngle.abs();
        int rem60 = degreeAngle % criticalAngle;
    
        if (rem60 >= criticalOffset) {
          degreeAngle += (60 - rem60);
        } else {
          degreeAngle -= rem60;
        }
    
        double resultAngleInRad = degreeAngle * (pi / 180);
    
        return isNegative ? -resultAngleInRad : resultAngleInRad;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-03
      • 1970-01-01
      • 1970-01-01
      • 2019-07-30
      • 2020-07-23
      • 1970-01-01
      • 1970-01-01
      • 2018-02-01
      相关资源
      最近更新 更多