for implementing this animation
i wrote this below code but, Elastic animation doesn't work on project and i'm not sure whats problem,
i want to have repeat of this animation
import 'package:flutter/material.dart';
void main()=>runApp(MaterialApp(home: Avatar(),));
class Avatar extends StatefulWidget {
#override
State<StatefulWidget> createState()=>_Avatar();
}
class _Avatar extends State<Avatar> with TickerProviderStateMixin{
AnimationController avatarController;
Animation<double> avatarSize;
#override
void initState() {
super.initState();
avatarController= AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
avatarSize = new Tween(begin: 0.0, end: 1.0).animate(
new CurvedAnimation(
parent: avatarController,
curve: new Interval(
0.100,
0.400,
curve: Curves.elasticOut,
),
),
);
avatarController.repeate();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit:StackFit.expand,
children: <Widget>[
AnimatedBuilder(
animation: avatarController,
builder: (context, widget) => Align(
child: Container(
width: 50.0,
height: 50.0,
color:Colors.green
),
),
)
],
),
);
}
}
Output:
You can play with duration and Tween to fine grain it.
void main() => runApp(MaterialApp(home: Avatar()));
class Avatar extends StatefulWidget {
#override
State<StatefulWidget> createState() => _Avatar();
}
class _Avatar extends State<Avatar> with TickerProviderStateMixin {
AnimationController _controller;
Tween<double> _tween = Tween(begin: 0.75, end: 2);
#override
void initState() {
super.initState();
_controller = AnimationController(duration: const Duration(milliseconds: 700), vsync: this);
_controller.repeat(reverse: true);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Align(
child: ScaleTransition(
scale: _tween.animate(CurvedAnimation(parent: _controller, curve: Curves.elasticOut)),
child: SizedBox(
height: 100,
width: 100,
child: CircleAvatar(backgroundImage: AssetImage(chocolateImage)),
),
),
),
],
),
);
}
}
The Tween's begin and end values should be the values you want to animate between. You then need to use the animated value somewhere in your layout.
For example, change your Tween to Tween(begin: 50.0, end: 100.0) and your Container to
Container(
width: avatarSize.value,
height: avatarSize.value,
color:Colors.green
)
Don't forget to also dispose of the animation controller within your widget's dispose():
#override
void dispose() {
avatarController.dispose();
super.dispose();
}
Add this dependency https://pub.dev/packages/animator
Try this code.
class BounceAnimation extends StatefulWidget {
#override
_BounceAnimationState createState() => _BounceAnimationState();
}
class _BounceAnimationState extends State<BounceAnimation>
with SingleTickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(title: Text("Bouncing Animation example")),
body: Center(
child: Container(
child: Animator(
duration: Duration(seconds: 1),
curve: Curves.elasticOut,
builder: (anim) {
return Transform.scale(
origin: Offset(00, -59),
scale: anim.value,
child: Transform.translate(
offset: Offset(00, -65),
child: CircleAvatar(
radius: 86,
backgroundColor: Colors.white,
child: CircleAvatar(
radius: 84,
backgroundColor: Colors.grey,
child: CircleAvatar(
radius: 80,
backgroundColor: Colors.white,
foregroundColor: Colors.black,
backgroundImage: NetworkImage(
"https://i1.wp.com/devilsworkshop.org/wp-content/uploads/sites/8/2013/01/enlarged-facebook-profile-picture.jpg?w=448&ssl=1",
),
),
),
),
),
);
},
)),
),
);
}
}
Related
FadeTransition animation is not working for backdropfilter.
The opacity goes from 0 to 1 suddenly, without the smooth transition that the animation should give.
As you can see from the code below, I have a background image and then a backdropfilter on top to blur the background at app startup.
(I then show other widgets, but the animation is working fine for them).
import 'dart:ui';
import 'package:flutter/material.dart';
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _backgroundOpacity;
bool _visible = true;
#override
void initState() {
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..forward();
// background opacity animation
_backgroundOpacity = Tween<double>(
begin: 0,
end: 1,
).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0, 1, curve: Curves.linear),
),
);
super.initState();
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.green[800],
),
body: Stack(
children: [
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Image(
image: AssetImage('assets/field.jpg'),
fit: BoxFit.cover,
),
),
FadeTransition(
opacity: _backgroundOpacity,
child: Container(
child: BackdropFilter(
filter: new ImageFilter.blur(sigmaX: 6.0, sigmaY: 6.0),
child: new Container(
decoration: new BoxDecoration(
color: Colors.grey.shade200.withOpacity(0.5),
),
),
),
),
),
],
),
);
}
}
basically what I get from this code is the background image clear and nice, then after 2 seconds suddenly blurred, without any transition.
What should I do to make fadeTransition to work with Backdropfilter?
The preferred way to fade in a blur is to use a TweenAnimationBuilder:
TweenAnimationBuilder<double>(
duration: Duration(milliseconds: 500),
tween: Tween<double>(begin: 0, end: 6),
builder: (context, value, _) {
return BackdropFilter(
key: GlobalObjectKey('background'),
filter: ImageFilter.blur(sigmaY: value, sigmaX: value),
child: Container(
decoration: new BoxDecoration(
color: Colors.grey.shade200.withOpacity(0.5),
),
),
);
},
),
I have got a stack of cards and scroll wheel. I am trying to animate the front card, move it to the right, then bring it back in a way it goes to the back of the cards.
I have used a future function to specify witch part of code should be done first. But what I get is; it changes the index of the card first the animation takes place. Here is my code:
class AnimationsPractice extends StatefulWidget {
static const String id = 'test_screen';
#override
_AnimationsPracticeState createState() => _AnimationsPracticeState();
}
class _AnimationsPracticeState extends State<AnimationsPractice>
with SingleTickerProviderStateMixin {
FixedExtentScrollController _scrollController =
FixedExtentScrollController(initialItem: 0);
AnimationController _controller;
Animation<Offset> _offsetAnimation;
int selected;
List<Widget> sampleCard;
Animation<Offset> _offsetAnimation2;
bool halfWayAnimation;
#override
void initState() {
super.initState();
_controller =
AnimationController(duration: const Duration(seconds: 1), vsync: this)
..repeat();
_offsetAnimation = Tween<Offset>(
begin: Offset.zero,
end: const Offset(1.5, 0.0),
).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(
0.0,
0.5,
curve: Curves.elasticIn,
),
),
);
_offsetAnimation2 = Tween<Offset>(
begin: const Offset(1.5, 0.0),
end: Offset.zero,
).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(
0.5,
1.0,
curve: Curves.elasticIn,
),
),
);
halfWayAnimation = false;
_controller.stop();
sampleCard = [
Container(
height: 60,
width: 40,
color: Colors.red,
),
Transform.rotate(
angle: 10 * (pi / 180),
child: Container(
height: 60,
width: 40,
color: Colors.blueGrey,
)),
SlideTransition(
position: halfWayAnimation ? _offsetAnimation2 : _offsetAnimation,
child: Container(
height: 60,
width: 40,
color: Colors.yellow,
),
),
];
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
Future<void> _playAnimation() async {
try {
await _controller.forward().orCancel;
await siftingIndex();
await _controller.reverse().orCancel;
} on TickerCanceled {
// the animation got canceled, probably because it was disposed of
}
}
Future<void> siftingIndex() {
return Future.delayed(const Duration(microseconds: 200), () {
sampleCard.insert(0, sampleCard[sampleCard.length - 1]);
sampleCard.removeLast();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(180.0),
child: SafeArea(
child: TextButton(
child: Text('back to login'),
onPressed: () {
Navigator.pushNamed(context, LoginScreen.id);
},
),
),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Stack(children: sampleCard),
CustomScrollWheel(
onItemChange: (x) {
setState(() {
_playAnimation();
halfWayAnimation = true;
});
},
scrollController: _scrollController,
),
],
),
);
}
}
enter image description here
I am trying to create a flutter application where the background image changes based off data coming in from an API. I have the following code written to have the screen fade in using an AnimationController and Animation of doubles, however whenever I try to load the app, all I get is a black screen.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(RootWidget());
class RootWidget extends StatefulWidget {
#override
_RootWidgetState createState() => _RootWidgetState();
}
class _RootWidgetState extends State<RootWidget> with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;
#override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 500));
_animation =
Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeOut
));
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primarySwatch: Colors.green),
home: AnimatedOpacity(
opacity: _animation.value,
duration: Duration(milliseconds: 1000),
child: Scaffold(
appBar: AppBar(
title: Text('Vuetiful Mobile'),
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/Sunny-photo.jpg'),
fit: BoxFit.cover
)
),
child: Container(
color: Color.fromARGB(100, 0, 0, 0),
child: Center(
child: Text('Temp', style: TextStyle(color: Colors.white))
)
)
),
),
),
);
}
}
You should either choose between using an AnimationController or the AnimatedOpacity widget, but not both.
AnimatedOpacity is already an animated version of opacity, so adding a controller to it doesn't do what you want; it handles all of the necessary animation logic itself. You just need to provide an opacity and it animates to it in the given duration and with the given curve.
The likely easier solution would be to stick with AnimatedOpacity and get rid of the controller. Then set the opacity value with a post frame callback:
class _RootWidgetState extends State<RootWidget> {
double opacity = 0;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
opacity = 1;
});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primarySwatch: Colors.green),
home: AnimatedOpacity(
opacity: opacity,
curve: Curves.easeOut,//Add your curve here
duration: Duration(milliseconds: 1000),//Set your desired duration
child: Scaffold(
appBar: AppBar(
title: Text('Vuetiful Mobile'),
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/Sunny-photo.jpg'),
fit: BoxFit.cover
)
),
child: Container(
color: Color.fromARGB(100, 0, 0, 0),
child: Center(
child: Text('Temp', style: TextStyle(color: Colors.white))
)
)
),
),
),
);
}
}
This solution also ends up being more efficient because flutter doesn't have to rebuild as much stuff for each tick.
Alternatively, you could keep the AnimationController and change AnimatedOpacity to Opacity:
class _RootWidgetState extends State<RootWidget> with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;
#override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(milliseconds: 500));
_controller.addListener(() {
setState((){});
});
_controller.forward();
_animation =
Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeOut
));
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primarySwatch: Colors.green),
home: Opacity(
opacity: _animation.value,
child: Scaffold(
appBar: AppBar(
title: Text('Vuetiful Mobile'),
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/Sunny-photo.jpg'),
fit: BoxFit.cover
)
),
child: Container(
color: Color.fromARGB(100, 0, 0, 0),
child: Center(
child: Text('Temp', style: TextStyle(color: Colors.white))
)
)
),
),
),
);
}
}
I've started playing with Flutter and now thinking about the best way how I can implement a card's flipping animation.
I found this flip_card package and I'm trying to adjust its source code to my needs.
Here is the app which I have now:
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(FlipAnimationApp());
class FlipAnimationApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Flip animation"),
),
body: Center(
child: Container(
width: 200,
height: 200,
child: WidgetFlipper(
frontWidget: Container(
color: Colors.green[200],
child: Center(
child: Text(
"FRONT side.",
),
),
),
backWidget: Container(
color: Colors.yellow[200],
child: Center(
child: Text(
"BACK side.",
),
),
),
),
),
),
),
);
}
}
class WidgetFlipper extends StatefulWidget {
WidgetFlipper({
Key key,
this.frontWidget,
this.backWidget,
}) : super(key: key);
final Widget frontWidget;
final Widget backWidget;
#override
_WidgetFlipperState createState() => _WidgetFlipperState();
}
class _WidgetFlipperState extends State<WidgetFlipper> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> _frontRotation;
Animation<double> _backRotation;
bool isFrontVisible = true;
#override
void initState() {
super.initState();
controller = AnimationController(duration: Duration(milliseconds: 500), vsync: this);
_frontRotation = TweenSequence(
<TweenSequenceItem<double>>[
TweenSequenceItem<double>(
tween: Tween(begin: 0.0, end: pi / 2).chain(CurveTween(curve: Curves.linear)),
weight: 50.0,
),
TweenSequenceItem<double>(
tween: ConstantTween<double>(pi / 2),
weight: 50.0,
),
],
).animate(controller);
_backRotation = TweenSequence(
<TweenSequenceItem<double>>[
TweenSequenceItem<double>(
tween: ConstantTween<double>(pi / 2),
weight: 50.0,
),
TweenSequenceItem<double>(
tween: Tween(begin: -pi / 2, end: 0.0).chain(CurveTween(curve: Curves.linear)),
weight: 50.0,
),
],
).animate(controller);
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: [
AnimatedCard(
animation: _backRotation,
child: widget.backWidget,
),
AnimatedCard(
animation: _frontRotation,
child: widget.frontWidget,
),
_tapDetectionControls(),
],
);
}
Widget _tapDetectionControls() {
return Stack(
fit: StackFit.expand,
children: <Widget>[
GestureDetector(
onTap: _leftRotation,
child: FractionallySizedBox(
widthFactor: 0.5,
heightFactor: 1.0,
alignment: Alignment.topLeft,
child: Container(
color: Colors.transparent,
),
),
),
GestureDetector(
onTap: _rightRotation,
child: FractionallySizedBox(
widthFactor: 0.5,
heightFactor: 1.0,
alignment: Alignment.topRight,
child: Container(
color: Colors.transparent,
),
),
),
],
);
}
void _leftRotation() {
_toggleSide();
}
void _rightRotation() {
_toggleSide();
}
void _toggleSide() {
if (isFrontVisible) {
controller.forward();
isFrontVisible = false;
} else {
controller.reverse();
isFrontVisible = true;
}
}
}
class AnimatedCard extends StatelessWidget {
AnimatedCard({
this.child,
this.animation,
});
final Widget child;
final Animation<double> animation;
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {
var transform = Matrix4.identity();
transform.setEntry(3, 2, 0.001);
transform.rotateY(animation.value);
return Transform(
transform: transform,
alignment: Alignment.center,
child: child,
);
},
child: child,
);
}
}
Here is how it looks like:
What I'd like to achieve is to make the card flip over its right side if it was tapped on its right half and over its left side if it was tapped on its left half. If it is tapped several times in a row on the same half it should flip over the same side (not back and forth as it is doing now).
So the desired animation should behave as the following one from Quizlet app.
You should know when you tap on the right or left to change the animations dynamically, for that you could use a flag isRightTap. Then, you should invert the values of the Tweens if it has to rotate to one side or to the other.
And the side you should rotate would be:
Rotate to left if the front is visible and you tapped on the left, or, because the back animation is reversed, if the back is is visible and you tapped on the right
Otherwise, rotate to right
Here are the things I changed in _WidgetFlipperState from the code in the question:
_updateRotations(bool isRightTap) {
setState(() {
bool rotateToLeft = (isFrontVisible && !isRightTap) || !isFrontVisible && isRightTap;
_frontRotation = TweenSequence(
<TweenSequenceItem<double>>[
TweenSequenceItem<double>(
tween: Tween(begin: 0.0, end: rotateToLeft ? (pi / 2) : (-pi / 2))
.chain(CurveTween(curve: Curves.linear)),
weight: 50.0,
),
TweenSequenceItem<double>(
tween: ConstantTween<double>(rotateToLeft ? (-pi / 2) : (pi / 2)),
weight: 50.0,
),
],
).animate(controller);
_backRotation = TweenSequence(
<TweenSequenceItem<double>>[
TweenSequenceItem<double>(
tween: ConstantTween<double>(rotateToLeft ? (pi / 2) : (-pi / 2)),
weight: 50.0,
),
TweenSequenceItem<double>(
tween: Tween(begin: rotateToLeft ? (-pi / 2) : (pi / 2), end: 0.0)
.chain(CurveTween(curve: Curves.linear)),
weight: 50.0,
),
],
).animate(controller);
});
}
#override
void initState() {
super.initState();
controller =
AnimationController(duration: Duration(milliseconds: 500), vsync: this);
_updateRotations(true);
}
void _leftRotation() {
_toggleSide(false);
}
void _rightRotation() {
_toggleSide(true);
}
void _toggleSide(bool isRightTap) {
_updateRotations(isRightTap);
if (isFrontVisible) {
controller.forward();
isFrontVisible = false;
} else {
controller.reverse();
isFrontVisible = true;
}
}
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp();
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage();
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _toggler = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(actions: [
TextButton(
onPressed: _onFlipCardPressed,
child: const Text('change', style: TextStyle(color: Colors.white)),
)
]),
body: Center(
child: SizedBox.square(
dimension: 140,
child: FlipCard(
toggler: _toggler,
frontCard: AppCard(title: 'Front'),
backCard: AppCard(title: 'Back'),
),
),
),
);
}
void _onFlipCardPressed() {
setState(() {
_toggler = !_toggler;
});
}
}
class AppCard extends StatelessWidget {
final String title;
const AppCard({
required this.title,
});
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.deepPurple[400],
),
child: Center(
child: Text(
title,
style: const TextStyle(
fontSize: 40.0,
color: Colors.white,
),
textAlign: TextAlign.center,
),
),
);
}
}
class FlipCard extends StatelessWidget {
final bool toggler;
final Widget frontCard;
final Widget backCard;
const FlipCard({
required this.toggler,
required this.backCard,
required this.frontCard,
});
#override
Widget build(BuildContext context) {
return GestureDetector(
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 800),
transitionBuilder: _transitionBuilder,
layoutBuilder: (widget, list) => Stack(children: [widget!, ...list]),
switchInCurve: Curves.ease,
switchOutCurve: Curves.ease.flipped,
child: toggler
? SizedBox(key: const ValueKey('front'), child: frontCard)
: SizedBox(key: const ValueKey('back'), child: backCard),
),
);
}
Widget _transitionBuilder(Widget widget, Animation<double> animation) {
final rotateAnimation = Tween(begin: pi, end: 0.0).animate(animation);
return AnimatedBuilder(
animation: rotateAnimation,
child: widget,
builder: (context, widget) {
final isFront = ValueKey(toggler) == widget!.key;
final rotationY = isFront ? rotateAnimation.value : min(rotateAnimation.value, pi * 0.5);
return Transform(
transform: Matrix4.rotationY(rotationY)..setEntry(3, 0, 0),
alignment: Alignment.center,
child: widget,
);
},
);
}
}
Try this code I've made some changes to your code, now the GestureDetector is divided equally in width on widget so when you tap on the left side of the box it will reverse the animation and if you tap on right side part it will forward the animation.
Widget _tapDetectionControls() {
return Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
flex: 1,
child: GestureDetector(
onTap: _leftRotation,
),
),
Expanded(
flex: 1,
child: GestureDetector(
onTap: _rightRotation,
),
),
],
);
}
void _leftRotation() {
controller.reverse();
}
void _rightRotation() {
controller.forward();
}
I'm trying to figure out how to notify user with alert that comes from top of the screen like normal push notification does.
How can I alert user from top of the screen.
AlertDialog is not customizable so I'm stuck with this. Is there any way to show something like alert or snack bar from top of the screen?
Flutter gives you the possiblity to create notifications with the help of the class Overlay. To animate these entering the screen from the top you can use the SlideTransition in combination with an AnimationController. Here is an example application I created:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: Home());
}
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton.icon(
icon: Icon(Icons.notifications_active),
label: Text('Notify!'),
onPressed: () {
Navigator.of(context)
.overlay
.insert(OverlayEntry(builder: (BuildContext context) {
return FunkyNotification();
}));
},
),
),
);
}
}
class FunkyNotification extends StatefulWidget {
#override
State<StatefulWidget> createState() => FunkyNotificationState();
}
class FunkyNotificationState extends State<FunkyNotification>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<Offset> position;
#override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 750));
position = Tween<Offset>(begin: Offset(0.0, -4.0), end: Offset.zero)
.animate(
CurvedAnimation(parent: controller, curve: Curves.bounceInOut));
controller.forward();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Material(
color: Colors.transparent,
child: Align(
alignment: Alignment.topCenter,
child: Padding(
padding: EdgeInsets.only(top: 32.0),
child: SlideTransition(
position: position,
child: Container(
decoration: ShapeDecoration(
color: Colors.deepPurple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0))),
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text(
'Notification!',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
),
),
),
),
),
),
);
}
}
Here you can dismiss notifications using the swipe up or down. This is the perfect notification for promotion in-app.
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> with TickerProviderStateMixin {
bool _fromTop = true;
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.fireplace_outlined),
onPressed: () {
showGeneralDialog(
barrierLabel: "Label",
barrierDismissible: true,
barrierColor: Colors.transparent,
transitionDuration: Duration(milliseconds: 700),
context: context,
pageBuilder: (context, anim1, anim2) {
return GestureDetector(
onVerticalDragUpdate: (dragUpdateDetails) {
Navigator.of(context).pop();
},
child: Column(
children: [
SizedBox(height: 40),
Card(
margin:
EdgeInsets.symmetric(vertical: 20, horizontal: 10),
child: Container(
height: 100,
child: Image.asset('lib/model/promo.png',
fit: BoxFit.fill),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(40),
),
),
),
],
),
);
},
transitionBuilder: (context, anim1, anim2, child) {
return SlideTransition(
position: anim1.drive(Tween(
begin: Offset(0, _fromTop ? -1 : 1), end: Offset(0, 0))
.chain(CurveTween(curve: Sprung()))),
child: child,
);
},
);
},
),
);
}
}
class Sprung extends Curve {
factory Sprung([double damping = 20]) => Sprung.custom(damping: damping);
Sprung.custom({
double damping = 20,
double stiffness = 180,
double mass = 1.0,
double velocity = 0.0,
}) : this._sim = SpringSimulation(
SpringDescription(
damping: damping,
mass: mass,
stiffness: stiffness,
),
0.0,
1.0,
velocity,
);
final SpringSimulation _sim;
#override
double transform(double t) => _sim.x(t) + t * (1 - _sim.x(1.0));
}