在可扩展浮动操作按钮中,在颤动中未检测到子小部件中的手势

Posted

技术标签:

【中文标题】在可扩展浮动操作按钮中,在颤动中未检测到子小部件中的手势【英文标题】:In Expandable Floating action button the gestures in the child widget is not detected in flutter 【发布时间】:2021-09-24 01:39:54 【问题描述】:

尝试实现一个二维扩展的浮动操作按钮,然后显示更多浮动操作按钮选项。 不知何故,能够使用变换小部件将浮动操作按钮的子小部件设置为正确的位置,但是当我尝试按下子小部件时,即按下浮动操作按钮时出现的小部件,它们没有响应到 onPressed 处理程序。 尝试了许多不同的东西,如 IgnorePointer、堆叠的行和列、AnimatedBuilder 等。但无法找到正确的解决方案。 就像有时用来使 UI 正确,然后未检测到手势,如果检测到手势,则 UI 会失真。 而且我对扑腾有点陌生。如有任何帮助解决此问题,我们将不胜感激。

这是我的代码:

main.dart

import "package:flutter/material.dart";
import 'myhome.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      theme: ThemeData(
        primaryColor: Colors.blue,
      ),
      title: "Custom Expandable FAB",
      home: MyHome(),
    );
  

myhome.dart

import 'package:flutter/material.dart';
import 'package:tester_project/customFAB.dart';

class MyHome extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      extendBody: true,
      backgroundColor: Colors.white,
      floatingActionButton: CustomFab(),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      bottomNavigationBar: BottomAppBar(
        color: Colors.blue,
        shape: CircularNotchedRectangle(),
        child: Container(
          height: 55,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              IconButton(
                icon: Icon(Icons.search),
                onPressed: () ,
              ),
              IconButton(
                icon: Icon(Icons.menu),
                onPressed: () ,
              ),
            ],
          ),
        ),
      ),
      appBar: AppBar(
        title: Text("Custom FAB"),
      ),
      body: Container(
        alignment: Alignment.center,
        child: Text("Click on Fab to expand"),
        color: Colors.white,
      ),
    );
  

CustomFab.dart

import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

class CustomFab extends StatefulWidget 
  @override
  _CustomFabState createState() => _CustomFabState();


class _CustomFabState extends State<CustomFab>
    with SingleTickerProviderStateMixin 
  AnimationController _animationController;
  Animation<double> _translateAnimation;
  Animation<double> _rotationAnimation;

  Animation<double> _iconRotation;

  bool _isExpanded = false;

  void animate() 
    if (!_isExpanded) 
      _animationController.forward();
     else 
      _animationController.reverse();
    

    _isExpanded = !_isExpanded;
  

  Widget fab1() 
    return Container(
      height: 60,
      width: 60,
      child: FittedBox(
        child: FloatingActionButton(
          heroTag: "btn3",
          backgroundColor: Color(0xffFFC852),
          elevation: 0,
          onPressed: () 
            print("pressed");
          ,
        ),
      ),
    );
  

  Widget fab2() 
    return Container(
      height: 60,
      width: 60,
      child: FittedBox(
        child: FloatingActionButton(
          heroTag: "btn4",
          child: Transform.rotate(
            angle: _iconRotation.value,
            child: Icon(Icons.home),
          ),
          elevation: _isExpanded ? 5 : 0,
          backgroundColor: Color(0xffE5E4F4),
          onPressed: () 
            print("Pressed");
          ,
        ),
      ),
    );
  

  Widget fab3() 
    return Container(
      height: 60,
      width: 60,
      child: FittedBox(
        child: FloatingActionButton(
          heroTag: "btn5",
          child: Transform.rotate(
            angle: _rotationAnimation.value,
            child: Icon(Icons.add),
          ),
          backgroundColor: Color(0xffFFC852),
          onPressed: () async 
            await Permission.contacts.request();
            if (await Permission.contacts.status.isGranted) 
              animate();
            
          ,
        ),
      ),
    );
  

  @override
  void initState() 
    _animationController =
        AnimationController(vsync: this, duration: Duration(milliseconds: 400))
          ..addListener(() 
            setState(() );
          );
    _translateAnimation = Tween<double>(begin: 0, end: 80)
        .chain(
          CurveTween(
            curve: _isExpanded ? Curves.fastOutSlowIn : Curves.bounceOut,
          ),
        )
        .animate(_animationController);

    _iconRotation = Tween<double>(begin: 3.14 / 2, end: 0)
        .chain(
          CurveTween(curve: Curves.bounceInOut),
        )
        .animate(_animationController);
    _rotationAnimation = Tween<double>(begin: 0, end: 3 * 3.14 / 4)
        .chain(
          CurveTween(
            curve: Curves.bounceInOut,
          ),
        )
        .animate(_animationController);
    super.initState();
  

  @override
  void dispose() 
    _animationController.dispose();
    super.dispose();
  

  @override
  Widget build(BuildContext context) 
    return Stack(
      clipBehavior: Clip.none,
      children: [
        Transform(
          transform:
              Matrix4.translationValues(0, -_translateAnimation.value, 0),
          child: fab1(),
        ),
        Transform(
          transform:
              Matrix4.translationValues(-_translateAnimation.value, 0, 0),
          child: fab2(),
        ),
        fab3(),
      ],
    );
  

展开前后的浮动动作按钮

【问题讨论】:

【参考方案1】:

看看这个。 https://api.flutter.dev/flutter/widgets/Transform-class.html

与在布局之前应用旋转的 RotatedBox 不同,此对象仅在绘制之前应用其转换,这意味着在计算此小部件的子级(以及此小部件)消耗多少空间时不考虑转换。

所以,您的fab1(),fab2(),fab3() 的位置相同。 尽管您为它们设置了动画,但它只是在painting 处移动,它们的真实位置不会改变。 只要给你的工厂上色,你就会明白我的意思。

        Container(
          color:Colors.green,
          child: Transform(
            transform:
                Matrix4.translationValues(-_translateAnimation!.value, 0, 0),
            child: fab2(),
          ),
        ),

现在您知道原因了,而且您需要知道怎么做。 所以我希望你能看看这个。 https://api.flutter.dev/flutter/animation/animation-library.html 您可以使用Stack&amp;&amp;Positioned,和Tween,计算每个按钮的位置,或其他方式。我会让你去探索。

这是 CustomFab.dart 的一些代码


  @override
  Widget build(BuildContext context) 
    return Container(
      // color: Colors.green, // Give this area a background color, then you know why.
      height: 150,// You need to give your "action area" a bigger size.
      width: 150,// make these bigger have a problem, your bar will have a bigger circle.
                // if you need this effect, you need to change all your fabs "Stack on the appbar"
                // or just remove `shape: CircularNotchedRectangle(),` in myhome.dart
      child: Stack(
        clipBehavior: Clip.none,
        children: [
          Positioned(// These numbers just for example, you can make your own size or position.
            left: 150 / 2 - 30,
            bottom: _translateAnimation.value + 40,
            child: fab1(),
          ),
          Positioned(
            left: 150 / 2 - 30 -_translateAnimation.value,
            bottom: 40,
            child: fab2(),
          ),
          Positioned(
            left: 150 / 2 - 30,
            bottom: 40,
            child: fab3(),
          ),
        ],
      ),
    );
  

【讨论】:

我也尝试使用堆栈和定位小部件来实现它,但没有任何改变,一切都保持不变...... 如果可能的话,请用不同的方法帮助我...... 在您的情况下,还有一个问题是,您的堆栈大小很小,而您clipBehavior: Clip.none,,因此按钮可以绘制,但没有手势区域。我会编辑答案。 关于if you need this effect, you need to change all your fabs "Stack on the appbar",我的意思是,不要在 CustomFab 中创建 floating buttons,您可以创建 Overlay,使按钮浮动在屏幕上,计算他们的位置。【参考方案2】:

使用此套餐https://pub.dev/packages/flutter_speed_dial尝试快速拨号

    SpeedDial(
    marginBottom: 25,
    marginEnd: 25,
    backgroundColor: Colors.blue,
    activeBackgroundColor: Colors.white,
    activeForegroundColor: Colors.blue,
    animatedIcon: AnimatedIcons.menu_close,
    children: [
      SpeedDialChild(
          child: Icon(
            Icons.filter_alt,
          ),
          label: 'ABC',
          onTap: () 
            
          ),
      SpeedDialChild(
          labelBackgroundColor: Colors.white,
          backgroundColor: Colors.blue,
          foregroundColor: Colors.white,
          child: Icon(Icons.add),
          label: 'ABC',
          onTap: () 
            
          ),
    ],
  ),

【讨论】:

以上是关于在可扩展浮动操作按钮中,在颤动中未检测到子小部件中的手势的主要内容,如果未能解决你的问题,请参考以下文章

将组件添加到子小部件后调整 QDialog 的大小

如何在颤动中从父小部件调用子小部件的initState()方法

Qt5 paintEvent 传播到子小部件

如何将父小部件焦点重定向到子小部件?

确定 QKeyEvent 的来源

如何在颤动中制作带有弹出菜单的浮动操作按钮?