Flutter变换动画破坏了底部导航栏中的浮动动作按钮的“按下状态”功能。需要解决方法

时间:2019-09-30 09:46:31

标签: flutter flutter-layout

我目前正在尝试实现在单击底部导航菜单中的浮动操作按钮时出现的径向菜单(图1)。动画和渲染工作正常,但是在动画之后,单击按钮时,甚至不会触发按下按钮功能。我已经读到这是由于堆栈,包装了按钮和动画。转换后的按钮的区域不是先验定义的。这导致按钮的手势检测停留在FAB后面。用固定大小的容器包装堆栈可以解决此问题,但是,这完全破坏了布局。另外,由于容器位于导航栏上方,因此无法访问背景中的可单击导航图标(请参见image2)。是否有已知的解决方法来解决此问题?我真的很期待得到专业的帮助。 :)

Image of not working buttons and desired layout

Image of the broken UI after wrapping the stack with a container. But in this solution button pressed is working

代码附在这里:

import 'package:flutter/material.dart';
import 'dart:math';
import 'package:vector_math/vector_math.dart' show radians;

class RadialFloatingActionButton extends StatefulWidget {
  @override
  _RadialFloatingActionButtonState createState() => _RadialFloatingActionButtonState();
 }

class _RadialFloatingActionButtonState extends State<RadialFloatingActionButton> with 
      SingleTickerProviderStateMixin {
      AnimationController controller;

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

      @override
      Widget build(BuildContext context) {
        return RadialAnimation(controller: controller);
      }
    }

    class RadialAnimation extends StatelessWidget {
      RadialAnimation({Key key, this.controller})
          : scale = Tween<double>(
              begin: 1.5,
              end: 0.0,
            ).animate(
              CurvedAnimation(parent: controller, curve: Curves.elasticInOut),
             ),
            translation = Tween<double>(
              begin: 0.0,
              end: 90.0,
            ).animate(
              CurvedAnimation(parent: controller, curve: Curves.easeInOutCirc),
            ),
            super(key: key);

      final AnimationController controller;
      final Animation<double> scale;
      final Animation<double> translation;

      build(context) {
        return AnimatedBuilder(
             animation: controller,
             builder: (context, builder) {
              return Stack(alignment: Alignment.center, children: [
                _buildButton(200, color: Colors.black, emoji: "A"),
                _buildButton(245, color: Colors.black, emoji: "B"),
                _buildButton(295, color: Colors.black, emoji: "C"),
                _buildButtonMore(340, color: Colors.grey),
                Transform.scale(
                  scale: scale.value -
                      1.5, // subtract the beginning value to run the opposite animation
                  child: FloatingActionButton(
                      child: Icon(
                        Icons.close,
                      ),
                      onPressed: _close,
                      backgroundColor: Colors.black),
                 ),
                Transform.scale(
                  scale: scale.value,
                  child: FloatingActionButton(
                      child: Icon(
                        Icons.people,
                        color: Colors.white,
                      ),
                      onPressed: _open,
                      backgroundColor: Colors.black),
                 )
              ]);
            });
      }

      _buildButtonMore(double angle, {Color color}) {
        final double rad = radians(angle);
        return Transform(
            transform: Matrix4.identity()
              ..translate(
                  (translation.value) * cos(rad), (translation.value) * sin(rad)),
            child: FloatingActionButton(
                child: Icon(Icons.more_horiz),
                backgroundColor: color,
                onPressed: _close,
                elevation: 0));
      }

      _buildButton(double angle, {Color color, String emoji}) {
        final double rad = radians(angle);
        return Transform(
            transform: Matrix4.identity()
              ..translate(
                  (translation.value) * cos(rad), (translation.value) * sin(rad)),
            child: FloatingActionButton(
                child: Center(
                  child: new Text(
                    emoji,
                    style: TextStyle(fontSize: 30),
                    textAlign: TextAlign.center,
                  ),
                 ),
                backgroundColor: color,
                onPressed: _close,
                elevation: 0));
      }

      _open() {
        controller.forward();
      }

      _close() {
        controller.reverse();
      }
    }

1 个答案:

答案 0 :(得分:0)

我现在无法测试,但是包装在容器中似乎是正确的解决方法,因为Transforms似乎not apply 会在无边界的盒子中击中测试行为(这就是为什么Container使其起作用)。也许有一种方法(某种小部件或属性)可以使hitTestBehavior(例如GestureDetector)在其中进行设置,将其设置为“不透明区域”,而不是将Container的整个边界框捕获为触摸。 抱歉,我无法直接为您提供答案,稍后将在计算机上进行确认:)