Rotating image based on drag handle in flutter

805

I made a few modifications to the code, notably

  1. Treating the "real" centerOfGestureDetector as the center of all the items you would like to rotate
  2. Determining and tracking the change in angle with the onPanStart,onPanEnd and onPanUpdate methods
import 'package:flutter/material.dart';

double ballRadius = 7.5;

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  double _angle = 0.0;
  double _oldAngle = 0.0;
  double _angleDelta = 0.0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: SafeArea(
          child: Stack(
            children: [
              Positioned(
                top: 100,
                left: 100,
                child: Transform.rotate(
                  angle: _angle,
                  child: Column(
                    children: [
                      Container(
                        width: 30,
                        height: 30,
                        decoration: BoxDecoration(
                          color: Colors.black,
                          borderRadius: BorderRadius.circular(30),
                        ),
                        child: LayoutBuilder(
                          builder: (context, constraints) {
                            //   Offset centerOfGestureDetector = Offset(
                            // constraints.maxWidth / 2, constraints.maxHeight / 2);
                            /**
                           * using center of positioned element instead to better fit the
                           * mental map of the user rotating object.
                           * (height = container height (30) + container height (30) + container height (200)) / 2
                           */
                            Offset centerOfGestureDetector =
                                Offset(constraints.maxWidth / 2, 130);
                            return GestureDetector(
                              behavior: HitTestBehavior.translucent,
                              onPanStart: (details) {
                                final touchPositionFromCenter =
                                    details.localPosition -
                                        centerOfGestureDetector;
                                _angleDelta = _oldAngle -
                                    touchPositionFromCenter.direction;
                              },
                              onPanEnd: (details) {
                                setState(
                                  () {
                                    _oldAngle = _angle;
                                  },
                                );
                              },
                              onPanUpdate: (details) {
                                final touchPositionFromCenter =
                                    details.localPosition -
                                        centerOfGestureDetector;

                                setState(
                                  () {
                                    _angle = touchPositionFromCenter.direction +
                                        _angleDelta;
                                  },
                                );
                              },
                            );
                          },
                        ),
                      ),
                      Container(
                        height: 30,
                        width: 5,
                        color: Colors.black,
                      ),
                      Container(
                        height: 200,
                        width: 200,
                        color: Colors.red,
                      ),
                    ],
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

Share:
805
Axel
Author by

Axel

Updated on December 24, 2022

Comments

  • Axel
    Axel over 1 year

    My end goal is to achieve somethinng like this:

    enter image description here

    As you can see there's the drag handle is required to rotate this image.

    I have a following code:

    import 'package:flutter/material.dart';
    
    double ballRadius = 7.5;
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      double _angle = 0.0;
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          home: Scaffold(
            body: SafeArea(
              child: Stack(
                children: [
                  Positioned(
                    top: 100,
                    left: 100,
                    child: Transform.rotate(
                      angle: _angle,
                      child: Column(
                        children: [
                          Container(
                            width: 30,
                            height: 30,
                            decoration: BoxDecoration(
                              color: Colors.black,
                              borderRadius: BorderRadius.circular(30),
                            ),
                            child: LayoutBuilder(
                              builder: (context, constraints) {
                                return GestureDetector(
                                  behavior: HitTestBehavior.translucent,
                                  onPanUpdate: (DragUpdateDetails details) {
                                    Offset centerOfGestureDetector = Offset(
                                      constraints.maxWidth / 2,
                                      constraints.maxHeight / 2,
                                    );
                                    final touchPositionFromCenter =
                                        details.localPosition -
                                            centerOfGestureDetector;
                                    print(touchPositionFromCenter.direction);
                                    setState(() {
                                      _angle = touchPositionFromCenter.direction;
                                    });
                                  },
                                );
                              },
                            ),
                          ),
                          Container(
                            height: 30,
                            width: 5,
                            color: Colors.black,
                          ),
                          Container(
                            height: 200,
                            width: 200,
                            color: Colors.red,
                          ),
                        ],
                      ),
                    ),
                  )
                ],
              ),
            ),
          ),
        );
      }
    }
    
    

    It is working. But sometimes it's too fast or too slow. Please help me fix this issue.