I have an example of a FloatingActionButton working multiple but I don't know how to add it onPressed to it.
I found on the form of the following topic:
https://stackoverflow.com/a/46480722/14451514
In the example there are three icons I need to know how I can onPressed it how I do that?
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController _controller;
static const List<IconData> icons = const [ Icons.sms, Icons.mail, Icons.phone ];
#override
void initState() {
_controller = new AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
}
Widget build(BuildContext context) {
Color backgroundColor = Theme.of(context).cardColor;
Color foregroundColor = Theme.of(context).accentColor;
return new Scaffold(
appBar: new AppBar(title: new Text('Speed Dial Example')),
floatingActionButton: new Column(
mainAxisSize: MainAxisSize.min,
children: new List.generate(icons.length, (int index) {
Widget child = new Container(
height: 70.0,
width: 56.0,
alignment: FractionalOffset.topCenter,
child: new ScaleTransition(
scale: new CurvedAnimation(
parent: _controller,
curve: new Interval(
0.0,
1.0 - index / icons.length / 2.0,
curve: Curves.easeOut
),
),
child: new FloatingActionButton(
heroTag: null,
backgroundColor: backgroundColor,
mini: true,
child: new Icon(icons[index], color: foregroundColor),
onPressed: () {},
),
),
);
return child;
}).toList()..add(
new FloatingActionButton(
heroTag: null,
child: new AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget child) {
return new Transform(
transform: new Matrix4.rotationZ(_controller.value * 0.5 * math.pi),
alignment: FractionalOffset.center,
child: new Icon(_controller.isDismissed ? Icons.share : Icons.close),
);
},
),
onPressed: () {
if (_controller.isDismissed) {
_controller.forward();
} else {
_controller.reverse();
}
},
),
),
),
);
}
}
If anyone knows the solution to that problem please help me
I would suggest you to add a FAB Onpress button, use this github program.
Speed Dail Floating Action Bar
https://github.com/tiagojencmartins/unicornspeeddial
A List (Array) of functions can help you here, you have an index of the current item just get the function from List by index and call it onPress.
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController _controller;
static const List<IconData> icons = const [
Icons.sms,
Icons.mail,
Icons.phone
];
static method1() {
print('method 1');
}
static method2() {
print('method 2');
}
static method3() {
print('method 3');
}
List<Function> methods = [method1, method2, method3];
#override
void initState() {
_controller = new AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
}
Widget build(BuildContext context) {
Color backgroundColor = Theme.of(context).cardColor;
Color foregroundColor = Theme.of(context).accentColor;
return new Scaffold(
appBar: new AppBar(title: new Text('Speed Dial Example')),
floatingActionButton: new Column(
mainAxisSize: MainAxisSize.min,
children: new List.generate(icons.length, (int index) {
Widget child = new Container(
height: 70.0,
width: 56.0,
alignment: FractionalOffset.topCenter,
child: new ScaleTransition(
scale: new CurvedAnimation(
parent: _controller,
curve: new Interval(0.0, 1.0 - index / icons.length / 2.0,
curve: Curves.easeOut),
),
child: new FloatingActionButton(
heroTag: null,
backgroundColor: backgroundColor,
mini: true,
child: new Icon(icons[index], color: foregroundColor),
onPressed: () {
methods[index]();
},
),
),
);
return child;
}).toList()
..add(
new FloatingActionButton(
heroTag: null,
child: new AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget child) {
return new Transform(
transform: new Matrix4.rotationZ(
_controller.value * 0.5 * math.pi),
alignment: FractionalOffset.center,
child: new Icon(
_controller.isDismissed ? Icons.share : Icons.close),
);
},
),
onPressed: () {
if (_controller.isDismissed) {
_controller.forward();
} else {
_controller.reverse();
}
},
),
),
),
);
}
}
try this out
You need to extend your IconData list to a model that contains Function. It will look something like this:
class NewModel {
IconData iconData;
Function func;
}
And then:
static const List<NewModel> iconsWithFunc =
[
/* Your Items with OnPressed Functions */
];
After that you can use it easily:
child: new FloatingActionButton(
heroTag: null,
backgroundColor: backgroundColor,
mini: true,
child: new Icon(iconsWithFunc[index].iconData, color: foregroundColor),
// Use it in here.
onPressed: iconsWithFunc[index].func,
),
Related
Here i have a simple animated dialog which with that i can show one screen into that. this screen into animated dialog sending request on appearing into dialog and can be receive data from server without any problem. but when i drag this dialog on top of screen to get full width and height i get this error:
This UncontrolledProviderScope widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
in fact i think this screen send multiple request when appear into dialog and when its shows as a new screen instance
problem is
ref.read(profileProvider.notifier).send(
method: HTTP.POST,
endPoint: Server.$userProfile,
parameters: {
'uuid': '123',
},
);
into MyProfile class
Full source code:
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:my_app/core/service/server.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'core/service/repository/request_repository.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(
ProviderScope(child: MyApp()),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: MyHome(),
);
}
}
class MyHome extends HookConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
GestureDetector(
onLongPress: () {
showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: "hi",
// barrierColor: Colors.black.withOpacity(0.2),
// transitionDuration: Duration(milliseconds: 500),
pageBuilder: (context, pAnim, sAnim) {
return const SafeArea(
child: FloatingDialog(
previewType: PreviewDialogsType.profile,
));
},
transitionBuilder: (context, pAnim, sAnim, child) {
if (pAnim.status == AnimationStatus.reverse) {
return FadeTransition(
opacity: Tween(begin: 0.0, end: 0.0).animate(pAnim),
child: child,
);
} else {
return FadeTransition(
opacity: pAnim,
child: child,
);
}
},
);
},
child: Container(
width: double.infinity,
height: 50.0,
color: Colors.indigoAccent,
child: const Text('LongPress please'),
),
),
],
),
);
}
}
enum PreviewDialogsType {
profile,
}
class FloatingDialog extends StatefulWidget {
final PreviewDialogsType previewType;
const FloatingDialog({super.key, required this.previewType});
#override
_FloatingDialogState createState() => _FloatingDialogState();
}
class _FloatingDialogState extends State<FloatingDialog> with TickerProviderStateMixin {
late double _dragStartYPosition;
late double _dialogYOffset;
late AnimationController _returnBackController;
late Animation<double> _dialogAnimation;
#override
void initState() {
super.initState();
_dialogYOffset = 0.0;
_returnBackController = AnimationController(vsync: this, duration: const Duration(milliseconds: 1300))
..addListener(() {
setState(() {
_dialogYOffset = _dialogAnimation.value;
});
});
}
#override
void dispose() {
_returnBackController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
Widget myContents = PreviewDialog(
type: widget.previewType,
);
return Padding(
padding: const EdgeInsets.only(
top: 100.0,
bottom: 10.0,
left: 16.0,
right: 16.0,
),
child: Transform.translate(
offset: Offset(0.0, _dialogYOffset),
child: Column(
children: <Widget>[
const Icon(
Icons.keyboard_arrow_up,
color: Colors.white,
size: 30.0,
),
Expanded(
child: GestureDetector(
onVerticalDragStart: (dragStartDetails) {
_dragStartYPosition = dragStartDetails.globalPosition.dy;
},
onVerticalDragUpdate: (dragUpdateDetails) {
setState(() {
_dialogYOffset = (dragUpdateDetails.globalPosition.dy) - _dragStartYPosition;
});
if (_dialogYOffset < -130) {
Navigator.of(context).pop();
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, pAnim, sAnim) => myContents,
transitionDuration: const Duration(milliseconds: 500),
transitionsBuilder: (context, pAnim, sAnim, child) {
if (pAnim.status == AnimationStatus.forward) {
return ScaleTransition(
scale: Tween(begin: 0.8, end: 1.0)
.animate(CurvedAnimation(parent: pAnim, curve: Curves.elasticOut)),
child: child,
);
} else {
return child;
}
}),
);
}
},
onVerticalDragEnd: (dragEndDetails) {
_dialogAnimation = Tween(begin: _dialogYOffset, end: 0.0)
.animate(CurvedAnimation(parent: _returnBackController, curve: Curves.elasticOut));
_returnBackController.forward(from: _dialogYOffset);
_returnBackController.forward(from: 0.0);
},
child: myContents,
),
),
],
),
),
);
}
}
class PreviewDialog extends StatefulWidget {
final PreviewDialogsType type;
final String? uuid;
const PreviewDialog({Key? key, required this.type, this.uuid}) : super(key: key);
#override
State<PreviewDialog> createState() => _PreviewDialogState();
}
class _PreviewDialogState extends State<PreviewDialog> {
late ScrollController scrollController;
#override
void initState() {
super.initState();
scrollController = ScrollController();
}
#override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: Scaffold(
body: MyProfile(),
),
),
);
}
}
class MyProfile extends HookConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
useEffect(() {
ref.read(profileProvider.notifier).send(
method: HTTP.POST,
endPoint: Server.$userProfile,
parameters: {
'uuid': '123',
},
);
return () {};
}, []);
return SafeArea(
child: Scaffold(
body: Container(
width: double.infinity,
height:double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ref.watch(profileProvider).when(
idle: () => const SizedBox(),
loading: () => const CircularProgressIndicator(),
success: (success) {
return const Text('successful');
},
error: (error, stackTrace) {
return Text('error');
},
)
],
),
),
),
);
}
}
I want to animate the height of my AppBar in Flutter using NotificationListener & ScrollController, but it doesn't seem to work. I know i'm missing something, i need help figuring it out.
Here's what i have,
class SampleApp extends StatefulWidget {
#override
_SampleAppState createState() => _SampleAppState();
}
class _SampleAppState extends State<SampleApp> with TickerProviderStateMixin {
Animation<double> animation;
AnimationController _controller;
ScrollController _scrollController;
#override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(milliseconds: 240));
animation = Tween(begin: kToolbarHeight, end: 0.0).animate(_controller);
_scrollController = ScrollController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
child: Container(color: Colors.red),
preferredSize: Size.fromHeight(animation.value),
),
bottomNavigationBar: Container(height: animation.value, color: Colors.red),
floatingActionButton: Container(
width: 50.0,
height: 50.0,
child: Center(
child: FittedBox(
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.arrow_upward),
),
),
),
),
body: NotificationListener(
onNotification: (notification) {
if (_scrollController.position.userScrollDirection == ScrollDirection.reverse) {
_controller.forward();
return true;
}
if (_scrollController.position.userScrollDirection == ScrollDirection.forward) {
_controller.reverse();
return true;
}
return false;
},
child: ListView(
controller: _scrollController,
children: List.generate(
200,
(index) => ListTile(
title: Text(index.toString()),
),
),
),
),
);
}
}
It should be that if user scrolls down, i want the appbar height and bottom bar height to be animated (reduce) & vice versa if user scrolls up.
You can copy paste run full code below
You need the following
animation.addListener(() {
setState(() {});
});
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: SampleApp(),
);
}
}
class SampleApp extends StatefulWidget {
#override
_SampleAppState createState() => _SampleAppState();
}
class _SampleAppState extends State<SampleApp> with TickerProviderStateMixin {
Animation<double> animation;
AnimationController _controller;
ScrollController _scrollController;
#override
void initState() {
super.initState();
print("$kToolbarHeight");
_controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 240));
animation = Tween(begin: kToolbarHeight, end: 0.0).animate(_controller);
_scrollController = ScrollController();
animation.addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
child: Container(color: Colors.red),
preferredSize: Size.fromHeight(animation.value),
),
bottomNavigationBar:
Container(height: animation.value, color: Colors.red),
floatingActionButton: Container(
width: 50.0,
height: 50.0,
child: Center(
child: FittedBox(
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.arrow_upward),
),
),
),
),
body: NotificationListener(
onNotification: (notification) {
if (_scrollController.position.userScrollDirection ==
ScrollDirection.reverse) {
print("reverse");
_controller.forward();
return true;
}
if (_scrollController.position.userScrollDirection ==
ScrollDirection.forward) {
print("forward");
_controller.reverse();
return true;
}
return false;
},
child: ListView(
controller: _scrollController,
children: List.generate(
200,
(index) => ListTile(
title: Text(index.toString()),
),
),
),
),
);
}
}
I didn't find any example for constructor CupertinoFullscreenDialogTransition
https://api.flutter.dev/flutter/cupertino/CupertinoFullscreenDialogTransition-class.html
I tried to understand below code but I didn't get it.
CupertinoFullscreenDialogTransition({
Key key,
#required Animation<double> animation,
#required this.child,
}) : _positionAnimation = CurvedAnimation(
parent: animation,
curve: Curves.linearToEaseOut,
// The curve must be flipped so that the reverse animation doesn't play
// an ease-in curve, which iOS does not use.
reverseCurve: Curves.linearToEaseOut.flipped,
).drive(_kBottomUpTween),
super(key: key);
Here's a more complete example
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
static const String _title = 'AppBar tutorial';
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Colors.blue[900],
appBarTheme: AppBarTheme(iconTheme: IconThemeData(color: Colors.white)),
),
title: _title,
home: CupertinoFullscreenDialogTransitionPage(),
);
}
}
//First Page
class CupertinoFullscreenDialogTransitionPage extends StatefulWidget {
#override
_CupertinoFullscreenDialogTransitionState createState() =>
_CupertinoFullscreenDialogTransitionState();
}
class _CupertinoFullscreenDialogTransitionState
extends State<CupertinoFullscreenDialogTransitionPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(60),
child: AppBar(
title: Text("Cupertino Screen Transition"),
centerTitle: true,
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CupertinoButton.filled(
child: Text("Next Page Cupertino Transition"),
onPressed: () => Navigator.of(context).push(
PageRouteBuilder(
opaque: false,
pageBuilder: (context, _, __) {
return FullDialogPage();
},
),
),
),
],
)),
);
}
}
//Second Page
class FullDialogPage extends StatefulWidget {
#override
_FullDialogPageState createState() => _FullDialogPageState();
}
class _FullDialogPageState extends State<FullDialogPage>
with TickerProviderStateMixin {
AnimationController _primary, _secondary;
Animation<double> _animationPrimary, _animationSecondary;
#override
void initState() {
//Primaty
_primary = AnimationController(vsync: this, duration: Duration(seconds: 1));
_animationPrimary = Tween<double>(begin: 0, end: 1)
.animate(CurvedAnimation(parent: _primary, curve: Curves.easeOut));
//Secondary
_secondary =
AnimationController(vsync: this, duration: Duration(seconds: 1));
_animationSecondary = Tween<double>(begin: 0, end: 1)
.animate(CurvedAnimation(parent: _secondary, curve: Curves.easeOut));
_primary.forward();
super.initState();
}
#override
void dispose() {
_primary.dispose();
_secondary.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return CupertinoFullscreenDialogTransition(
primaryRouteAnimation: _animationPrimary,
secondaryRouteAnimation: _animationSecondary,
linearTransition: false,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.indigo[900],
title: Text("Testing"),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
_primary.reverse();
Future.delayed(Duration(seconds: 1), () {
Navigator.of(context).pop();
});
},
),
),
),
);
}
}
I've made this simple example, I hope it helps you understand how to implement the CupertinoFullscreenDialogTransition Widget.
import 'package:flutter/cupertino.dart';
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.orange,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{
AnimationController _animationController;
#override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500),
);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Stackoverflow playground'),
),
body: Container(
child: Column(
children: <Widget>[
CupertinoFullscreenDialogTransition(
primaryRouteAnimation: _animationController,
secondaryRouteAnimation: _animationController,
linearTransition: false,
child: Center(
child: Container(
color: Colors.blueGrey,
width: 300,
height: 300,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
RaisedButton(
onPressed: () => _animationController.forward(),
child: Text('Forward'),
),
RaisedButton(
onPressed: () => _animationController.reverse(),
child: Text('Reverse'),
),
],
),
],
),
)
);
}
}
in this simple code, i try to show and hide barrier on top of widgets,showing this barrier can be have with animation, but when i try to close and hide that, controller.reverse() doesn't have any animation to hide
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: BarrierEffect(),
));
class BarrierEffect extends StatefulWidget {
#override
State<BarrierEffect> createState() => _BarrierEffect();
}
class _BarrierEffect extends State<BarrierEffect> with TickerProviderStateMixin {
var isShownBarrier = false;
AnimationController controller;
Animation<double> animation;
#override
void initState() {
super.initState();
controller = AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);
animation.addStatusListener((status) {
if (status == AnimationStatus.completed) {
controller.reverse();
setState(() {
isShownBarrier = false;
});
} else if (status == AnimationStatus.dismissed) {
controller.forward();
setState(() {
isShownBarrier = true;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Stack(
children: <Widget>[
Center(
child: RaisedButton(
color: Colors.white,
child: Text('show barrier'),
onPressed: () => controller.forward(),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0))),
),
Visibility(
visible: isShownBarrier ? true : false,
child: FadeTransition(
opacity: animation,
child: Container(
color: Colors.black.withOpacity(0.5),
child: Center(child: Text('test')),
),
),
)
],
),
),
);
}
}
Is this what you are looking for?
Full code:
void main() => runApp(MaterialApp(home: BarrierEffect()));
class BarrierEffect extends StatefulWidget {
#override
State<BarrierEffect> createState() => _BarrierEffect();
}
class _BarrierEffect extends State<BarrierEffect> with TickerProviderStateMixin {
AnimationController controller;
#override
void initState() {
super.initState();
controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: AnimatedBuilder(
animation: controller,
builder: (_, child) {
return Stack(
children: <Widget>[
Center(
child: RaisedButton(
child: Text('Show Barrier'),
onPressed: () => controller.repeat(reverse: true),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)),
),
),
Visibility(
visible: controller.value != 0,
child: Opacity(
opacity: controller.value,
child: Container(
color: Colors.black.withOpacity(0.9),
child: Center(child: Text('My Barrier', style: TextStyle(color: Colors.white))),
),
),
)
],
);
},
),
);
}
}
is any solution to make drag and drop dialogs in flutter? for example after showing dialog in center of screen i would like to drag it to top of screen to make fullscreen dialog over current cover, for example this code is simple implementation to show dialog and i'm not sure, how can i do that
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(title: 'Flutter Demo', theme: ThemeData(), home: Page());
}
}
class Page extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton.icon(
onPressed: () {
showDialog(
context: context,
builder: (_) => FunkyOverlay(),
);
},
icon: Icon(Icons.message),
label: Text("PopUp!")),
),
);
}
}
class FunkyOverlay extends StatefulWidget {
#override
State<StatefulWidget> createState() => FunkyOverlayState();
}
class FunkyOverlayState extends State<FunkyOverlay>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> scaleAnimation;
#override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 450));
scaleAnimation =
CurvedAnimation(parent: controller, curve: Curves.elasticInOut);
controller.addListener(() {
setState(() {});
});
controller.forward();
}
#override
Widget build(BuildContext context) {
return Center(
child: Material(
color: Colors.transparent,
child: ScaleTransition(
scale: scaleAnimation,
child: Container(
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0))),
child: Padding(
padding: const EdgeInsets.all(50.0),
child: Text("Well hello there!"),
),
),
),
),
);
}
}
This is one way to do it ,
import 'package:flutter/material.dart';
main() {
runApp(MaterialApp(
theme: ThemeData(
primarySwatch: Colors.indigo,
),
home: App(),
));
}
class App extends StatefulWidget {
#override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.open_in_new),
onPressed: () {
showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: "hi",
barrierColor: Colors.black.withOpacity(0.2),
transitionDuration: Duration(milliseconds: 500),
pageBuilder: (context, pAnim, sAnim) {
return SafeArea(child: FloatingDialog());
},
transitionBuilder: (context, pAnim, sAnim, child) {
if (pAnim.status == AnimationStatus.reverse) {
return FadeTransition(
opacity: Tween(begin: 0.0, end: 0.0).animate(pAnim),
child: child,
);
} else {
return FadeTransition(
opacity: pAnim,
child: child,
);
}
},
);
},
),
);
}
}
class FloatingDialog extends StatefulWidget {
#override
_FloatingDialogState createState() => _FloatingDialogState();
}
class _FloatingDialogState extends State<FloatingDialog>
with TickerProviderStateMixin {
double _dragStartYPosition;
double _dialogYOffset;
Widget myContents = MyScaffold();
AnimationController _returnBackController;
Animation<double> _dialogAnimation;
#override
void initState() {
super.initState();
_dialogYOffset = 0.0;
_returnBackController =
AnimationController(vsync: this, duration: Duration(milliseconds: 1300))
..addListener(() {
setState(() {
_dialogYOffset = _dialogAnimation.value;
print(_dialogYOffset);
});
});
}
#override
void dispose() {
_returnBackController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
top: 100.0,
bottom: 10.0,
left: 10.0,
right: 10.0,
),
child: Transform.translate(
offset: Offset(0.0, _dialogYOffset),
child: Column(
children: <Widget>[
Icon(
Icons.keyboard_arrow_up,
color: Colors.white,
),
Expanded(
child: GestureDetector(
onVerticalDragStart: (dragStartDetails) {
_dragStartYPosition = dragStartDetails.globalPosition.dy;
print(dragStartDetails.globalPosition);
},
onVerticalDragUpdate: (dragUpdateDetails) {
setState(() {
_dialogYOffset = (dragUpdateDetails.globalPosition.dy) -
_dragStartYPosition;
});
print(_dialogYOffset);
if (_dialogYOffset < -90.0) {
Navigator.of(context).pop();
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, pAnim, sAnim) => myContents,
transitionDuration: Duration(milliseconds: 500),
transitionsBuilder: (context, pAnim, sAnim, child) {
if (pAnim.status == AnimationStatus.forward) {
return ScaleTransition(
scale: Tween(begin: 0.8, end: 1.0).animate(
CurvedAnimation(
parent: pAnim,
curve: Curves.elasticOut)),
child: child,
);
} else {
return FadeTransition(
opacity: pAnim,
child: child,
);
}
}),
);
}
},
onVerticalDragEnd: (dragEndDetails) {
_dialogAnimation = Tween(begin: _dialogYOffset, end: 0.0)
.animate(CurvedAnimation(
parent: _returnBackController,
curve: Curves.elasticOut));
_returnBackController.forward(from: _dialogYOffset);
_returnBackController.forward(from: 0.0);
},
child: myContents,
),
),
],
),
),
);
}
}
class MyScaffold extends StatelessWidget {
const MyScaffold({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Channels"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(),
body: Placeholder(),
),
),
);
},
),
),
);
}
}
Output:
You can try this.
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool _shown = false;
double _topOffset = 20, _dialogHeight = 400;
Duration _duration = Duration(milliseconds: 400);
Offset _offset, _initialOffset;
#override
void didChangeDependencies() {
super.didChangeDependencies();
var size = MediaQuery.of(context).size;
_offset = Offset(size.width, (size.height - _dialogHeight) / 2);
_initialOffset = _offset;
}
#override
Widget build(BuildContext context) {
var appBarColor = Colors.blue[800];
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () => setState(() => _shown = !_shown)),
body: SizedBox.expand(
child: Stack(
children: <Widget>[
Container(
color: appBarColor,
child: SafeArea(
bottom: false,
child: Align(
child: Column(
children: <Widget>[
MyAppBar(
title: "Image",
color: appBarColor,
icon: Icons.home,
onPressed: () {},
),
Expanded(child: Image.asset("assets/images/landscape.jpeg", fit: BoxFit.cover)),
],
),
),
),
),
AnimatedOpacity(
opacity: _shown ? 1 : 0,
duration: _duration,
child: Material(
elevation: 8,
color: Colors.grey[900].withOpacity(0.5),
child: _shown
? GestureDetector(
onTap: () => setState(() => _shown = !_shown),
child: Container(color: Colors.transparent, child: SizedBox.expand()),
)
: SizedBox.shrink(),
),
),
// this shows our dialog
Positioned(
top: _offset.dy,
left: 10,
right: 10,
height: _shown ? null : 0,
child: AnimatedOpacity(
duration: _duration,
opacity: _shown ? 1 : 0,
child: GestureDetector(
onPanUpdate: (details) => setState(() => _offset += details.delta),
onPanEnd: (details) {
// when tap is lifted and current y position is less than set _offset, navigate to the next page
if (_offset.dy < _topOffset) {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, anim1, anim2) => Screen2(),
transitionDuration: _duration,
transitionsBuilder: (context, anim1, anim2, child) {
bool isForward = anim1.status == AnimationStatus.forward;
Tween<double> tween = Tween(begin: isForward ? 0.9 : 0.5, end: 1);
return ScaleTransition(
scale: tween.animate(
CurvedAnimation(
parent: anim1,
curve: isForward ? Curves.bounceOut : Curves.easeOut,
),
),
child: child,
);
},
),
).then((_) {
_offset = _initialOffset;
});
}
// make the dialog come back to the original position
else {
Timer.periodic(Duration(milliseconds: 5), (timer) {
if (_offset.dy < _initialOffset.dy - _topOffset) {
_offset = Offset(_offset.dx, _offset.dy + 15);
setState(() {});
} else if (_offset.dy > _initialOffset.dy + _topOffset) {
_offset = Offset(_offset.dx, _offset.dy - 15);
setState(() {});
} else
timer.cancel();
});
}
},
child: Column(
children: <Widget>[
Icon(Icons.keyboard_arrow_up, color: Colors.white, size: 32),
Hero(
tag: "MyTag",
child: SizedBox(
height: _dialogHeight, // makes sure we don't exceed than our specified height
child: SingleChildScrollView(child: CommonWidget(appBar: MyAppBar(title: "FlutterLogo", color: Colors.orange))),
),
),
],
),
),
),
),
],
),
),
);
}
}
// this app bar is used in 1st and 2nd screen
class MyAppBar extends StatelessWidget {
final String title;
final Color color;
final IconData icon;
final VoidCallback onPressed;
const MyAppBar({Key key, #required this.title, #required this.color, this.icon, this.onPressed}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: kToolbarHeight,
color: color,
width: double.maxFinite,
alignment: Alignment.centerLeft,
child: Row(
children: <Widget>[
icon != null ? IconButton(icon: Icon(icon), onPressed: onPressed, color: Colors.white,) : SizedBox(width: 16),
Text(
title,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white),
),
],
),
);
}
}
// this is the one which is shown in both Dialog and Screen2
class CommonWidget extends StatelessWidget {
final bool isFullscreen;
final Widget appBar;
const CommonWidget({Key key, this.isFullscreen = false, this.appBar}) : super(key: key);
#override
Widget build(BuildContext context) {
var child = Container(
width: double.maxFinite,
color: Colors.blue,
child: FlutterLogo(size: 300, colors: Colors.orange),
);
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
appBar,
isFullscreen ? Expanded(child: child) : child,
],
);
}
}
class Screen2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
var appBarColor = Colors.orange;
return Scaffold(
body: Container(
color: appBarColor,
child: SafeArea(
bottom: false,
child: CommonWidget(
isFullscreen: true,
appBar: MyAppBar(
title: "FlutterLogo",
color: appBarColor,
icon: Icons.arrow_back,
onPressed: () => Navigator.pop(context),
),
),
),
),
);
}
}