尝试实现一个二维扩展的浮动操作按钮,然后显示浮动操作按钮的更多选项。 能够使用变换小部件以某种方式将浮动操作按钮的子小部件动画到正确的位置,但是当我尝试按下子小部件时,即按下浮动操作按钮时出现的小部件,它们没有响应到 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(),
);
}
}
我的家.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(),
],
);
}
}
展开前后的浮动操作按钮
看看这个。 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&&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(),
),
],
),
);
}
使用 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: () {
}),
],
),