问题
By this simple code I can show dialog on bottom of screen like with this screenshot:
But I have three simple issue:
- set margin on bottom of dialog such as
20.0
on showing dialog - using
controller.reverse()
on dismiss dialog - dismiss dialog on click on outside of dialog
Full source code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void showPopup() {
showDialog(
context: context,
builder: (_) => PopUp(),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: showPopup,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class PopUp extends StatefulWidget {
@override
State<StatefulWidget> createState() => PopUpState();
}
class PopUpState extends State<PopUp> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> opacityAnimation;
Tween<double> opacityTween = Tween<double>(begin: 0.0, end: 1.0);
Tween<double> marginTopTween = Tween<double>(begin: 300, end: 280);
Animation<double> marginTopAnimation;
@override
void initState() {
super.initState();
controller = AnimationController(duration: const Duration(milliseconds: 300), vsync: this);
marginTopAnimation = marginTopTween.animate(controller)
..addListener(() {
setState(() {});
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: opacityTween.animate(controller),
child: Material(
color: Colors.transparent,
child: Container(
margin: EdgeInsets.only(
top: marginTopAnimation.value,
left:20.0,
right:20.0,
),
color: Colors.red,
child: Text("Container"),
),
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
回答1:
Screenshot:
Code:
floatingActionButton: FloatingActionButton(
onPressed: () {
showGeneralDialog(
barrierLabel: "Label",
barrierDismissible: true,
barrierColor: Colors.black.withOpacity(0.5),
transitionDuration: Duration(milliseconds: 700),
context: context,
pageBuilder: (context, anim1, anim2) {
return Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 300,
child: SizedBox.expand(child: FlutterLogo()),
margin: EdgeInsets.only(bottom: 50, left: 12, right: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(40),
),
),
);
},
transitionBuilder: (context, anim1, anim2, child) {
return SlideTransition(
position: Tween(begin: Offset(0, 1), end: Offset(0, 0)).animate(anim1),
child: child,
);
},
);
},
)
回答2:
Output:
Not sure if I got your question clearly, if this is what you are looking for, replace your PopUp
class with mine.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void showPopup() {
showDialog(
context: context,
builder: (_) => PopUp(),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: showPopup,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class PopUp extends StatefulWidget {
@override
State<StatefulWidget> createState() => PopUpState();
}
class PopUpState extends State<PopUp> with TickerProviderStateMixin {
AnimationController controller;
double _bottom = 0, _fromTop = 300, _screenHeight, _containerHeight = 300;
@override
void initState() {
super.initState();
controller = AnimationController(duration: const Duration(milliseconds: 300), vsync: this)
..addListener(() {
Timer.periodic(Duration(milliseconds: 15), (timer) {
if (_bottom < _screenHeight - _fromTop - _containerHeight) {
_bottom += 1;
setState(() {});
}
});
});
controller.forward();
}
@override
Widget build(BuildContext context) {
_screenHeight = MediaQuery.of(context).size.height;
return SizedBox(
width: double.infinity,
height: double.infinity,
child: Stack(
children: <Widget>[
Positioned(
bottom: _bottom,
left: 0,
right: 0,
child: Container(height: _containerHeight, color: Colors.green),
),
],
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
回答3:
From top to bottom you can use
bool _fromTop = true;
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
showGeneralDialog(
barrierLabel: "Label",
barrierDismissible: true,
barrierColor: Colors.black.withOpacity(0.5),
transitionDuration: Duration(milliseconds: 700),
context: context,
pageBuilder: (context, anim1, anim2) {
return Align(
alignment: _fromTop ? Alignment.topCenter : Alignment.bottomCenter,
child: Container(
height: 300,
child: SizedBox.expand(child: FlutterLogo()),
margin: EdgeInsets.only(top: 50, left: 12, right: 12, bottom: 50),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(40),
),
),
);
},
transitionBuilder: (context, anim1, anim2, child) {
return SlideTransition(
position: Tween(begin: Offset(0, _fromTop ? -1 : 1), end: Offset(0, 0)).animate(anim1),
child: child,
);
},
);
},
),
);
}
来源:https://stackoverflow.com/questions/57131978/how-to-animate-alert-dialog-position-in-flutter