ookami-kb / storybook_flutter

A storybook for Flutter widgets.
https://pub.dev/packages/storybook_flutter
MIT License
288 stars 66 forks source link

TapUpDetais.globalPosition is incorrect #122

Open bramp opened 1 year ago

bramp commented 1 year ago

When running the Storybook with the device frame and panels down the size, the Tap Details globalPosition incorrectly includes the screen outside of the device frame.

For example:

GestureDetector(
  behavior: HitTestBehavior.opaque,
  onTapUp: (details) {
    print('onTapUp ${details.globalPosition}');
  },
  child: const Placeholder(),
)

If you click in the top left corner, you don't get 0,0, but instead ~600,10, because it includes the 600 pixels of panel to the left of the device frame.

This globalPosition should somehow be compensated for the area outside of the device being emulated.

bramp commented 1 year ago

Ok, I fixed this for myself by creating a widget that can map the offset. This does require a little bit more work, but it keeps my testing simple.

/// Insert TranslatePosition into the widget tree and call
/// TranslatePosition.translate(context, offset) to translate the global offset
/// to a offset from this widget.
class TranslatePosition extends StatelessWidget {
  final Widget child;

  const TranslatePosition({Key? key, required this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    GlobalKey key = GlobalKey();

    return Provider(
      key: key,
      create: (context) {
        final RenderBox box =
            key.currentContext!.findRenderObject() as RenderBox;

        // The top left corner of the TranslatePosition widget.
        return TranslatePositionOffset(box.localToGlobal(Offset.zero));
      },
      child: child,
    );
  }

  static translate(BuildContext context, Offset global) {
    try {
      return global - context.read<TranslatePositionOffset>();
    } on ProviderNullException {
      return global;
    }
  }
}

class TranslatePositionOffset extends Offset {
  TranslatePositionOffset(Offset offset) : super(offset.dx, offset.dy);
}
Storybook(
      wrapperBuilder: (context, child) {
        return TranslatePosition(
          child: child,
        );
      },
GestureDetector(
    behavior: HitTestBehavior.opaque,
    onTapUp: (details) {
        final position = TranslatePosition.translate(context, details.globalPosition);
        print('onTapUp $position');
    }
)

I also looked if there was a easy way to hook into Flutter to change this, but didn't find anything useful. BTW The reason I needed the "global" position, was to work with Overlays, which seem to assume the top-left of the app is 0,0, and there is no conveniant way to get the coordinates of where the Overlay is in global coordinates.