Reputation: 71
I am trying to do an animation to make a green box move back and forth. Trying to use onEnd and curve. So I want the green box to go by its self to the right and back. It will be moving back and forth and I will also have to put something in the setState.
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(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
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> {
double _moveX = 0.0;
void _incrementCounter() {
setState(() {
_moveX++;
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: AnimatedAlign(
duration: Duration(microseconds: 300),
curve: Curves.bounceIn,
alignment: Alignment(_moveX, -0.0),
child: Container(
width: 50,
height: 50,
color: Colors.green,
),
),
)
],
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Upvotes: 0
Views: 2537
Reputation: 447
Here is the example of a local notification that is displayed for 3 seconds with back and forth animation.
import 'package:flutter/material.dart';
import 'package:romobili_poc/app/constants/AppConstants.dart';
class LevelNotification extends StatefulWidget {
@override
_LevelNotificationState createState() => _LevelNotificationState();
}
class _LevelNotificationState extends State<LevelNotification>
with SingleTickerProviderStateMixin {
AnimationController levelNotificationController;
Animation<Offset> levelNotificationOffset;
@override
void initState() {
levelNotificationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
levelNotificationOffset = Tween<Offset>(
begin: Offset(0.0, -1.0),
end: Offset(0.0, 0.0),
).animate(levelNotificationController);
levelNotificationOffset.addStatusListener((status) {
print(status);
Future.delayed(
const Duration(seconds: 3),
() => levelNotificationController.reverse(),
);
});
super.initState();
}
@override
void dispose() {
levelNotificationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topCenter,
child: SlideTransition(
position: levelNotificationOffset,
child: InkWell(
onTap: () {
levelNotificationController.forward();
},
child: Container(
color: Colors.red,
height: 100,
width: double.infinity,
),
),
),
);
}
}
Upvotes: 1
Reputation: 17123
In the onEnd
property of the AnimatedAlign widget, trigger the animation to go back with a decrementCounter
method of some kind, identical to _incrementCounter
, but decreasing instead.
void _decrementCounter() {
setState(() {
_moveX--;
});
}
To trigger the animation initially, you should increment the position value in initState
, but it must be registered as a post frame callback to ensure the widget is mounted, and also to trigger the animation properly in AnimatedAlign
. Ex.
@override
void initState() {
super.initState();
WidgetsBinding.addPostFrameCallback(_incrementCounter);
}
Since you also want to make this animation repeat, you need to conditionally call either _incrementCounter
or _decrementCounter
based on the last called method. This can be easily done just by checking the current position. Ex.
onEnd: () {
if(_moveX.round() == 0) {//round might not be able to be used depending on the range of values you want to animate between
_incrementCounter();
}
else {
_decrementCounter();
}
}
This could likely be done more simply with an AnimationController
as it has a repeat
method, but it might not benefit you enough to be used in this case.
Upvotes: 0