Offsets are different onTap and OnDrag - Flutter
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);
}
}
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