The widget cannot be touched or changed the position of the widget on the purple mark when I change the rotation of the widget. and will be touched successfully when the rotation returns to 0 degrees or before change rotation.

enter image description here

working fine when not rotating

enter image description here

this is my code

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

class View_Test_Design extends StatefulWidget {
  @override
  _View_Test_DesignState createState() => _View_Test_DesignState();
}

class _View_Test_DesignState extends State<View_Test_Design> {
  double x = 100;
  double y = 100;

  double w = 200;
  double h = 50;

  double r=0; // Not Working fine when change to another number 

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Rotate|Pos|Drag"),
      ),
      body: Stack(
        children: <Widget>[
          Positioned(
              left: x,
              top: y,
              child: GestureDetector(
                  onPanUpdate: (details) {
                    setState(() {
                      x = x + details.delta.dx;
                      y = y + details.delta.dy;
                    });
                  },
                  child: Transform.rotate(
                      angle: math.pi * r / 180,
                      child:
                          Container(width: w, height: h, color: Colors.red))))
        ],
      ),
    );
  }
} 

any solution why this is not working?


Solution 1: Amir

This is because the Transform widget translates a widget outside the bounds of a parent widget. So you need to make the parent widget bigger.

@override
Widget build(BuildContext context) {
 return Scaffold(
  appBar: AppBar(
    title: Text("Rotate|Pos|Drag"),
  ),
  body: Stack(
    overflow: Overflow.visible,
    children: <Widget>[
      Positioned(
          left: x,
          top: y,
          width: MediaQuery.of(context).size.width,
          height: MediaQuery.of(context).size.height,
          child: GestureDetector(
              onPanUpdate: (details) {
                setState(() {
                  x = x + details.delta.dx;
                  y = y + details.delta.dy;
                });
              },
              child: Transform.rotate(
                  angle: math.pi * r / 180,
                  child:
                      Container(width: w, height: h, color: Colors.red))))
     ],
   ),
 );
}

Answer is from here https://github.com/flutter/flutter/issues/27587


Solution 2: Dabbel

Had a similar problem, this is my solution.

https://stackoverflow.com/a/74165192/12098106

import 'package:flutter/material.dart';

// -------------------------------------------------------------------
// THE ITEM TO BE DRAWN
// -------------------------------------------------------------------

class DrawContainer {
  Color color;
  Offset offset;
  double width;
  double height;
  double scale;
  double angle;
  late double _baseScaleFactor;
  late double _baseAngleFactor;

  DrawContainer(this.color, this.offset, this.width, this.height, this.scale,
      this.angle) {
    onScaleStart();
  }

  onScaleStart() {
    _baseScaleFactor = scale;
    _baseAngleFactor = angle;
  }

  onScaleUpdate(double scaleNew) =>
      scale = (_baseScaleFactor * scaleNew).clamp(0.5, 5);

  onRotateUpdate(double angleNew) => angle = _baseAngleFactor + angleNew;
}

// -------------------------------------------------------------------
// APP
// -------------------------------------------------------------------

void main() {
  runApp(const MaterialApp(home: GestureTest()));
}

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

  @override
  // ignore: library_private_types_in_public_api
  _GestureTestState createState() => _GestureTestState();
}

// -------------------------------------------------------------------
// APP STATE
// -------------------------------------------------------------------

class _GestureTestState extends State<GestureTest> {
  final List<DrawContainer> containers = [
    DrawContainer(Colors.red, const Offset(50, 50), 100, 100, 1.0, 0.0),
    DrawContainer(Colors.yellow, const Offset(100, 100), 200, 100, 1.0, 0.0),
    DrawContainer(Colors.green, const Offset(150, 150), 50, 100, 1.0, 0.0),
  ];

  void onGestureStart(DrawContainer e) => e.onScaleStart();

  onGestureUpdate(DrawContainer e, ScaleUpdateDetails d) {
    e.offset = e.offset + d.focalPointDelta;
    if (d.rotation != 0.0) e.onRotateUpdate(d.rotation);
    if (d.scale != 1.0) e.onScaleUpdate(d.scale);
    setState(() {}); // redraw
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
        child: Scaffold(
      body: SizedBox(
        height: double.infinity,
        width: double.infinity,
        child: Stack(
          children: [
            ...containers.map((e) {
              return GestureDetector(
                  onScaleStart: (details) {
                    // detect two fingers to reset internal factors
                    if (details.pointerCount == 2) {
                      onGestureStart(e);
                    }
                  },
                  onScaleUpdate: (details) => onGestureUpdate(e, details),
                  child: DrawWidget(e));
            }).toList(),
          ],
        ),
      ),
    ));
  }
}

// -------------------------------------------------------------------
// POSITION, ROTATE AND SCALE THE WIDGET
// -------------------------------------------------------------------

class DrawWidget extends StatelessWidget {
  final DrawContainer e;
  const DrawWidget(this.e, {Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned(
          left: e.offset.dx,
          top: e.offset.dy,
          child: Transform.rotate(
            angle: e.angle,
            child: Transform.scale(
              scale: e.scale,
              child: Container(
                height: e.width,
                width: e.height,
                color: e.color,
              ),
            ),
          ),
        ),
      ],
    );
  }
}


Solution 3: Taimoor Ghafar

Use DeferredPointer widget to detect gestures outside the bounds of a parent.