问题
I want to add red blinking dot on the container when it is tapped, but the dot position is not accurate. How to fix?
MyApp
import 'package:flutter/material.dart';
import 'blinking_dot.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
double posx;
double posy;
void onTapDown(BuildContext context, TapDownDetails details) {
print('${details.globalPosition}');
final RenderBox box = context.findRenderObject();
final Offset localOffset = box.globalToLocal(details.globalPosition);
setState(() {
posx = localOffset.dx;
posy = localOffset.dy;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GestureDetector(
onTapDown: (TapDownDetails details) => onTapDown(context, details),
child: Stack(
children: <Widget>[
Container(
height: double.infinity,width: double.infinity,
padding: EdgeInsets.all(10),
child: Image.asset("assets/img.jpg")),
Positioned(
child: BlinkingDot(),
left: posx,
top: posy,
)
],
)));
}
}
blinking_dot.dart
import 'package:flutter/material.dart';
class BlinkingDot extends StatefulWidget {
@override
_BlinkingDotState createState() => _BlinkingDotState();
}
class _BlinkingDotState extends State<BlinkingDot>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
@override
void initState() {
_animationController =
new AnimationController(vsync: this, duration: Duration(seconds: 1));
_animationController.repeat();
super.initState();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: _animationController,
child: Container(
height: 15,
width: 15,
child: FloatingActionButton(
backgroundColor: Colors.redAccent,
)));
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
}
Output
回答1:
posy = localOffset.dy- MediaQuery.of(context).padding.top - kToolbarHeight;
also you need to decrease offset by half of the red dot size in your case if will something like this
posx = localOffset.dx - 7.5;
posy = localOffset.dy- MediaQuery.of(context).padding.top - kToolbarHeight - 7.5;
回答2:
Are you looking like this?
Home page
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
double posx;
double posy;
void onTapDown(BuildContext context, TapDownDetails details) {
print('${details.globalPosition}');
final RenderBox box = context.findRenderObject();
final Offset localOffset = box.globalToLocal(details.globalPosition);
setState(() {
posx = localOffset.dx;
posy = localOffset.dy-70.0;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("widget.title"),
),
body: GestureDetector(
onTapDown: (TapDownDetails details) => onTapDown(context, details),
child: Stack(
children: <Widget>[
Container(
height: double.infinity,
width: double.infinity,
padding: EdgeInsets.all(10),
child: Image.asset("assets/img.jpg")),
Positioned(
child: BlinkingDot(),
left: posx,
top: posy,
)
],
),
));
}
}
BlinkingDot page
class BlinkingDot extends StatefulWidget {
@override
_BlinkingDotState createState() => _BlinkingDotState();
}
class _BlinkingDotState extends State<BlinkingDot>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
@override
void initState() {
_animationController =
new AnimationController(vsync: this, duration: Duration(seconds: 1));
_animationController.repeat();
super.initState();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: _animationController,
child: Container(
height: 15,
width: 15,
child: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.redAccent,
)));
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
}
回答3:
It's because you did not consider the following
- You need to subtract AppBar height from dy.
- You need to subtract the circle radius from both dx and dy.
- You need to subtract the top padding from dy and left padding from dx.
Do the following to get the expected result
posx = localOffset.dx - MediaQuery.of(context).padding.left - circleRadius;
posy = localOffset.dy -MediaQuery.of(context).padding.top - circleRadius - kToolbarHeight;
Here is the complete snippet
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
//int _counter = 0;
double posx;
double posy;
final circleRadius = 7.5;
void onTapDown(BuildContext context, TapDownDetails details) {
print('${details.globalPosition}');
final RenderBox box = context.findRenderObject();
final Offset localOffset = box.globalToLocal(details.globalPosition);
setState(() {
posx =
localOffset.dx - MediaQuery.of(context).padding.left - circleRadius;
posy = localOffset.dy -MediaQuery.of(context).padding.top - circleRadius - kToolbarHeight;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GestureDetector(
onTapDown: (TapDownDetails details) => onTapDown(context, details),
child: Stack(
children: <Widget>[
Container(
height: double.infinity,
width: double.infinity,
padding: EdgeInsets.all(10),
child: Image.asset("assets/img.jpg")),
Positioned(
child: BlinkingDot(circleRadius: circleRadius),
left: posx,
top: posy,
)
],
)));
}
}
class BlinkingDot extends StatefulWidget {
final double circleRadius;
const BlinkingDot({Key key, this.circleRadius}) : super(key: key);
@override
_BlinkingDotState createState() => _BlinkingDotState();
}
class _BlinkingDotState extends State<BlinkingDot>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
@override
void initState() {
_animationController =
new AnimationController(vsync: this, duration: Duration(seconds: 1));
_animationController.repeat();
super.initState();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: _animationController,
child: Container(
height: widget.circleRadius * 2,
width: widget.circleRadius * 2,
child: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.redAccent,
)));
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
}
See the live demo here.
来源:https://stackoverflow.com/questions/60410715/stack-position-not-accurate