ResponsiveFramework icon indicating copy to clipboard operation
ResponsiveFramework copied to clipboard

draggable feedback location

Open wph144 opened this issue 5 years ago • 12 comments

hi, thanks for great package I am using ReorderableWrap of 'reorderables' package. I found feedback's location is wrong when using responsive_framework package. More generally, there are same problem when using Draggable widget. following is minimal reproducible application.

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

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

class MyApp extends StatelessWidget {
// This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, widget) {
        return ResponsiveWrapper.builder(
          BouncingScrollWrapper.builder(context, widget),
          maxWidth: 1200,
          minWidth: 350,
          debugLog: false,
          defaultScale: true,
          breakpoints: [
            ResponsiveBreakpoint.resize(350, name: MOBILE, scaleFactor: 0.8),
            ResponsiveBreakpoint.autoScale(800, name: TABLET, scaleFactor: 1.4),
            ResponsiveBreakpoint.autoScale(1000, name: TABLET, scaleFactor: 1.4),
            const ResponsiveBreakpoint.resize(1200, name: DESKTOP),
            const ResponsiveBreakpoint.autoScale(2460, name: "4K"),
          ],
          mediaQueryData: MediaQuery.of(context).copyWith(textScaleFactor: 1),
          background: Container(),
        );
      },
      home: DraggableExample(),
    );
  }
}

class DraggableExample extends StatefulWidget {
  @override
  DraggableExampleState createState() => DraggableExampleState();
}

class DraggableExampleState extends State<DraggableExample> with SingleTickerProviderStateMixin {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Spacer(),
          Row(
            children: [
              Spacer(),
              Draggable(
                feedback: Container(
                  width: 60,
                  height: 60,
                  color: Colors.red,
                ),
                child: Container(
                  width: 60,
                  height: 60,
                  color: Colors.red,
                ),
              ),
            ],
          ),
          SizedBox(height: MediaQuery.of(context).padding.bottom,),
        ],
      )
    );
  }
}

If item is on top-left, there are no or small difference, on right-bottom there are big difference. I intentionally put scale factor apart from 1.0

Can you help me?

wph144 avatar Aug 26 '20 01:08 wph144

Thanks for reporting this issue. I'm going to look into if it is possible to overwrite the root level MediaQuery parameters. Some framework widgets fetch their layout from the root screen metrics directly which means they are not getting the right metrics.

rayliverified avatar Sep 01 '20 03:09 rayliverified

Could you try using this build with the MediaQuery parameter? It was used to fix MediaQuery for entire app.

builder: (BuildContext context, Widget widget) =>
                DevicePreview.appBuilder(
              context,
              Builder(builder: (BuildContext context) {
                return MediaQuery(
                data: MediaQuery.of(context),
                child: ResponsiveWrapper.builder(MainView()),
                  maxWidth: 2460,
                  minWidth: 480,
                  defaultScale: true,
                  breakpoints: <ResponsiveBreakpoint>[
                    const ResponsiveBreakpoint.resize(480, name: MOBILE),
                    const ResponsiveBreakpoint.autoScale(600, name: TABLET),
                    const ResponsiveBreakpoint.autoScale(1000,
                        name: TABLET, scaleFactor: 1.2),
                    const ResponsiveBreakpoint.resize(1200, name: DESKTOP),
                    const ResponsiveBreakpoint.autoScale(2460, name: '4K'),
                  ],
                  background: Container(color: const Color(0xFFF5F5F5)),
                ),

gcostaapps avatar Sep 19 '20 14:09 gcostaapps

I tried below, but I still have same problem. It seems that I already used MediaData on MaterialApp level with 'mediaQueryData parameter of ResponsiveWrapper.builder method'. DevicePreview is just helper and not related to this issue, right? (i have compile error, so I cannot try right now, https://github.com/aloisdeniel/flutter_device_preview/issues/67)

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, widget) {
        return MediaQuery(
          data: MediaQuery.of(context),
          child: ResponsiveWrapper.builder(
            BouncingScrollWrapper.builder(context, widget),
            maxWidth: 1200,
            minWidth: 350,
            debugLog: false,
            defaultScale: true,
            breakpoints: [
              ResponsiveBreakpoint.resize(350, name: MOBILE, scaleFactor: 0.8),
              ResponsiveBreakpoint.autoScale(800, name: TABLET, scaleFactor: 1.4),
              ResponsiveBreakpoint.autoScale(1000, name: TABLET, scaleFactor: 1.4),
              const ResponsiveBreakpoint.resize(1200, name: DESKTOP),
              const ResponsiveBreakpoint.autoScale(2460, name: "4K"),
            ],
//            mediaQueryData: MediaQuery.of(context).copyWith(textScaleFactor: 1),
            background: Container(),
          ),
        );
      },
      home: DraggableExample(),
    );
  }
}

Thanks for reply :)

wph144 avatar Sep 19 '20 18:09 wph144

@searchy2 Might be related to this one, but I have issue with ReorderableListView. Should I open a new issue ? Depending on the location of the click, it throw the widget off.

bounty1342 avatar Sep 23 '20 14:09 bounty1342

It's most likely related to this issue.

The problem/solution is in passing a transformed composited tap target.

Not sure on the exact implementation but I can point you in the right direction if you are interested in taking a look.

rayliverified avatar Sep 23 '20 14:09 rayliverified

Found this :

https://medium.com/flutter/how-to-float-an-overlay-widget-over-a-possibly-transformed-ui-widget-1d15ca7667b6

So wrapping the parent widget with a CompositedTransformTarget to get reference to the cordinate sytem and then wrap the child with CompositedTransformFollower to follow it. This seems way to easy to actually work 😁

bounty1342 avatar Sep 24 '20 10:09 bounty1342

Same problem, very complicated to use draggable on tablet. When moving, the draggable is moved away from the cursor. I have the problem only on iOS, everything works on android. Do you have any news on the issue ? Thanks

cyrilOrderoo avatar Nov 30 '20 14:11 cyrilOrderoo

Hi @searchy2, Having issues with dragg and drop, but also with other package like flutter_intro. Do you have any update on a fix ?

bounty1342 avatar Dec 29 '20 20:12 bounty1342

any progress?

wph144 avatar Jan 22 '21 08:01 wph144

I resolved with workaround (simple but some boilerplate codes) If you use the widget that internally use OverlayEntry to make draggable feedback, Responsive framework package can generate coordination problem. e.g., ReorderableWrap, Draggable, LongPressDraggable, etc. That widget may have parameter onDragStarted, onDragEnded, feedback. (or other name)

Offset dragPosition = Offset.zero;   // member variable or variable in model
Widget feedback;                              // member variable or variable in model

Listener(
  onPointerDown: (details) {
    dragPosition = details.localPosition;
    setState(() {});                                           // or some other notify method
  },
  onPointerMove: (details) {
    dragPosition = details.localPosition;
    setState(() {});
  },
  child: Stack(
    children: [
      LongPressDraggable(
        feedback: const SizedBox(),
        onDragStarted() {
          // your another logic
          feedback = buildYourFeedbackWidget();
          setState(() {});
        },
        onDragEnd(_) {                  // or cancel? anyway when drag ended with any reason
          // your another logic
          feedback = null;
          setState(() {});
        },
        // some other your logics on LongPressDraggable
      ),
      Visibility(
        visible: feedback != null && dragPosition != null,
        child: Positioned(
          left: dragPosition.dx - 40,          // 40 can be changed to your amount
          top: dragPosition.dy - 40,
          child: IgnorePointer(
            child: Opacity(
              opacity: 0.7,
              child: feedback,
            ),
          ),
        ),
      )
    ]
  ),

wph144 avatar Jan 24 '21 16:01 wph144

no updates for this issue for over a year? I really like this plugin but I can't use it because my app is based on a form with a reorderable list..

infobkm avatar Mar 15 '22 14:03 infobkm

no updates for this issue for over a year? I really like this plugin but I can't use it because my app is based on a form with a reorderable list..

0.2.0 version released but issue still present.. :( no workaround?

gozluc84 avatar May 21 '22 22:05 gozluc84

Any updates on this? I was trying to find a workaround by disabling autoscaling for some widgets where I use ReorderableListView, but could not get it to work. Does anyone know how to do this? Just wrapping my widget with another ResponsiveWrapper did not work.

TimBaumgart avatar Jan 11 '23 12:01 TimBaumgart

I found a solution that is working for me. I am calculating a transform-matrix, which depends on the current pointer location, and apply it to the proxy decorator. Here is my Code:

class ReorderableList extends StatefulWidget {
  @override
  State<ReorderableList> createState() => _ReorderableListState();
}

class _ReorderableListState extends State<ReorderableList> {
  double pointerHeightScaleFactor = 0;

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerMove: (event) {
        pointerHeightScaleFactor =
            (event.position.dy / ResponsiveWrapper.of(context).screenHeight);
      },
      child: SliverReorderableList(
        proxyDecorator: (child, index, animation) {
          ResponsiveWrapperData data = ResponsiveWrapper.of(context);
          double widthOffset = data.scaledWidth - data.screenWidth;
          double heightOffset = data.scaledHeight - data.screenHeight;
          return Transform.translate(
            offset: Offset(
              widthOffset,
              heightOffset * pointerHeightScaleFactor,
            ),
            child: Material(
              child: child,
              elevation: 8,
            ),
          );
        },
      ),
    );
  }
}

This approach is not 100% correct, I think, but it fits my needs. It might break, if your draggable has a variable x-offset.

TimBaumgart avatar Jan 12 '23 08:01 TimBaumgart

@rayliverified Why this issue is being closed, even though it still unfixed?

@TimBaumgart is a workaround, not a fix. But still, it does not work with the current newest version of the package. scaledWidth and scaledHeight doesn't exist, for instance.

WillianSalceda avatar May 18 '23 17:05 WillianSalceda

It also seems to conflict with Draggable. Similar issue with that. It seems like the globalToLocal-calculation or something like that is not correct.

Eerey avatar Jan 29 '24 15:01 Eerey

Same issue here, when using LongPressDraggable inside ResponsiveScaledBox, the DraggableDetails.offset returned from onDragEnd are not in the correct scaled coordinate system. Whilst it might not be possible to override or alter this, a workaround or an additional method inside responsive_framework to convert would be handy.

egonbeermat avatar Feb 22 '24 17:02 egonbeermat

Facing same issue with ReorderableListView, when dragging, the item overflows and become bigger than original size. Quick dirty solution is to use internal padding as follows

ReorderableListView(
                  padding:
                      const EdgeInsets.symmetric(horizontal: 30, vertical: 20),

This puts some padding around the list view item so that on drag, it doesn't overflow screen width.

No solution yet?

elkSal avatar Mar 06 '24 22:03 elkSal