I saw many webs when scroll down they have slide fade animations on their widgetI am wondering how they work! Any example with fade slide animation will be appreciated
New to flutter wondering how to do where to start
Try this code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: _title,
home: FadeTransitionExample(),
);
}
}
class FadeTransitionExample extends StatefulWidget {
#override
State<StatefulWidget> createState() => _Fade();
}
class _Fade extends State<FadeTransitionExample> with TickerProviderStateMixin {
AnimationController? animationController;
Animation<double>? _animationValue;
#override
void initState() {
super.initState();
animationController = AnimationController(vsync: this, duration: const Duration(seconds: 2),);
_animationValue = Tween<double>(begin: 0.0, end: 0.5).animate(animationController!);
animationController!.addStatusListener((status){
if(status == AnimationStatus.completed){
animationController!.reverse();
}
else if(status == AnimationStatus.dismissed){
animationController!.forward();
}
});
animationController!.forward();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: FadeTransition(
opacity: _animationValue!,
child: Container(
color: Colors.blue,
width: 150,
height: 150,
),
),
),
),
);
}
}
Related
I have a custom widget that changes color when tapped inside a gridview. When I scroll to the bottom and scroll back up to the top selected widget its animation is reversed.
I'm pretty sure that it has something to do with the widget being disposed of when out of view but I don't have a solution to overcome it. See my code below:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Thirty Seconds',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
// Page with the gridview
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.count(
crossAxisCount: 2,
children: List.generate(20, (index) {
return MyCustomWidget(
key: GlobalKey(),
index: index + 1,
);
}),
),
);
}
}
// Custom Widget
class MyCustomWidget extends StatefulWidget {
const MyCustomWidget({
super.key,
required this.index,
});
final int index;
#override
State<MyCustomWidget> createState() => _MyCustomWidgetState();
}
class _MyCustomWidgetState extends State<MyCustomWidget>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<Color?> _colorAnimation;
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
_colorAnimation = ColorTween(begin: Colors.white, end: Colors.yellow)
.animate(_animationController)
..addListener(() => setState(() {}));
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _toggleAnimation() {
if (_animationController.isCompleted) {
_animationController.reverse();
} else {
_animationController.forward();
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
_toggleAnimation();
},
child: Container(
color: _colorAnimation.value,
child: Center(
child: Text("Custom Widget ${widget.index}"),
),
),
);
}
}
GridView dispose the widget that aren't visible on UI. You can use cacheExtent(not suitable for this case) or AutomaticKeepAliveClientMixin on _MyCustomWidgetState.
class _MyCustomWidgetState extends State<MyCustomWidget>
with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
You may prefer handing it parent widget and passing a bool to check active state or state-management or project level depends on scenario.
Is there any way to Animate a Text widget which is placed in the center of screen to the Title of Appbar ?
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(child:Text('Animate Me!')),
);
}
How shall I approach to animate it in Flutter?
Edit :
I was imagining a Text fly and hover from Center of the screen to title of Appbar.
Yes, you can animate the Text widget within the AppBar of your app. Your approach to animating the Text widget should be pretty much like any other animation. You can apply almost all types of animations available in Flutter. Please the code below :
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
#override
State createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController _controller;
//String text = "";
Future myFuture;
//Animation<int> _charInt;
Animation<Offset> position;
final String title = 'Flutter Demo Project';
Future myAnimation() async {
_controller = AnimationController(
duration: const Duration(milliseconds: 1500),
vsync: this,
);
setState(() {
// _charInt = StepTween(begin: 0, end: title.length)
// .animate(CurvedAnimation(parent: _controller, curve: Curves.easeIn));
position = Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: const Offset(0.0, -9.0),
).animate(CurvedAnimation(curve: Curves.bounceOut, parent: _controller));
});
await _controller.forward();
}
#override
void initState() {
super.initState();
myFuture = myAnimation();
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
// final AnimatedBuilder animatedBuilder = _charInt == null
// ? null
// : AnimatedBuilder(
// animation: _charInt,
// builder: (BuildContext context, Widget child) {
// final String text = title.substring(0, _charInt.value);
// return Text(text);
// },
// );
return Scaffold(
appBar: AppBar(title: Text(title)), //animatedBuilder),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//animatedBuilder,
SlideTransition(
position: position,
child: Text(
title,
style: const TextStyle(fontSize: 32),
),
),
],
),
),
);
}
}
I have this code which uses an AnimationController and Tween to rotate a container along Z-axis when Start/Stop Button is pressed. The problem is it forwards the animation only first time after that no matter how many times I press the button it does nothing and the container remains stationary .
curvesanimation.dart which has all the animation logic
import 'package:flutter/material.dart';
import 'dart:math' as math;
class CurvedAnimationExample extends StatefulWidget {
CurvedAnimationExample({Key key}) : super(key: key);
#override
CurvedAnimationExampleState createState() => CurvedAnimationExampleState();
}
class CurvedAnimationExampleState extends State<CurvedAnimationExample>
with SingleTickerProviderStateMixin {
Animation<double> _animation;
AnimationController _animationController;
#override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: Duration(seconds: 5))
..addListener(() {
setState(() {});
});
final Animation curve =
CurvedAnimation(parent: _animationController, curve: Curves.easeIn);
_animation = Tween<double>(begin: 0, end: math.pi * 2).animate(curve);
}
void startStopAnimation() {
print(_animationController.isAnimating.toString());
if (_animationController.isAnimating)
_animationController.stop();
else {
_animationController.forward();
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Transform(
alignment: Alignment.center,
transform: Matrix4.identity()..rotateZ(_animation.value),
child: Container(
color: Colors.pinkAccent,
width: 200,
height: 200,
),
),
RaisedButton(
child: const Text("Start/Stop Animation"),
elevation: 15,
color: Colors.blueGrey,
onPressed: () => startStopAnimation(),
)
],
));
}
#override
void dispose() {
_animationController.dispose();
print("Curved Animation Example : dispose is called");
super.dispose();
}
}
main.dart file
import 'package:flutter/material.dart';
import 'curvesanimations.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: MyHomeScaffold(
title: "Curved Animation Example",
),
);
}
}
class MyHomeScaffold extends StatelessWidget {
final String title;
MyHomeScaffold({this.title});
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: CurvedAnimationExample(),
),
);
}
}
This is because your animation has already reached its endpoint. You can't keep going forward once the end point is reached. An easy fix is to check if the animation is at the endpoint already and reset it to the beginning if it is:
void startStopAnimation() {
print(_animationController.isAnimating.toString());
if (_animationController.isAnimating)
_animationController.stop();
else {
print("forward");
if(_animationController.isCompleted) {//Check if animation is at endpoint
_animationController.value = 0;
}
_animationController.forward();
}
}
in this simple below ui i have Container right of screen and i want to collapse and expand it with elastic animation, for example on expand elasticIn animation and for collapse elasticOut.
Is this what you need?
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
import 'dart:math';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Spring Box",
theme: ThemeData(),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
Animation animationIn, animationOut;
AnimationController _animationController;
#override
void initState() {
_animationController = AnimationController(
vsync: this,
value: 1.0,
duration: Duration(milliseconds: 500),
);
animationIn = CurvedAnimation(parent: _animationController, curve: Curves.elasticIn);
animationOut = CurvedAnimation(parent: _animationController, curve: Curves.elasticIn);
}
_toggleExpanded() {
if (_animationController.status == AnimationStatus.completed) {
_animationController.reverse();
} else {
_animationController.forward();
}
}
#override
Widget build(BuildContext context) {
var isExpanded = _animationController.status != AnimationStatus.completed;
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: _toggleExpanded,
child: Icon(Icons.add),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
CollapsAnimation(
animation: isExpanded ? animationOut : animationIn,
child: Container(
color: Color(0xFF404bc4),
),
),
],
),
backgroundColor: Color(0xFFe8e8e8),
);
}
}
class CollapsAnimation extends AnimatedWidget {
CollapsAnimation({key, animation, this.child})
: super(
key: key,
listenable: animation,
);
final Widget child;
final Tween tween = Tween<double>(begin: 0, end: 80);
#override
Widget build(BuildContext context) {
Animation<double> animation = listenable;
var animationValue = tween.evaluate(animation);
double width = animationValue >= 0.0 ? animationValue : 0.0;
return Container(
width: width,
child: child,
);
}
}
I am currently working on a hit/damage animation in Flutter. I want that each time the screen is tapped, it throws an animation showing an integer. I could not find a way to make it work. For now each time I tap the screen, the animation starts over stopping the previous one. I use the BLoC pattern inside the project so this animation is thrown by a streambuilder.
Here is my current code:
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final StreamController<int> streamController = StreamController<int>();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: GestureDetector(
onTap: () {
streamController.sink.add(Random().nextInt(5));
},
child: Scaffold(
body: Center(
child: StreamBuilder<int>(
stream: streamController.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return DamageAnimated(snapshot.data);
}
return Container();
},
),
),
),
),
);
}
}
class DamageAnimated extends StatefulWidget {
const DamageAnimated(this.damage);
final int damage;
#override
_DamageAnimatedState createState() => _DamageAnimatedState();
}
class _DamageAnimatedState extends State<DamageAnimated> with SingleTickerProviderStateMixin {
AnimationController animationController;
#override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
);
}
#override
void dispose() {
animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
animationController.forward(from: 0.0);
return AnimatedBuilder(
animation: animationController,
builder: (BuildContext context, Widget child) {
return Transform.translate(
offset: Offset(0, -100 * animationController.value),
child: Opacity(
opacity: 1 - animationController.value,
child: Text(
'${widget.damage}',
),
),j
);
},
);
}
}
This displays an integer translating upward and fading away at same time but I can't figure out how to have the same animation running multiple time concurrently.
You're only ever returning 1 DamageAnimated. Look at the example below - you'll need to implement something similar. Btw, the ... syntax to expand a list is new in dart, so you need to update sdk version in pubspec.yaml
environment:
sdk: ">=2.2.2 <3.0.0"
I've tested this on iOS, not Android, but no reason it shouldn't work.
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> {
List<Widget> _anims = [];
int _count = 0;
int _animationsRunning = 0;
void animationEnded() {
_animationsRunning--;
if (_animationsRunning == 0) {
setState(() {
_anims = [];
});
print('all animations completed - removing widget from stack (now has ${_anims.length} elements)');
}
}
void _startAnimation() {
setState(() {
_anims.add(DamageAnimated(_count, animationEnded));
_count++;
_animationsRunning++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Stack(
children: <Widget>[
..._anims,
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _startAnimation,
tooltip: 'Start animation',
child: Icon(Icons.add),
),
);
}
}
class DamageAnimated extends StatefulWidget {
const DamageAnimated(this.damage, this.endedCallback);
final int damage;
final VoidCallback endedCallback;
#override
_DamageAnimatedState createState() => _DamageAnimatedState();
}
class _DamageAnimatedState extends State<DamageAnimated> with SingleTickerProviderStateMixin {
AnimationController animationController;
#override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed)
if (mounted) {
widget.endedCallback();
}
});
}
#override
void dispose() {
animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
animationController.forward(from: 0.0);
return AnimatedBuilder(
animation: animationController,
builder: (BuildContext context, Widget child) {
return Transform.translate(
offset: Offset(0, -100 * animationController.value),
child: Opacity(
opacity: 1 - animationController.value,
child: Text(
'${widget.damage}',
),
),
);
},
);
}
}
Maybe you could try adding StatusListeners to the animation or you could, instead, reset and start the animation each time you tap the screen such as:
onTap: () {
streamController.sink.add(Random().nextInt(5));
animationController.reset();
animationController.forward(from: 0.0);
},
I couldn't try this on my own at the moment, but I think it's a way to do it.
Sorry for waisting your time if it doesn't work.