Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Offsets are different onTap and OnDrag - Flutter

I have an image in which certain items are there which have starting offsets and their height and width, corresponding to each item in images I have different text, I have to drag the text and drop it to the correct position on the image,I am getting different offset while tap to particular location and while drag also I am getting different offsets. How can I get the same offsets?

Here is my code and image I am using. these are the details of Tree

x=673
y=635
h=214
w=149

with respect to image. enter image description here

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  ImageInfo _imageInfo;
  AssetImage assestImage;
  double dx;
  double dy;
  Offset dragOffset;
  @override
  void initState() {
    super.initState();
    assestImage = AssetImage('assets/hospital.jpg');
    WidgetsBinding.instance.addPostFrameCallback((a) => _getImageInfo());
  }

  void _getImageInfo() async {
    Image image = new Image.asset('assets/hospital.jpg');
    image.image
        .resolve(new ImageConfiguration())
        .addListener((ImageInfo info, bool _) {
      _imageInfo = info;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            DragTarget(
                onAccept: (Offset dragOffset) {},
                builder: (
                  BuildContext context,
                  List<dynamic> accepted,
                  List<dynamic> rejected,
                ) {
                  return TapImage(
                    onTap: (Offset offset) {
                      print('Offset on Tapping the image is $offset');
                      dx = offset.dx * _imageInfo.image.width;
                      dy = offset.dy * _imageInfo.image.height;
                      if (_imageInfo != null) {
                        print('Image clicked: ${dx.toInt()} x ${dy.toInt()}');
                        if ((673 <= dx && dx <= 822) &&
                            (635 <= dy && dy <= 849)) {
                          print('you drop in tree');
                        } else {}
                      }
                    },
                    image: assestImage,
                  );
                }),
            Draggable(
                dragAnchor: DragAnchor.pointer,
                onDragEnd: (details) {
                  setState(() {
                    dragOffset = details.offset;
                  });
                  print('dragoffset in onDrag Method is  $dragOffset');
                },
                data: dragOffset,
                child: Container(
                    color: Colors.green,
                    child: Text(
                      'Tree',
                      style: TextStyle(fontSize: 30.0),
                    )),
                feedback: Container(
                  height: 10.0,
                  child: Text(
                    'Tree',
                    style: TextStyle(fontSize: 15.0),
                  ),
                )),
          ],
        ),
      ),
    );
  }
}

typedef void OnTapLocation(Offset offset);

class TapImage extends StatelessWidget {
  TapImage({Key key, this.onTap, this.image}) : super(key: key);

  final OnTapLocation onTap;
  final ImageProvider image;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (TapDownDetails details) => _onTap(details, context),
      onLongPress: () {},
      child: Image(image: AssetImage('assets/hospital.jpg')),
    );
  }

  void _onTap(TapDownDetails details, BuildContext context) {
    RenderBox getBox = context.findRenderObject();
    Offset local = getBox.globalToLocal(details.globalPosition);
    print('locla ois $local');
    onTap(Offset(local.dx / getBox.size.width, local.dy / getBox.size.height));
  }
}
like image 892
Rishabh Avatar asked Mar 06 '19 08:03

Rishabh


2 Answers

its working for me

class _HomeState extends State<Home> {
  ImageInfo _imageInfo;
  AssetImage assestImage;
  double getheight;
  double getywidth;

  Offset dragOffset;
  @override
  void initState() {
    super.initState();
    assestImage = AssetImage('assets/hospital.jpg');
    WidgetsBinding.instance.addPostFrameCallback((a) => _getImageInfo());
  }

  void _getImageInfo() async {
    Image image = new Image.asset('assets/hospital.jpg');
    image.image
        .resolve(new ImageConfiguration())
        .addListener((ImageInfo info, bool _) {
      _imageInfo = info;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          child: Column(
        children: <Widget>[
          TapImage(
            onTap: (Offset offset, RenderBox getBox, TapDownDetails details) {
              double dx;
              double dy;
              dx = offset.dx * _imageInfo.image.width;
              dy = offset.dy * _imageInfo.image.height;
              setState(() {
                dragEnd(dx, dy);
              });
            },
            image: assestImage,
          ),
          Draggable(
              dragAnchor: DragAnchor.pointer,
              onDragStarted: () {
                WidgetsBinding.instance
                    .addPostFrameCallback((_) => setState(() {
                          RenderBox getBox = context.findRenderObject();
                          getheight = getBox.size.height;
                          getywidth = getBox.size.width;
                        }));
              },
              onDragEnd: (details) {
                double dx;
                double dy;
                dx = (details.offset.dx / getywidth) * _imageInfo.image.width;
                dy =
                    ((details.offset.dy) / getywidth) * _imageInfo.image.height;
                setState(() {
                  dragEnd(dx, dy);
                });
              },
              child: Padding(
                padding: const EdgeInsets.only(top: 28.0),
                child: Container(
                    color: Colors.green,
                    child: Text(
                      'tree',
                      style: TextStyle(fontSize: 30.0),
                    )),
              ),
              feedback: Container(
                height: 10.0,
                child: Text(
                  'tree',
                  style: TextStyle(fontSize: 15.0),
                ),
              )),
        ],
      )),
    );
  }

  void dragEnd(double dx, double dy) {
    if (_imageInfo != null) {
      if ((673 <= dx && dx <= 822) && (635 <= dy && dy <= 849)) {
        showDialog(
          context: context,
          builder: (context) {
            return _textDescriptionDialog(
              context,
              'Drag on tree',
            );
          },
        );
      } else {
        showDialog(
          context: context,
          builder: (context) {
            return _textDescriptionDialog(
              context,
              'Drag outside',
            );
          },
        );
      }
    }
  }

  Widget _textDescriptionDialog(BuildContext context, String text) {
    return new FractionallySizedBox(
        heightFactor: MediaQuery.of(context).orientation == Orientation.portrait
            ? 0.5
            : 0.8,
        widthFactor: MediaQuery.of(context).orientation == Orientation.portrait
            ? 0.8
            : 0.4,
        child: Card(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(20.0),
            ),
          ),
          child: Container(child: Center(child: Text(text))),
        ));
  }
}

typedef void OnTapLocation(
    Offset offset, RenderBox getBox, TapDownDetails details);

class TapImage extends StatelessWidget {
  TapImage({Key key, this.onTap, this.image}) : super(key: key);

  final OnTapLocation onTap;
  final ImageProvider image;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (TapDownDetails details) => _onTap(details, context),
      child: Image(image: AssetImage('assets/hospital.jpg')),
    );
  }

  void _onTap(TapDownDetails details, BuildContext context) {
    RenderBox getBox = context.findRenderObject();
    print('size is ${getBox.size}');
    Offset local = getBox.globalToLocal(details.globalPosition);
    print('local is $local');
    onTap(Offset(local.dx / getBox.size.width, local.dy / getBox.size.height),
        getBox, details);
  }
}
like image 51
Rishabh Avatar answered Nov 04 '22 17:11

Rishabh


You could make new Widget then get local render box size. Something like this:

class _MyHomePageState extends State<MyHomePage> {
  NetworkImage _networkImage;
  ImageInfo _imageInfo;

  @override
  void initState() {
    super.initState();

    _networkImage = NetworkImage('https://i.stack.imgur.com/2PnTa.jpg');
    _getImageInfo();
  }

  void _getImageInfo() async {
    NetworkImage _key = await _networkImage.obtainKey(ImageConfiguration());
    _networkImage.load(_key).addListener((ImageInfo i, bool b){
      print('Image size: ${i.image.width} - ${i.image.height}');
      _imageInfo = i;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ImageDetector(
          onTap: (Offset offset){
            if(_imageInfo != null){
              print('Image clicked: ${offset.dx * _imageInfo.image.width} x ${offset.dy * _imageInfo.image.height}');
            }
          },
          image: _networkImage,
        ),
      ),
    );
  }
}

typedef void OnTapLocation(Offset offset);

class ImageDetector extends StatelessWidget {
  ImageDetector({Key key, this.onTap, this.image}) : super(key: key);

  final OnTapLocation onTap;
  final ImageProvider image;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (TapDownDetails details) => _onTap(details, context),
      child: Image(image: image),
    );
  }


  void _onTap(TapDownDetails details, BuildContext context) {
    RenderBox getBox = context.findRenderObject();
    Offset local = getBox.globalToLocal(details.globalPosition);

    print('Clicked on: ${local.dx / getBox.size.width} - ${local.dy / getBox.size.height}');
    onTap(Offset(local.dx / getBox.size.width, local.dy / getBox.size.height));
  }
}

This will return click position between 0.0, 0.0 and 1.0, 1.0, you can get size of the image and get exact location from those.

Edit: updated the code

like image 2
knezzz Avatar answered Nov 04 '22 18:11

knezzz