I/where 如何将自定义动画浮动操作按钮置于主要 page/content 之上?扑
How do I/where do I put a custom Animated Floating Action Button to be on top of the main page/content? flutter
我遵循了一些关于创建自定义浮动操作按钮的教程,并成功地重新创建了它并根据我的喜好进行了自定义。但是,我遇到了初学者问题,而我不知道如何 to/where 开始构建内容的主体。
更具体地说,我想构建一个视频提要(如 instagram/youtube 样式),但将 FAB(浮动操作按钮)用作此菜单和其他一些菜单屏幕。
如何在代码中I/where开始构建我的内容主体?
请在下面找到我当前的自定义操作按钮和动画代码。谢谢你的时间。
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'constants.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Mandaboo',
theme: ThemeData(
),
home: MyHomePage(
),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation degOneTranslationAnimation,degTwoTranslationAnimation,degThreeTranslationAnimation, degFourTranslationAnimation;
Animation rotationAnimation;
double getRadiansFromDegree(double degree) {
double unitRadian = 57.295779513;
return degree / unitRadian;
}
@override
void initState() {
animationController = AnimationController(vsync: this,duration: Duration(milliseconds: 250));
degOneTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.2), weight: 75.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.2,end: 1.0), weight: 25.0),
]).animate(animationController);
degTwoTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.4), weight: 55.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.4,end: 1.0), weight: 45.0),
]).animate(animationController);
degThreeTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.75), weight: 35.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.75,end: 1.0), weight: 65.0),
]).animate(animationController);
degFourTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 2.10), weight: 15.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 2.10,end: 1.0), weight: 85.0),
]).animate(animationController);
rotationAnimation = Tween<double>(begin: 180.0,end: 0.0).animate(CurvedAnimation(parent: animationController
, curve: Curves.easeOut));
super.initState();
animationController.addListener((){
setState(() {
});
});
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
child: Scaffold(
body: Container(
width: size.width,
height: size.height,
child: Stack(
children: <Widget>[
Positioned(
right: 30,
bottom: 30,
child: Stack(
alignment: Alignment.bottomRight,
children: <Widget>[
IgnorePointer(
child: Container(
color: Colors.white.withOpacity(0.0), // comment or change to transparent color
height: 150.0,
width: 150.0,
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(270),degOneTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degOneTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 40,
height: 40,
icon: Icon(
Icons.add,
color: Colors.white,
),
onClick: (){
print('First Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(240),degTwoTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degTwoTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.shop_two,
color: Colors.white,
),
onClick: (){
print('Second button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(210),degThreeTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degThreeTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.equalizer,
color: Colors.white,
),
onClick: (){
print('Third Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(180),degFourTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degFourTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.settings,
color: Colors.white,
),
onClick: (){
print('Fourth Button');
},
),
),
),
Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value)),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 60,
height: 60,
icon: Icon(
Icons.menu,
color: Colors.white,
),
onClick: (){
if (animationController.isCompleted) {
animationController.reverse();
} else {
animationController.forward();
}
},
),
)
],
))
],
),
),
),
);
}
}
class CircularButton extends StatelessWidget {
final double width;
final double height;
final Color color;
final Icon icon;
final Function onClick;
CircularButton({this.color, this.width, this.height, this.icon, this.onClick});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: color,shape: BoxShape.circle),
width: width,
height: height,
child: IconButton(icon: icon,enableFeedback: true, onPressed: onClick),
);
}
}
p.s - 我知道对此可能有一个非常简单的答案,但我现在还不知道。
p.p.s - 我对此进行了认真的搜索,但找不到答案,因此提出了这个问题。
假设这是您的小部件树
创建主要内容 body 通过 flutter codelabs
一些建议
- Material 库中的 Scaffold 小部件提供了一个默认应用栏、一个标题和一个 body 属性 用于保存主屏幕的小部件树。小部件子树可能非常复杂。
- 小部件的主要工作是提供一种构建方法,该方法描述如何根据其他 lower-level 小部件显示小部件。
然后添加自定义浮动按钮,您需要做的就是
...
Scaffold(
body: Center(..
floatingActionButton:MyCustomFaB(),
您可以复制粘贴 运行 下面的完整代码
您可以将您的自定义 Floating Action Button
移动到 Scaffold
的 floatingActionButton
并将您的主要内容放在 body
return Scaffold(
appBar: AppBar(
title: const Text('Test page'),
),
body: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Colors.blue,
child: Center(child: Text('Entry ${index}')),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
floatingActionButton: Stack(
children: <Widget>[
Positioned(
工作演示
完整代码
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Mandaboo',
theme: ThemeData(),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation degOneTranslationAnimation,
degTwoTranslationAnimation,
degThreeTranslationAnimation,
degFourTranslationAnimation;
Animation rotationAnimation;
double getRadiansFromDegree(double degree) {
double unitRadian = 57.295779513;
return degree / unitRadian;
}
@override
void initState() {
animationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 250));
degOneTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0.0, end: 1.2), weight: 75.0),
TweenSequenceItem<double>(
tween: Tween<double>(begin: 1.2, end: 1.0), weight: 25.0),
]).animate(animationController);
degTwoTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0.0, end: 1.4), weight: 55.0),
TweenSequenceItem<double>(
tween: Tween<double>(begin: 1.4, end: 1.0), weight: 45.0),
]).animate(animationController);
degThreeTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0.0, end: 1.75), weight: 35.0),
TweenSequenceItem<double>(
tween: Tween<double>(begin: 1.75, end: 1.0), weight: 65.0),
]).animate(animationController);
degFourTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0.0, end: 2.10), weight: 15.0),
TweenSequenceItem<double>(
tween: Tween<double>(begin: 2.10, end: 1.0), weight: 85.0),
]).animate(animationController);
rotationAnimation = Tween<double>(begin: 180.0, end: 0.0).animate(
CurvedAnimation(parent: animationController, curve: Curves.easeOut));
super.initState();
animationController.addListener(() {
setState(() {});
});
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
title: const Text('Test page'),
),
body: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Colors.blue,
child: Center(child: Text('Entry ${index}')),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
floatingActionButton: Stack(
children: <Widget>[
Positioned(
right: 30,
bottom: 30,
child: Stack(
alignment: Alignment.bottomRight,
children: <Widget>[
IgnorePointer(
child: Container(
color: Colors.white.withOpacity(
0.0), // comment or change to transparent color
height: 150.0,
width: 150.0,
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(270),
degOneTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(
getRadiansFromDegree(rotationAnimation.value))
..scale(degOneTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 40,
height: 40,
icon: Icon(
Icons.add,
color: Colors.white,
),
onClick: () {
print('First Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(240),
degTwoTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(
getRadiansFromDegree(rotationAnimation.value))
..scale(degTwoTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.shop_two,
color: Colors.white,
),
onClick: () {
print('Second button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(210),
degThreeTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(
getRadiansFromDegree(rotationAnimation.value))
..scale(degThreeTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.equalizer,
color: Colors.white,
),
onClick: () {
print('Third Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(180),
degFourTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(
getRadiansFromDegree(rotationAnimation.value))
..scale(degFourTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.settings,
color: Colors.white,
),
onClick: () {
print('Fourth Button');
},
),
),
),
Transform(
transform: Matrix4.rotationZ(
getRadiansFromDegree(rotationAnimation.value)),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 60,
height: 60,
icon: Icon(
Icons.menu,
color: Colors.white,
),
onClick: () {
if (animationController.isCompleted) {
animationController.reverse();
} else {
animationController.forward();
}
},
),
)
],
))
],
),
);
}
}
class CircularButton extends StatelessWidget {
final double width;
final double height;
final Color color;
final Icon icon;
final Function onClick;
CircularButton(
{this.color, this.width, this.height, this.icon, this.onClick});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
width: width,
height: height,
child: IconButton(icon: icon, enableFeedback: true, onPressed: onClick),
);
}
}
内容不可见,因为您正在为自定义 FAB 使用脚手架
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
//import 'constants.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Mandaboo',
theme: ThemeData(
),
home: MyHomePage(
),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text('hi i\'m content'),),
floatingActionButton: CustomFAB(),
);
}
}
class CustomFAB extends StatefulWidget {
@override
_CustomFABState createState() => _CustomFABState();
}
class _CustomFABState extends State<CustomFAB> with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation degOneTranslationAnimation,degTwoTranslationAnimation,degThreeTranslationAnimation, degFourTranslationAnimation;
Animation rotationAnimation;
double getRadiansFromDegree(double degree) {
double unitRadian = 57.295779513;
return degree / unitRadian;
}
@override
void initState() {
animationController = AnimationController(vsync: this,duration: Duration(milliseconds: 250));
degOneTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.2), weight: 75.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.2,end: 1.0), weight: 25.0),
]).animate(animationController);
degTwoTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.4), weight: 55.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.4,end: 1.0), weight: 45.0),
]).animate(animationController);
degThreeTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.75), weight: 35.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.75,end: 1.0), weight: 65.0),
]).animate(animationController);
degFourTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 2.10), weight: 15.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 2.10,end: 1.0), weight: 85.0),
]).animate(animationController);
rotationAnimation = Tween<double>(begin: 180.0,end: 0.0).animate(CurvedAnimation(parent: animationController
, curve: Curves.easeOut));
super.initState();
animationController.addListener((){
setState(() {
});
});
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
width: size.width,
height: size.height,
child: Stack(
children: <Widget>[
Positioned(
right: 30,
bottom: 30,
child: Stack(
alignment: Alignment.bottomRight,
children: <Widget>[
IgnorePointer(
child: Container(
color: Colors.white.withOpacity(0.0), // comment or change to transparent color
height: 150.0,
width: 150.0,
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(270),degOneTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degOneTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 40,
height: 40,
icon: Icon(
Icons.add,
color: Colors.white,
),
onClick: (){
print('First Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(240),degTwoTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degTwoTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.shop_two,
color: Colors.white,
),
onClick: (){
print('Second button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(210),degThreeTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degThreeTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.equalizer,
color: Colors.white,
),
onClick: (){
print('Third Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(180),degFourTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degFourTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.settings,
color: Colors.white,
),
onClick: (){
print('Fourth Button');
},
),
),
),
Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value)),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 60,
height: 60,
icon: Icon(
Icons.menu,
color: Colors.white,
),
onClick: (){
if (animationController.isCompleted) {
animationController.reverse();
} else {
animationController.forward();
}
},
),
)
],
))
],
),
);
}
}
class CircularButton extends StatelessWidget {
final double width;
final double height;
final Color color;
final Icon icon;
final Function onClick;
CircularButton({this.color, this.width, this.height, this.icon, this.onClick});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: color,shape: BoxShape.circle),
width: width,
height: height,
child: IconButton(icon: icon,enableFeedback: true, onPressed: onClick),
);
}
}
我遵循了一些关于创建自定义浮动操作按钮的教程,并成功地重新创建了它并根据我的喜好进行了自定义。但是,我遇到了初学者问题,而我不知道如何 to/where 开始构建内容的主体。
更具体地说,我想构建一个视频提要(如 instagram/youtube 样式),但将 FAB(浮动操作按钮)用作此菜单和其他一些菜单屏幕。
如何在代码中I/where开始构建我的内容主体?
请在下面找到我当前的自定义操作按钮和动画代码。谢谢你的时间。
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'constants.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Mandaboo',
theme: ThemeData(
),
home: MyHomePage(
),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation degOneTranslationAnimation,degTwoTranslationAnimation,degThreeTranslationAnimation, degFourTranslationAnimation;
Animation rotationAnimation;
double getRadiansFromDegree(double degree) {
double unitRadian = 57.295779513;
return degree / unitRadian;
}
@override
void initState() {
animationController = AnimationController(vsync: this,duration: Duration(milliseconds: 250));
degOneTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.2), weight: 75.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.2,end: 1.0), weight: 25.0),
]).animate(animationController);
degTwoTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.4), weight: 55.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.4,end: 1.0), weight: 45.0),
]).animate(animationController);
degThreeTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.75), weight: 35.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.75,end: 1.0), weight: 65.0),
]).animate(animationController);
degFourTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 2.10), weight: 15.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 2.10,end: 1.0), weight: 85.0),
]).animate(animationController);
rotationAnimation = Tween<double>(begin: 180.0,end: 0.0).animate(CurvedAnimation(parent: animationController
, curve: Curves.easeOut));
super.initState();
animationController.addListener((){
setState(() {
});
});
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
child: Scaffold(
body: Container(
width: size.width,
height: size.height,
child: Stack(
children: <Widget>[
Positioned(
right: 30,
bottom: 30,
child: Stack(
alignment: Alignment.bottomRight,
children: <Widget>[
IgnorePointer(
child: Container(
color: Colors.white.withOpacity(0.0), // comment or change to transparent color
height: 150.0,
width: 150.0,
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(270),degOneTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degOneTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 40,
height: 40,
icon: Icon(
Icons.add,
color: Colors.white,
),
onClick: (){
print('First Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(240),degTwoTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degTwoTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.shop_two,
color: Colors.white,
),
onClick: (){
print('Second button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(210),degThreeTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degThreeTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.equalizer,
color: Colors.white,
),
onClick: (){
print('Third Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(180),degFourTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degFourTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.settings,
color: Colors.white,
),
onClick: (){
print('Fourth Button');
},
),
),
),
Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value)),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 60,
height: 60,
icon: Icon(
Icons.menu,
color: Colors.white,
),
onClick: (){
if (animationController.isCompleted) {
animationController.reverse();
} else {
animationController.forward();
}
},
),
)
],
))
],
),
),
),
);
}
}
class CircularButton extends StatelessWidget {
final double width;
final double height;
final Color color;
final Icon icon;
final Function onClick;
CircularButton({this.color, this.width, this.height, this.icon, this.onClick});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: color,shape: BoxShape.circle),
width: width,
height: height,
child: IconButton(icon: icon,enableFeedback: true, onPressed: onClick),
);
}
}
p.s - 我知道对此可能有一个非常简单的答案,但我现在还不知道。 p.p.s - 我对此进行了认真的搜索,但找不到答案,因此提出了这个问题。
假设这是您的小部件树
一些建议
- Material 库中的 Scaffold 小部件提供了一个默认应用栏、一个标题和一个 body 属性 用于保存主屏幕的小部件树。小部件子树可能非常复杂。
- 小部件的主要工作是提供一种构建方法,该方法描述如何根据其他 lower-level 小部件显示小部件。
然后添加自定义浮动按钮,您需要做的就是
...
Scaffold(
body: Center(..
floatingActionButton:MyCustomFaB(),
您可以复制粘贴 运行 下面的完整代码
您可以将您的自定义 Floating Action Button
移动到 Scaffold
的 floatingActionButton
并将您的主要内容放在 body
return Scaffold(
appBar: AppBar(
title: const Text('Test page'),
),
body: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Colors.blue,
child: Center(child: Text('Entry ${index}')),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
floatingActionButton: Stack(
children: <Widget>[
Positioned(
工作演示
完整代码
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Mandaboo',
theme: ThemeData(),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation degOneTranslationAnimation,
degTwoTranslationAnimation,
degThreeTranslationAnimation,
degFourTranslationAnimation;
Animation rotationAnimation;
double getRadiansFromDegree(double degree) {
double unitRadian = 57.295779513;
return degree / unitRadian;
}
@override
void initState() {
animationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 250));
degOneTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0.0, end: 1.2), weight: 75.0),
TweenSequenceItem<double>(
tween: Tween<double>(begin: 1.2, end: 1.0), weight: 25.0),
]).animate(animationController);
degTwoTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0.0, end: 1.4), weight: 55.0),
TweenSequenceItem<double>(
tween: Tween<double>(begin: 1.4, end: 1.0), weight: 45.0),
]).animate(animationController);
degThreeTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0.0, end: 1.75), weight: 35.0),
TweenSequenceItem<double>(
tween: Tween<double>(begin: 1.75, end: 1.0), weight: 65.0),
]).animate(animationController);
degFourTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0.0, end: 2.10), weight: 15.0),
TweenSequenceItem<double>(
tween: Tween<double>(begin: 2.10, end: 1.0), weight: 85.0),
]).animate(animationController);
rotationAnimation = Tween<double>(begin: 180.0, end: 0.0).animate(
CurvedAnimation(parent: animationController, curve: Curves.easeOut));
super.initState();
animationController.addListener(() {
setState(() {});
});
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
title: const Text('Test page'),
),
body: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: 50,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Colors.blue,
child: Center(child: Text('Entry ${index}')),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
floatingActionButton: Stack(
children: <Widget>[
Positioned(
right: 30,
bottom: 30,
child: Stack(
alignment: Alignment.bottomRight,
children: <Widget>[
IgnorePointer(
child: Container(
color: Colors.white.withOpacity(
0.0), // comment or change to transparent color
height: 150.0,
width: 150.0,
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(270),
degOneTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(
getRadiansFromDegree(rotationAnimation.value))
..scale(degOneTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 40,
height: 40,
icon: Icon(
Icons.add,
color: Colors.white,
),
onClick: () {
print('First Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(240),
degTwoTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(
getRadiansFromDegree(rotationAnimation.value))
..scale(degTwoTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.shop_two,
color: Colors.white,
),
onClick: () {
print('Second button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(210),
degThreeTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(
getRadiansFromDegree(rotationAnimation.value))
..scale(degThreeTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.equalizer,
color: Colors.white,
),
onClick: () {
print('Third Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(180),
degFourTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(
getRadiansFromDegree(rotationAnimation.value))
..scale(degFourTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.settings,
color: Colors.white,
),
onClick: () {
print('Fourth Button');
},
),
),
),
Transform(
transform: Matrix4.rotationZ(
getRadiansFromDegree(rotationAnimation.value)),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 60,
height: 60,
icon: Icon(
Icons.menu,
color: Colors.white,
),
onClick: () {
if (animationController.isCompleted) {
animationController.reverse();
} else {
animationController.forward();
}
},
),
)
],
))
],
),
);
}
}
class CircularButton extends StatelessWidget {
final double width;
final double height;
final Color color;
final Icon icon;
final Function onClick;
CircularButton(
{this.color, this.width, this.height, this.icon, this.onClick});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
width: width,
height: height,
child: IconButton(icon: icon, enableFeedback: true, onPressed: onClick),
);
}
}
内容不可见,因为您正在为自定义 FAB 使用脚手架
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
//import 'constants.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Mandaboo',
theme: ThemeData(
),
home: MyHomePage(
),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text('hi i\'m content'),),
floatingActionButton: CustomFAB(),
);
}
}
class CustomFAB extends StatefulWidget {
@override
_CustomFABState createState() => _CustomFABState();
}
class _CustomFABState extends State<CustomFAB> with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation degOneTranslationAnimation,degTwoTranslationAnimation,degThreeTranslationAnimation, degFourTranslationAnimation;
Animation rotationAnimation;
double getRadiansFromDegree(double degree) {
double unitRadian = 57.295779513;
return degree / unitRadian;
}
@override
void initState() {
animationController = AnimationController(vsync: this,duration: Duration(milliseconds: 250));
degOneTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.2), weight: 75.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.2,end: 1.0), weight: 25.0),
]).animate(animationController);
degTwoTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.4), weight: 55.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.4,end: 1.0), weight: 45.0),
]).animate(animationController);
degThreeTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 1.75), weight: 35.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 1.75,end: 1.0), weight: 65.0),
]).animate(animationController);
degFourTranslationAnimation = TweenSequence([
TweenSequenceItem<double>(tween: Tween<double >(begin: 0.0,end: 2.10), weight: 15.0),
TweenSequenceItem<double>(tween: Tween<double>(begin: 2.10,end: 1.0), weight: 85.0),
]).animate(animationController);
rotationAnimation = Tween<double>(begin: 180.0,end: 0.0).animate(CurvedAnimation(parent: animationController
, curve: Curves.easeOut));
super.initState();
animationController.addListener((){
setState(() {
});
});
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
width: size.width,
height: size.height,
child: Stack(
children: <Widget>[
Positioned(
right: 30,
bottom: 30,
child: Stack(
alignment: Alignment.bottomRight,
children: <Widget>[
IgnorePointer(
child: Container(
color: Colors.white.withOpacity(0.0), // comment or change to transparent color
height: 150.0,
width: 150.0,
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(270),degOneTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degOneTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 40,
height: 40,
icon: Icon(
Icons.add,
color: Colors.white,
),
onClick: (){
print('First Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(240),degTwoTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degTwoTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.shop_two,
color: Colors.white,
),
onClick: (){
print('Second button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(210),degThreeTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degThreeTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.equalizer,
color: Colors.white,
),
onClick: (){
print('Third Button');
},
),
),
),
Transform.translate(
offset: Offset.fromDirection(getRadiansFromDegree(180),degFourTranslationAnimation.value * 100),
child: Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value))..scale(degFourTranslationAnimation.value),
alignment: Alignment.center,
child: CircularButton(
color: Colors.black54,
width: 40,
height: 40,
icon: Icon(
Icons.settings,
color: Colors.white,
),
onClick: (){
print('Fourth Button');
},
),
),
),
Transform(
transform: Matrix4.rotationZ(getRadiansFromDegree(rotationAnimation.value)),
alignment: Alignment.center,
child: CircularButton(
color: Colors.red,
width: 60,
height: 60,
icon: Icon(
Icons.menu,
color: Colors.white,
),
onClick: (){
if (animationController.isCompleted) {
animationController.reverse();
} else {
animationController.forward();
}
},
),
)
],
))
],
),
);
}
}
class CircularButton extends StatelessWidget {
final double width;
final double height;
final Color color;
final Icon icon;
final Function onClick;
CircularButton({this.color, this.width, this.height, this.icon, this.onClick});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: color,shape: BoxShape.circle),
width: width,
height: height,
child: IconButton(icon: icon,enableFeedback: true, onPressed: onClick),
);
}
}