在 BottomSheet 中实现转换
Implementing transitions in a BottomSheet
我正在尝试实现以下设计,但我似乎无法理解我应该采用的方式:P
我正在考虑使用通过 showModalBottomSheet
函数显示的 BottomSheet
,但我不知道如何实现转换(我会使用 FadeTransition
淡入淡出效果,虽然不知道高度变化效果)
到目前为止我得到了什么:
import 'package:flutter/material.dart';
import 'dart:math';
class Setup extends StatefulWidget {
final Widget child;
const Setup(this.child);
@override
_SetupState createState() => _SetupState();
}
class MyCurve extends Curve {
@override
double transform(double t) => -pow(t, 2) + 1;
}
class _SetupState extends State<Setup> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> opacityAnimation;
int i = 0;
@override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 500));
opacityAnimation = CurvedAnimation(
parent: Tween<double>(begin: 1, end: 0).animate(_controller),
curve: Curves.easeInOutExpo);
}
@override
Widget build(BuildContext context) {
return BottomSheet(
enableDrag: false,
elevation: 16,
backgroundColor: Colors.transparent,
builder: (_) => Container(
margin: EdgeInsets.all(8),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(16)),
child: Material(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16)),
child: FadeTransition(
opacity: opacityAnimation,
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
widget.child,
Container(
height: 10,
),
RaisedButton(
child: Text("Next"),
onPressed: () {
_controller.forward().then((_) {
_controller.reverse();
});
},
)
],
)),
)),
),
onClosing: () {},
);
}
}
如您所见,我刚刚使淡入淡出动画正常工作,并完成了 none 路由或高度转换。
由于 BottomNavigationSheet 的高度基于其内容的高度,因此您可以轻松地为其设置动画。
使用 BottomSheet 中的 Container 并为其指定所需的高度。高度本身可以通过创建一个 AnimationController 来设置动画,将 begin 和 end 设置为您想要的高度值并设置状态。然后用 opacity-animation.
开始动画
containerHeight = CurvedAnimation(
parent: Tween<double>(begin: 350, end: 200).animate(_controller)..addListener(() {setState(() {});});,
curve: Curves.easeInOutExpo);
这应该可以完成工作。
既然可以使用 AnimatedContainer
和 AnimateCrossFade
.
实现相同的效果,为什么还要复杂化呢?
仅供参考
class BS extends StatefulWidget {
_BS createState() => _BS();
}
class _BS extends State<BS> {
bool _showSecond = false;
@override
Widget build(BuildContext context) {
return BottomSheet(
onClosing: () {},
builder: (BuildContext context) => AnimatedContainer(
margin: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(30)),
child: AnimatedCrossFade(
firstChild: Container(
constraints: BoxConstraints.expand(
height: MediaQuery.of(context).size.height - 200),
//remove constraint and add your widget hierarchy as a child for first view
padding: EdgeInsets.all(20),
child: Align(
alignment: Alignment.bottomCenter,
child: RaisedButton(
onPressed: () => setState(() => _showSecond = true),
padding: EdgeInsets.all(15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Suivant"),
],
),
),
),
),
secondChild: Container(
constraints: BoxConstraints.expand(
height: MediaQuery.of(context).size.height / 3),
//remove constraint and add your widget hierarchy as a child for second view
padding: EdgeInsets.all(20),
child: Align(
alignment: Alignment.bottomCenter,
child: RaisedButton(
onPressed: () => setState(() => _showSecond = false),
color: Colors.green,
padding: EdgeInsets.all(15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("ok"),
],
),
),
),
),
crossFadeState: _showSecond
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
duration: Duration(milliseconds: 400)),
duration: Duration(milliseconds: 400),
),
);
}
}
我正在尝试实现以下设计,但我似乎无法理解我应该采用的方式:P
我正在考虑使用通过 showModalBottomSheet
函数显示的 BottomSheet
,但我不知道如何实现转换(我会使用 FadeTransition
淡入淡出效果,虽然不知道高度变化效果)
到目前为止我得到了什么:
import 'package:flutter/material.dart';
import 'dart:math';
class Setup extends StatefulWidget {
final Widget child;
const Setup(this.child);
@override
_SetupState createState() => _SetupState();
}
class MyCurve extends Curve {
@override
double transform(double t) => -pow(t, 2) + 1;
}
class _SetupState extends State<Setup> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> opacityAnimation;
int i = 0;
@override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 500));
opacityAnimation = CurvedAnimation(
parent: Tween<double>(begin: 1, end: 0).animate(_controller),
curve: Curves.easeInOutExpo);
}
@override
Widget build(BuildContext context) {
return BottomSheet(
enableDrag: false,
elevation: 16,
backgroundColor: Colors.transparent,
builder: (_) => Container(
margin: EdgeInsets.all(8),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(16)),
child: Material(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16)),
child: FadeTransition(
opacity: opacityAnimation,
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
widget.child,
Container(
height: 10,
),
RaisedButton(
child: Text("Next"),
onPressed: () {
_controller.forward().then((_) {
_controller.reverse();
});
},
)
],
)),
)),
),
onClosing: () {},
);
}
}
如您所见,我刚刚使淡入淡出动画正常工作,并完成了 none 路由或高度转换。
由于 BottomNavigationSheet 的高度基于其内容的高度,因此您可以轻松地为其设置动画。
使用 BottomSheet 中的 Container 并为其指定所需的高度。高度本身可以通过创建一个 AnimationController 来设置动画,将 begin 和 end 设置为您想要的高度值并设置状态。然后用 opacity-animation.
开始动画containerHeight = CurvedAnimation(
parent: Tween<double>(begin: 350, end: 200).animate(_controller)..addListener(() {setState(() {});});,
curve: Curves.easeInOutExpo);
这应该可以完成工作。
既然可以使用 AnimatedContainer
和 AnimateCrossFade
.
仅供参考
class BS extends StatefulWidget {
_BS createState() => _BS();
}
class _BS extends State<BS> {
bool _showSecond = false;
@override
Widget build(BuildContext context) {
return BottomSheet(
onClosing: () {},
builder: (BuildContext context) => AnimatedContainer(
margin: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(30)),
child: AnimatedCrossFade(
firstChild: Container(
constraints: BoxConstraints.expand(
height: MediaQuery.of(context).size.height - 200),
//remove constraint and add your widget hierarchy as a child for first view
padding: EdgeInsets.all(20),
child: Align(
alignment: Alignment.bottomCenter,
child: RaisedButton(
onPressed: () => setState(() => _showSecond = true),
padding: EdgeInsets.all(15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Suivant"),
],
),
),
),
),
secondChild: Container(
constraints: BoxConstraints.expand(
height: MediaQuery.of(context).size.height / 3),
//remove constraint and add your widget hierarchy as a child for second view
padding: EdgeInsets.all(20),
child: Align(
alignment: Alignment.bottomCenter,
child: RaisedButton(
onPressed: () => setState(() => _showSecond = false),
color: Colors.green,
padding: EdgeInsets.all(15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("ok"),
],
),
),
),
),
crossFadeState: _showSecond
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
duration: Duration(milliseconds: 400)),
duration: Duration(milliseconds: 400),
),
);
}
}