如何在Flutter中垂直布局Widget而不重叠?

问题描述 投票:0回答:2

我正在开发一个 Flutter 项目,遇到了布局问题。如下图所示,我当前的实现结果是小部件彼此堆叠,而我的目标是将它们垂直分开。

目前布局:

所需布局:

如何在同一视图中垂直分隔这些小部件?具体来说,我想将

HomePageTimerUI
放在上面,将
CountDownTimer
放在下面。

下面是我的小部件的相关代码:

homePageTimerUI.dart:

class HomePageTimerUI extends StatefulWidget {
  const HomePageTimerUI({Key? key}) : super(key: key);

  @override
  State<HomePageTimerUI> createState() => _HomePageTimerUIState();
}

class _HomePageTimerUIState extends State<HomePageTimerUI> {
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: double.maxFinite,
      width: double.infinity,
      child: DefaultTabController(
        length: 3,
        child: Scaffold(
          appBar: AppBar(
            elevation: 0,
            backgroundColor: Colors.transparent,
            bottom: PreferredSize(
              preferredSize: const Size.fromHeight(40),
              child: Container(
                color: Colors.transparent,
                child: SafeArea(
                  child: Column(
                    children: <Widget>[
                      TabBar(
                          indicator: const UnderlineTabIndicator(
                              borderSide: BorderSide(
                                  color: Color(0xff3B3B3B), width: 4.0),
                              insets:
                                  EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 11.0)),
                          indicatorWeight: 15,
                          indicatorSize: TabBarIndicatorSize.label,
                          labelColor: const Color(0xff3B3B3B),
                          labelStyle: const TextStyle(
                              fontSize: 12,
                              letterSpacing: 1.3,
                              fontWeight: FontWeight.w500),
                          unselectedLabelColor: const Color(0xffD7D7D7),
                          tabs: const [
                            Tab(
                              text: "POMODORO",
                              icon: Icon(Icons.work_history, size: 40),
                            ),
                            Tab(
                              text: "SHORT BREAK",
                              icon: Icon(Icons.ramen_dining, size: 40),
                            ),
                            Tab(
                              text: "LONG BREAK",
                              icon: Icon(Icons.battery_charging_full_rounded,
                                  size: 40),
                            ),
                          ])
                    ],
                  ),
                ),
              ),
            ),
          ),
          body: TabBarView(
            children: const <Widget>[
              // Center(
              //   child: StartPomodoro(),
              // ),
              // Center(
              //   child: ShortBreak(),
              // ),
              // Center(child: LongBreak()),
            ],
          ),
        ),
      ),
    );
  }
}

countDownTimer.dart

class CountDownTimer extends StatefulWidget {
  @override
  _CountDownTimerState createState() => _CountDownTimerState();
}

class _CountDownTimerState extends State<CountDownTimer>
    with TickerProviderStateMixin {
  late AnimationController controller;

  String get timerString {
    Duration duration = controller.duration! * controller.value;
    return '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
  }

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: Duration(seconds: 5),
    );
  }

  @override
  Widget build(BuildContext context) {
    ThemeData themeData = Theme.of(context);
    return Scaffold(
      backgroundColor: Colors.white10,
      body: AnimatedBuilder(
          animation: controller,
          builder: (context, child) {
            return Stack(
              children: <Widget>[
                Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    color: Colors.amber,
                    height:
                        controller.value * MediaQuery.of(context).size.height,
                  ),
                ),
                Padding(
                  padding: EdgeInsets.all(8.0),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Expanded(
                        child: Align(
                          alignment: FractionalOffset.center,
                          child: Stack(
                            children: <Widget>[
                              CustomPaint(
                                  painter: CustomTimerPainter(
                                animation: controller,
                                backgroundColor: Colors.white,
                                color: themeData.indicatorColor,
                              )),
                              Align(
                                alignment: FractionalOffset.center,
                                child: Column(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceEvenly,
                                  crossAxisAlignment:
                                      CrossAxisAlignment.center,
                                  children: <Widget>[
                                    Text(
                                      timerString,
                                      style: TextStyle(
                                          fontSize: 112.0,
                                          color: Colors.white),
                                    ),
                                  ],
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.stretch,
                        children: [
                          AnimatedBuilder(
                              animation: controller,
                              builder: (context, child) {
                                return FloatingActionButton.extended(
                                    onPressed: () {
                                      if (controller.isAnimating)
                                        controller.stop();
                                      else {
                                        controller.reverse(
                                            from: controller.value == 0.0
                                                ? 1.0
                                                : controller.value);
                                      }
                                    },
                                    icon: Icon(controller.isAnimating
                                        ? Icons.pause
                                        : Icons.play_arrow),
                                    label: Text(
                                        controller.isAnimating ? "Pause" : "Play"));
                              }),
                        ],
                      ),
                    ],
                  ),
                ),
              ],
            );
          }),
    );
  }
}

class CustomTimerPainter extends CustomPainter {
  CustomTimerPainter({
    required this.animation,
    required this.backgroundColor,
    required this.color,
  }) : super(repaint: animation);

  final Animation<double> animation;
  final Color backgroundColor, color;

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = backgroundColor
      ..strokeWidth = 10.0
      ..strokeCap = StrokeCap.butt
      ..style = PaintingStyle.stroke;

    canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
    paint.color = color;
    double progress = (1.0 - animation.value) * 2 * math.pi;
    canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);
  }

  @override
  bool shouldRepaint(CustomTimerPainter old) {
    return animation.value != old.animation.value ||
        color != old.color ||
        backgroundColor != old.backgroundColor;
  }
}

我尝试使用

Column
小部件解决问题,同时包装
HomePageTimerUI
CountDownTimer
,但它没有按预期工作:

class StackedPages extends StatelessWidget {
  const StackedPages({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        HomePageTimerUI(),
        CountDownTimer(),
      ],
    );
  }
}

如何才能达到下图所示的所需布局?

任何指导或建议将不胜感激。谢谢!

flutter dart widget
2个回答
1
投票

您需要 Stack() 小部件吗? 您想用一个替换另一个吗? 您可以使用 AnimatedSwitcher()。

AnimatedSwitcher(
        duration: const Duration(seconds: 1), child: MyWidget());

其中MyWidget()通过SetState()分配给你想要显示的小部件。小部件以漂亮的动画进行切换。

如果您需要将一个 Widget 在垂直轴上放置在另一个 Widget 之上,您应该尝试删除脚手架和具有无穷大值的 SizedBox。


0
投票

如果这个类不能堆叠。 只需使用

static
类型即可。 使用
CountDownTimer
将这些代码添加到同一文件中。

static const Widget countDownTimer = CountDownTimer();
...
// class CountDownTimer

然后,你必须导入这个文件并通过这个参数调用这个小部件。 例子

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        HomePageTimerUI(),
        countDownTimer,
      ],
    );
  }

但您不需要使用

StackPages
只需将
countDownTimer
放入您的页面即可。

© www.soinside.com 2019 - 2024. All rights reserved.