Stack position not accurate

故事扮演 提交于 2021-01-28 05:08:23

问题


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

  1. You need to subtract AppBar height from dy.
  2. You need to subtract the circle radius from both dx and dy.
  3. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!