My application has a stateful widget which is the profile area, I would like to display an animated icon indicating to the user that is possible to scroll the screen, I want to use the animated icon, how to auto animate an AnimatedIcon as soon the Profile screen loads, thanks.
Obs.: The play_pause is just a placeholder for an animated icon
import 'package:flutter/material.dart';
void main() {
runApp(Profile());
}
class Profile extends StatefulWidget {
#override
ProfileState createState() {
return ProfileState();
}
}
class ProfileState extends State<Profile> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: AnimatedIcon(
progress: AnimationController(
vsync: this,
duration: Duration(milliseconds: 400),
reverseDuration: Duration(milliseconds: 400),
),
icon: AnimatedIcons.play_pause,
),
)
)
);
}
}
You have to create an instance of AnimationController and initialize it on the initState. Then you can start the animation by calling animateTo method.
import 'package:flutter/material.dart';
void main() {
runApp(Profile());
}
class Profile extends StatefulWidget {
#override
ProfileState createState() {
return ProfileState();
}
}
class ProfileState extends State<Profile> with TickerProviderStateMixin {
AnimationController _animationController;
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 400),
);
_animationController.animateTo(1.0);
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: AnimatedIcon(
progress: _animationController,
icon: AnimatedIcons.play_pause,
),
),
),
);
}
}
you could do that using the animationController
_animationController.forward(); /// to start the animation
You can start your animation after the build method executes by calling it like this.
#override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
_animationController.forward();
});
}
Related
The print functions should be called according to the lifecycle transitions, but none of them are being called. To test this, I'm running the app in debug mode and moving it to the background/foreground (i.e. changing to another app and then returning to this app).
What am I doing wrong?
import 'package:flutter/material.dart';
class StopwatchVw extends StatefulWidget {
const StopwatchVw({Key? key}) : super(key: key);
#override _StopwatchVwState createState() => _StopwatchVwState();
}
class _StopwatchVwState extends State<StopwatchVw> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance!.addObserver(this);
}
#override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) {
print('Changed');
switch (state) {
case AppLifecycleState.inactive:
print("Inactive");
break;
case AppLifecycleState.paused:
print("Paused");
break;
case AppLifecycleState.resumed:
print("Resumed");
break;
case AppLifecycleState.detached:
print("Suspending");
break;
}
}
#override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(body: Text('HEY'));
}
This is my main.dart:
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:clocker/stopwatch_vw.dart';
import 'package:flutter/material.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Window.initialize();
await Window.hideWindowControls();
runApp(const MyApp());
doWhenWindowReady(() {
const initialSize = Size(350, 200);
appWindow
..size = initialSize
..minSize = initialSize
..maxSize = initialSize
..alignment = Alignment.bottomRight
..show();
});
Window.setEffect(
effect: WindowEffect.acrylic,
color: const Color.fromARGB(29, 250, 250, 227),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MoveWindow(child: const StopwatchVw())
);
}
}
Flutter currently doesn't support LifeCycle events on the desktop, But there is an existing issue which is being tracked here #30735.
Currently, you can determine the status of your application with the window_manager package
class Windows extends StatefulWidget {
const Windows({super.key});
#override
State<Windows> createState() => _WindowsState();
}
class _WindowsState extends State<Windows> with WindowListener {
#override
void onWindowClose() {
// do something
}
#override
void onWindowFocus() {
// do something
}
#override
void onWindowMinimize() {
// do something
}
#override
void initState() {
windowManager.addListener(this);
super.initState();
}
#override
void dispose() {
windowManager.removeListener(this);
super.dispose();
}
In my Flutter app I have lots of pop up dialogs, but I need to dismiss any open dialog when app goes to background (user switches to another app).
I know about Lifecycle, but it's not easy to implement it for all dialogs.
Did you try Navigator.popUntil on the life cycle?.
Navigator.popUntil(context, (route) => !(route is PopupRoute));
Example:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
#override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
void _showDialogs() {
showDialog(
context: context,
builder: (context) => AlertDialog(title: Text("Dialog 1")),
);
showDialog(
context: context,
builder: (context) => AlertDialog(title: Text("Dialog 2")),
);
showDialog(
context: context,
builder: (context) => AlertDialog(title: Text("Dialog 3")),
);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
child: Text("show multiple dialogs"),
onPressed: _showDialogs,
),
),
);
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused)
Navigator.popUntil(context, (route) => !(route is PopupRoute));
}
}
Navigator.of(context,rootNavigator:true).pop();
I've been trying to make a Container move from the bottom of the screen to the middle when I click a button. However, I can't figure out how to properly execute the animation only when I press the button. Furthermore, it seems that when I call the _customWidget.startAnimation() method an error stating I called the function on void always happens. Here are my questions:
How do I access startAnimation() inside MyCustomWidget properly and how should I structure the code to only run the animation when I press the button?
Main.dart:
import 'package:flutter/material.dart';
import 'MyCustomWidget.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
MyCustomWidget _customWidget;
#override
void initState() {
super.initState();
_customWidget = MyCustomWidget();
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: MyCustomWidget(),
),
FloatingActionButton(
onPressed: () => {} //_customWidget.startAnimation() gives an error,
)
],
);
}
}
MyCustomWidget.dart:
import 'package:flutter/material.dart';
class MyCustomWidget extends StatefulWidget {
#override
_MyCustomWidgetState createState() => _MyCustomWidgetState();
startAnimation() {
debugPrint('is this where the function should be?');
}
}
class _MyCustomWidgetState extends State<MyCustomWidget>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation<Offset> _offsetAnimation;
void startAnimation() {
debugPrint('or is it here?');
}
#override
void initState() {
super.initState();
//Following code should go in startAnimation() rather than letting it execute
//every time the object is created
_animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..repeat(reverse: true);
_offsetAnimation = Tween<Offset>(
begin: Offset.zero,
end: const Offset(1.5, 0.0),
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.elasticIn,
));
}
#override
Widget build(BuildContext context) {
return SlideTransition(
position: _offsetAnimation,
child: Container(
color: Colors.white,
height: 50,
width: 50,
),
);
}
#override
void dispose() {
super.dispose();
_animationController.dispose();
}
}
In Flutter, you access the child widgets using key. You also have to make the state public (remove the underscore from _MyCustomWidgetState)
So in the child:
class MyCustomWidget extends StatelessWidget {
final Key key;
MyCustomWidget(this.key) : super(key: key);
[...]
in the parent:
GlobalKey<MyCustomWidgetState> key = GlobalKey<MyCustomWidgetState>();
[...]
Center(
child: MyCustomWidget(key)
)
and calling the child (from parent):
key.currentState.startAnimation();
Tien's answer got my widget working correctly, here's how the two files look after the modifications:
Main.dart
import 'package:flutter/material.dart';
import 'MyCustomWidget.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GlobalKey<MyCustomWidgetState> _customWidgetKey =
GlobalKey<MyCustomWidgetState>();
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: MyCustomWidget(_customWidgetKey),
),
FloatingActionButton(
onPressed: () => _customWidgetKey.currentState.show(),
)
],
);
}
}
MyCustomWidget.dart:
import 'package:flutter/material.dart';
class MyCustomWidget extends StatefulWidget {
final Key key;
MyCustomWidget(this.key) : super(key: key);
#override
MyCustomWidgetState createState() => MyCustomWidgetState();
}
class MyCustomWidgetState extends State<MyCustomWidget>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation<Offset> _offsetAnimation;
void show() {
setState(() {
_animationController.animateTo(1.0);
});
}
void hide() {
setState(() {
_animationController.animateTo(0.0);
});
}
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
_offsetAnimation = Tween<Offset>(
begin: Offset(0.0, 40),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOutQuint,
));
}
#override
Widget build(BuildContext context) {
return SlideTransition(
position: _offsetAnimation,
child: Container(
child: FloatingActionButton(
backgroundColor: Colors.white,
onPressed: () => hide(),
),
),
);
}
#override
void dispose() {
super.dispose();
_animationController.dispose();
}
}
This gets you a button which brings up a button when pressed. Clicking the second button sends it down. This whole thing is going to be useful to make custom widgets pop up and down!
I need to start an animation of a child widget from a parent widget. How can I do this?
I've tried giving the parent the controller, but then how do you replace vsync: this?
This is the basic code (I haven't actually tested this code yet, but I shows what I mean):
import 'package:flutter/material.dart';
class ParentWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ChildText(),
FlatButton(
child: Text('start the animation'),
onPressed: () {
// start the animation!!!????????
},
)
],
);
}
}
class ChildText extends StatefulWidget {
#override
_ChildTextState createState() => _ChildTextState();
}
class _ChildTextState extends State<ChildText> with TickerProviderStateMixin {
AnimationController _controller;
Animation _animation;
#override
void initState() {
super.initState();
// actual animation is much more complex, this is just a random demo
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 2));
_animation = Tween(begin: -1.0, end: 100.0).animate(CurvedAnimation(
parent: _controller,
curve: Curves.fastOutSlowIn,
));
}
#override
Widget build(BuildContext context) {
return Transform.translate(
offset: Offset(0, _animation.value),
child: Text('Text with fancy animation'));
}
}
You can try this:
class ParentWidget extends StatefulWidget {
#override
_ParentWidget createState() => _ParentWidget();
}
class _ParentWidget extends State<ParentWidget> with TickerProviderStateMixin {
AnimationController _controller;
#override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 2));
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ChildText(_controller),
FlatButton(
child: Text('start the animation'),
onPressed: () {
// start the animation!!!
_controller.forward();
},
)
],
);
}
}
class ChildText extends StatefulWidget {
ChildText(this._controller);
final AnimationController _controller;
#override
_ChildTextState createState() => _ChildTextState();
}
class _ChildTextState extends State<ChildText> with TickerProviderStateMixin {
Animation _animation;
#override
void initState() {
super.initState();
_animation = Tween(begin: -1.0, end: 100.0).animate(CurvedAnimation(
parent: widget._controller,
curve: Curves.fastOutSlowIn,
));
}
#override
Widget build(BuildContext context) {
return Transform.translate(
offset: Offset(0, _animation.value),
child: Text('Text with fancy animation'));
}
}
I want to run a function every time the page changes in my Flutter application.
Ideally, I don't want to call this function in initState of every page, as sometimes people can forget to add the call in a new page.
Think of it as middleware - be basically before the page loads etc, some code needs to run.
Updated code for review
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:myapp/pages/login_page.dart';
import 'package:myapp/pages/dashboard_page.dart';
import 'package:myapp/styles/constants.dart';
import 'package:myapp/services/auth_service.dart';
Future<void> main() async {
// create a auth service instance
AuthService authService = AuthService(secureStorage: FlutterSecureStorage());
bool isLoggedIn = await authService.isUserLoggedIn();
// run the app
runApp(MyApp(
isLoggedIn: isLoggedIn,
));
}
class MyApp extends StatefulWidget {
final bool isLoggedIn;
MyApp({this.isLoggedIn});
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with RouteAware {
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
#override
void didChangeDependencies() {
super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context));
}
#override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}
#override
void didPush() {
print('didPush');
}
#override
void didPopNext() {
print('didPopNext');
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'App NAME',
theme: ThemeData(
primarySwatch: Colors.green,
primaryColor: kPrimeColour,
),
home: widget.isLoggedIn == true ? DashboardPage() : LoginPage(),
navigatorObservers: [routeObserver],
);
}
}
You can use implementation method didChangeDependencies this function called after initState,
flutter doc :
Subclasses rarely override this method because the framework always calls build after a dependency changes. Some subclasses do override this method because they need to do some expensive work (e.g., network fetches) when their dependencies change, and that work would be too expensive to do for every build.
Link
#override
void didChangeDependencies() {
super.didChangeDependencies();
// set your stuff here
}
You can use inheritance
abstract class MyState<T extends StatefulWidget> extends State {
#override
void initState() {
super.initState();
//YOUR CHANGE PAGE METHOD HERE
}
}
class YellowBird extends StatefulWidget {
const YellowBird({ Key key }) : super(key: key);
#override
_YellowBirdState createState() => _YellowBirdState();
}
class _YellowBirdState extends MyState<YellowBird> {
#override
Widget build(BuildContext context) {
return Container(color: const Color(0xFFFFE306));
}
}