Я пытаюсь изучить флаттер. Мне удалось отредактировать быстрый набор из здесь и создать быстрый набор с желаемой анимацией вращения. Но в настоящее время я столкнулся с проблемой, что FAB будет находиться наверху моего ящика, когда его откроют. Я не знаю, как это исправить. Пожалуйста, помогите мне. FAB находится наверху ящика: 
Main:
final _drawerNav = Drawer(
child: Container(
color: constant.colorPrimary,
child: ListView(
padding: EdgeInsets.fromLTRB(10.0, 30.0, 10.0, 10.0),
children: <Widget>[
UserAccountsDrawerHeader(
decoration: BoxDecoration(color: constant.colorPrimary),
accountName: Text("Ashish Rawat",
style: TextStyle(color: constant.colorWhite)),
accountEmail: Text("ashishrawat2911@gmail.com",
style: TextStyle(color: constant.colorWhite)),
currentAccountPicture: CircleAvatar(
radius: 100,
backgroundColor: constant.colorWhite,
child: Container(
width: 100,
child: CircleAvatar(
radius: 50,
backgroundColor: constant.colorPrimary,
child: Text(
"A",
style: TextStyle(fontSize: 40.0),
),
),
decoration: new BoxDecoration(
shape: BoxShape.circle,
border: new Border.all(
color: constant.colorWhite,
width: 2.0,
),
),
),
),
),
ListTile(
leading: Icon(OMIcons.accountCircle, color: constant.colorWhite),
title: Text(constant.profile,
style: TextStyle(color: constant.colorWhite)),
onTap: () {},
),
ListTile(
leading: Icon(OMIcons.event, color: constant.colorWhite),
title: Text(constant.calendar,
style: TextStyle(color: constant.colorWhite)),
onTap: () {},
),
ListTile(
leading: Icon(OMIcons.assignment, color: constant.colorWhite),
title: Text(constant.archive,
style: TextStyle(color: constant.colorWhite)),
onTap: () {},
),
ListTile(
leading: Icon(OMIcons.photo, color: constant.colorWhite),
title: Text(constant.gallery,
style: TextStyle(color: constant.colorWhite)),
onTap: () {},
),
ListTile(
leading: Icon(OMIcons.exitToApp, color: constant.colorWhite),
title: Text(constant.signOut,
style: TextStyle(color: constant.colorWhite)),
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: new Text("Alert Dialog title"),
content: new Text("Alert Dialog body"),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
},
),
],
),
))
_onSpeedDialAction(int selectedActionIndex) {
print('$selectedActionIndex Selected');
}
Widget _buildFloatingActionButton() {
final TextStyle customStyle =
TextStyle(inherit: false, color: Colors.black);
final icons = [
SpeedDialAction(child: Icon(OMIcons.photo)),
SpeedDialAction(child: Icon(OMIcons.assignment)),
SpeedDialAction(child: Icon(OMIcons.event)),
];
return SpeedDialFloatingActionButton(
actions: icons,
screenColor: Colors.black.withOpacity(0.3),
useRotateAnimation: false,
onAction: _onSpeedDialAction,
controller: _controller,
isDismissible: true,
backgroundColor: constant.colorPrimary,
foregroundColor: constant.colorWhite,
);
}
return Scaffold(
appBar: AppBar(
title: Text(_title, style: TextStyle(color: constant.colorPrimary)),
iconTheme: IconThemeData(
color: constant.colorPrimary,
),
centerTitle: true,
elevation: 1.0,
backgroundColor: constant.colorWhite),
drawer: _drawerNav,
body: _pageView,
bottomNavigationBar: _bottomNav,
floatingActionButton: _buildFloatingActionButton(),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
)
SpeedDialFloatingActionButton.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'dart:math' as math;
// Special Thanks to Andrea Bizzotto and Matt Carroll!
//
// Goal: https://material.io/components/buttons-floating-action-button/#types-of-transitions
// Influenced by: https://medium.com/coding-with-flutter/flutter-adding-animated-overlays-to-your-app-e0bb049eff39
// https://stackoverflow.com/questions/46480221/flutter-floating-action-button-with-speed-dail
// Codes from: https://github.com/bizz84/bottom_bar_fab_flutter
// https://github.com/matthew-carroll/fluttery/blob/master/lib/src/layout_overlays.dart
class SpeedDialFloatingActionButton extends StatelessWidget {
/// Creates Floating action button with speed dial attached.
///
/// [childOnFold] is default widget attched to Floating action button.
/// [useRotateAnimation] makes more fancy when using with Icons.add or with unfold child.
///
/// The [childOnFold] must not be null. Additionally,
/// if [childOnUnfold] is specified, two widgets([childOnFold] and [childOnUnfold]) will be switched with animation when speed dial is opened/closed.
///
/// NOTE: In order to apply fade transition between [childOnFold] and [childOnUnfold], make sure one of those has Key field. (eg. ValueKey<int>(value) or UniqueKey()).
/// As we using AnimatedSwitcher for transition animation, no key with same type of child will perform no animation. It is AnimatedSwitcher's behaviour.
SpeedDialFloatingActionButton(
{@required this.actions,
this.onAction,
@required this.childOnFold,
this.childOnUnfold,
this.useRotateAnimation = false,
this.backgroundColor,
this.foregroundColor,
this.screenColor,
this.animationDuration = 250,
this.controller,
this.isDismissible = false,
this.labelPosition});
final List<SpeedDialAction> actions;
final ValueChanged<int> onAction;
final Widget childOnFold;
final Widget childOnUnfold;
final int animationDuration;
final bool useRotateAnimation;
final SpeedDialController controller;
final bool isDismissible;
/// The floating button's background color.
///
/// If this property is null, then the [Theme]'s
/// [ThemeData.floatingActionButtonTheme.backgroundColor] is used. If that
/// property is also null, then the [Theme]'s
/// [ThemeData.colorScheme.secondary] color is used.
final Color backgroundColor;
/// The floating button's foreground color.
///
/// If this property is null, then the [Theme]'s
/// [ThemeData.floatingActionButtonTheme.foregroundColor] is used. If that
/// property is also null, then the [Theme]'s
/// [ThemeData.colorScheme.onSecondary] color is used.
final Color foregroundColor;
/// The screen background color when the speed dial is unfolded.
///
/// If this property is null, then the background will be transparent.
/// Tip: use the opacity property to create semi-transparent backgrounds. Example:
/// ```dart
/// screenColor: Colors.black.withOpacity(0.2)
/// ```
final Color screenColor;
/// Define if the action's labels will be at the left or at the right of their action button.
///
/// If this property is null, then the label position will obey the following rule:
/// when the floating button is positioned before the middle of the display (on the x axis), the label will be at the right of the action button,
/// otherwise the label will be at the left of the action button.
final LabelPosition labelPosition;
@override
Widget build(BuildContext context) {
return AnchoredOverlay(
showOverlay: true,
overlayBuilder: (context, offset) {
return SpeedDial(
controller: controller,
actions: actions,
onAction: onAction,
childOnFold: childOnFold,
childOnUnfold: childOnUnfold,
animationDuration: animationDuration,
useRotateAnimation: useRotateAnimation,
backgroundColor: backgroundColor,
foregroundColor: foregroundColor,
screenColor: screenColor,
isDismissible: isDismissible,
offset: Offset(offset.dx, offset.dy),
labelPosition: labelPosition,
);
},
child: FloatingActionButton(onPressed: () {}),
);
}
}
class SpeedDialAction {
SpeedDialAction(
{this.child, this.label, this.backgroundColor, this.foregroundColor});
final Widget child;
final Widget label;
/// The action button's background color.
///
/// If this property is null, then the [Theme]'s
/// [ThemeData.cardColor] is used.
final Color backgroundColor;
/// The action button's foreground color.
///
/// If this property is null, then the [Theme]'s
/// [ThemeData.accentColor] is used.
final Color foregroundColor;
}
class SpeedDial extends StatefulWidget {
SpeedDial({
@required this.actions,
this.onAction,
@required this.childOnFold,
this.childOnUnfold,
this.animationDuration,
this.useRotateAnimation,
this.backgroundColor,
this.foregroundColor,
this.screenColor,
this.controller,
this.isDismissible,
this.offset,
this.labelPosition,
});
final SpeedDialController controller;
final List<SpeedDialAction> actions;
final ValueChanged<int> onAction;
final Widget childOnFold;
final Widget childOnUnfold;
final int animationDuration;
final bool useRotateAnimation;
final Color screenColor;
final Color backgroundColor;
final Color foregroundColor;
final bool isDismissible;
final Offset offset;
final LabelPosition labelPosition;
@override
State createState() => _SpeedDialState();
}
class _SpeedDialState extends State<SpeedDial> with TickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: widget.animationDuration),
);
widget.controller ?? SpeedDialController()
..setAnimator(_controller);
if (widget.isDismissible) {
_controller.addStatusListener(_onDismissible);
}
}
@override
Widget build(BuildContext context) {
return _buildActions();
}
Widget _buildActions() {
final Size fullsize = MediaQuery.of(context).size; // device size
final double wButton = 28; // button width
final double hButtom = 28; // button height
double start;
LabelPosition labelPosition = widget.labelPosition;
if (labelPosition == null) {
labelPosition = widget.offset.dx > (fullsize.width / 2)
? LabelPosition.Left
: LabelPosition.Right;
}
if (labelPosition == LabelPosition.Right) {
start = widget.offset.dx - wButton;
} else {
start = fullsize.width - widget.offset.dx - wButton;
}
double bottom;
if (widget.offset.dy > (fullsize.height / 2)) {
bottom = fullsize.height - widget.offset.dy - hButtom;
} else {
bottom = fullsize.height + (widget.offset.dy.abs() - hButtom);
}
return widget.screenColor != null
? _buildActionsWithOverlay(bottom, start, labelPosition)
: _buildActionsWithoutOverlay(bottom, start, labelPosition);
}
Widget _buildActionsWithOverlay(
[double bottom, double start, LabelPosition labelPosition]) {
var screenColorSequence = TweenSequence<Color>([
TweenSequenceItem(
weight: 1.0,
tween: ColorTween(
begin: Color.fromARGB(0, 0, 0, 0), end: widget.screenColor))
]);
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
if (_controller.isDismissed == false)
return GestureDetector(
onTap: toggle,
child: Container(
color: screenColorSequence
.evaluate(AlwaysStoppedAnimation(_controller.value)),
child: _buildActionsWithoutOverlay(
bottom, start, labelPosition)));
else
return _buildActionsWithoutOverlay(bottom, start, labelPosition);
});
}
Widget _buildActionsWithoutOverlay(
[double bottom, double start, LabelPosition labelPosition]) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
Positioned.directional(
textDirection: labelPosition == LabelPosition.Left
? TextDirection.rtl
: TextDirection.ltr,
bottom: bottom,
start: start,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: labelPosition == LabelPosition.Left
? CrossAxisAlignment.end
: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: List.generate(widget.actions.length, (int index) {
return _buildChild(index, labelPosition);
}).reversed.toList()
..add(
_buildFab(),
),
),
),
],
);
}
Widget _buildChild(int index, LabelPosition labelPosition) {
List<Widget> rowChildren = [
_buildLabelAction(index),
_buildChildAction(index),
];
return Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: labelPosition == LabelPosition.Left
? rowChildren
: rowChildren.reversed.toList());
}
Widget _buildLabelAction(int index) {
return FadeTransition(
opacity: Tween<double>(begin: 0, end: 1).animate(_controller),
child: widget.actions[index].label != null
? Container(
padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 8.0),
margin: EdgeInsets.only(right: 5.0, bottom: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(6.0)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.7),
offset: Offset(0.8, 0.8),
blurRadius: 2.4,
)
],
),
child: widget.actions[index].label,
)
: Container(),
);
}
Widget _buildChildAction(int index) {
Color backgroundColor =
widget.actions[index].backgroundColor ?? Theme.of(context).cardColor;
Color foregroundColor =
widget.actions[index].foregroundColor ?? Theme.of(context).accentColor;
return Container(
height: 70.0,
width: 56.0,
alignment: FractionalOffset.topCenter,
child: ScaleTransition(
scale: CurvedAnimation(
parent: _controller,
curve: Interval(0.0, (index + 1) / widget.actions.length,
curve: Curves.linear),
),
child: FloatingActionButton(
backgroundColor: backgroundColor,
foregroundColor: foregroundColor,
mini: true,
child: widget.actions[index].child,
onPressed: () => _onAction(index),
),
),
);
}
Widget _buildFab() {
return FloatingActionButton(
onPressed: toggle,
backgroundColor: widget.backgroundColor,
foregroundColor: widget.foregroundColor,
child:
AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget child) {
return Transform(
transform:
Matrix4.rotationZ(_controller.value * 0.5 * math.pi),
alignment: FractionalOffset.center,
child: Icon(
_controller.isDismissed ? Icons.add : Icons.close),
);
},
),
elevation: 2.0,
);
}
void toggle() {
if (_controller.isDismissed) {
_controller.forward();
} else {
_controller.reverse();
}
}
Widget _buildRotation(Widget child) {
return Transform.rotate(
angle: _controller.value * pi / 4,
child: child,
);
}
Widget _buildAnimatedSwitcher() {
return AnimatedSwitcher(
duration: Duration(milliseconds: widget.animationDuration),
child:
_controller.value < 0.5 ? widget.childOnFold : widget.childOnUnfold,
);
}
void _onAction(int index) {
_controller.reverse();
widget.onAction(index);
}
void _onDismissible(AnimationStatus status) {
Future<bool> _onReturn() async {
_controller.reverse();
return false;
}
if (status == AnimationStatus.forward) {
Navigator.of(context).push(
PageRouteBuilder(
fullscreenDialog: true,
opaque: false,
barrierDismissible: true,
transitionDuration: Duration(milliseconds: 100),
barrierColor: Colors.black54,
pageBuilder: (BuildContext context, _, __) {
return WillPopScope(
child: Container(),
onWillPop: _onReturn,
);
},
),
);
}
if (status == AnimationStatus.reverse) {
Navigator.pop(context);
}
}
}
enum LabelPosition { Left, Right }
class AnchoredOverlay extends StatelessWidget {
final bool showOverlay;
final Widget Function(BuildContext, Offset anchor) overlayBuilder;
final Widget child;
AnchoredOverlay({
this.showOverlay,
this.overlayBuilder,
this.child,
});
@override
Widget build(BuildContext context) {
return new Container(
child: new LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return new OverlayBuilder(
showOverlay: showOverlay,
overlayBuilder: (BuildContext overlayContext) {
RenderBox box = context.findRenderObject() as RenderBox;
final center =
box.size.center(box.localToGlobal(const Offset(0.0, 0.0)));
return overlayBuilder(overlayContext, center);
},
child: child,
);
}),
);
}
}
class OverlayBuilder extends StatefulWidget {
final bool showOverlay;
final Function(BuildContext) overlayBuilder;
final Widget child;
OverlayBuilder({
this.showOverlay = false,
this.overlayBuilder,
this.child,
});
@override
_OverlayBuilderState createState() => new _OverlayBuilderState();
}
class _OverlayBuilderState extends State<OverlayBuilder> {
OverlayEntry overlayEntry;
@override
void initState() {
super.initState();
if (widget.showOverlay) {
WidgetsBinding.instance.addPostFrameCallback((_) => showOverlay());
}
}
@override
void didUpdateWidget(OverlayBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
WidgetsBinding.instance.addPostFrameCallback((_) => syncWidgetAndOverlay());
}
@override
void reassemble() {
super.reassemble();
WidgetsBinding.instance.addPostFrameCallback((_) => syncWidgetAndOverlay());
}
@override
void dispose() {
if (isShowingOverlay()) {
hideOverlay();
}
super.dispose();
}
bool isShowingOverlay() => overlayEntry != null;
void showOverlay() {
overlayEntry = new OverlayEntry(
builder: widget.overlayBuilder,
);
addToOverlay(overlayEntry);
}
void addToOverlay(OverlayEntry entry) async {
Overlay.of(context).insert(entry);
}
void hideOverlay() {
overlayEntry.remove();
overlayEntry = null;
}
void syncWidgetAndOverlay() {
if (isShowingOverlay() && !widget.showOverlay) {
hideOverlay();
} else if (!isShowingOverlay() && widget.showOverlay) {
showOverlay();
}
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
class CenterAbout extends StatelessWidget {
final Offset position;
final Widget child;
CenterAbout({
this.position,
this.child,
});
@override
Widget build(BuildContext context) {
return new Positioned(
top: position.dy,
left: position.dx,
child: new FractionalTranslation(
translation: const Offset(-0.5, -0.5),
child: child,
),
);
}
}
class SpeedDialController extends ChangeNotifier {
SpeedDialController();
AnimationController _animationController;
setAnimator(AnimationController controller) {
_animationController = controller;
}
unfold() {
if (_animationController.isDismissed == false) {
_animationController.reverse();
}
}
}