Flutter manage animation controller from outside of class - flutter

this is my simple animation in class witch i use that
controller = AnimationController(vsync: this, duration: Duration(milliseconds: 200));
offset = Tween<Offset>(begin: Offset.zero, end: Offset(0.0, -1.0)).animate(controller);
controller.forward();
in that i can only manage animation controller such as forward, reverse inside of class and i try to move this controller to outside of class like with another class as NotificationBarController, is any body help me how can i achieve to this solution?
for example
controller = NotificationBarController();
controller.forward();
source code
class NotificationBar extends StatefulWidget {
final Widget contentWidget;
final Widget barWidget;
NotificationBar({#required this.contentWidget, #required this.barWidget});
#override
State<StatefulWidget> createState() => NotificationBarState();
}
class NotificationBarState extends State<NotificationBar> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<Offset> offset;
#override
void initState() {
super.initState();
controller = AnimationController(vsync: this, duration: Duration(milliseconds: 200));
// offset = Tween<Offset>(begin: Offset.zero, end: Offset(1.0, 0.0)).animate(controller); from right
offset = Tween<Offset>(begin: Offset.zero, end: Offset(0.0, -1.0)).animate(controller);
controller.forward();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
),
);
}
}
my tired class to implementing that, but this is wrong
class NotificationBarController extends ChangeNotifier {
NotificationBarController({#required TickerProvider vsync}): _animationController = AnimationController(vsync: vsync);
Animation<double> get animation => _animationController?.view ?? kAlwaysCompleteAnimation;
Animation<double> get state => _animationController?.view ?? kAlwaysCompleteAnimation;
}

You can use GlobalKey for it.
First you need to instantiate and store it like this
final key = GlobalKey<NotificationBarState>(), then you need to pass it to NotificationBar constructor calling super with the key. Then you can access the state and its members by calling key.currentState.someMethod().
However the whole idea doesn't look like Flutter way for me. I would suggest to subscribe to some stream or changeNotifier inside NotificationBarState and fire animation as a reaction on new event or notification

Related

how to access to ScrollControll of a class from another class in flutter?

Hello i`m new in flutter.
I made a special listView for myself and made a controller for it.
In the main page, I have called my own list view and I have a button that I want to execute the following method by pressing it from the Main class and my list view scrolls inside another class.
scroll method:
void _animateToIndex(int index) {
_controller.animateTo(
index * 50,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
}
In fact, I want to execute the method of another class that contains my scrollview from the Main class.
my listView class:
class CustomNumberScroller extends StatefulWidget {
const CustomNumberScroller(
{Key? key, required this.curStep, required this.pageNumberOfMainDart})
: super(key: key);
#override
State<CustomNumberScroller> createState() => _CustomNumberScrollerState();
}
final dataKey = new GlobalKey();
final ScrollController _controller = ScrollController();
void _animateToIndex(int index) {
_controller.animateTo(
index * 50,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
}
class _CustomNumberScrollerState extends State<CustomNumberScroller> {
#override
Widget build(BuildContext context) {
Size media = MediaQuery.of(context).size;
return ...
}
}
you can use state management as provide and put scroll controller in class and access to controller in any place in widget tree
hope that helps you
get started with provider

Flutter SizeTransition only at first widget build

I made a widget 'ExpandableSection' which animates the child content by using a SizeTransition. It also works fine so far but I would like to have an additional parameter like "disableAtFirstBuild" so there is no initial animation but the widget is instantly shown. And only on rebuild the animation should be triggered. It seems like an easy task but I searched multiple hours for a solution without luck. For example I tried to set the animation duration to zero at first, invert a state boolean to save the fact that one build is done and afterwards set the duration to the normal value again. But somehow you cannot change an active controller. Is there a way to do it? Maybe it is quite easy and obvious but it is just not clear to me.
Any help would be much appreciated.
import 'package:flutter/widgets.dart';
class ExpandableSection extends StatefulWidget {
final Widget? child;
final bool? expand, useSliverScrollSafeMode;
final Axis axis;
ExpandableSection({this.expand = false, this.useSliverScrollSafeMode = false, this.axis = Axis.vertical, this.child});
#override
_ExpandableSectionState createState() => _ExpandableSectionState();
}
class _ExpandableSectionState extends State<ExpandableSection> with SingleTickerProviderStateMixin {
late AnimationController expandController;
late Animation<double> animation;
#override
void initState() {
super.initState();
prepareAnimations();
_runExpandCheck();
}
void prepareAnimations() {
expandController = AnimationController(vsync: this, duration: const Duration(milliseconds: 650));
animation = CurvedAnimation(
parent: expandController,
curve: Curves.easeInOutQuart,
);
}
void _runExpandCheck() {
if (widget.expand!) {
expandController.forward();
} else {
expandController.reverse();
}
}
#override
void didUpdateWidget(ExpandableSection oldWidget) {
super.didUpdateWidget(oldWidget);
_runExpandCheck();
}
#override
void dispose() {
expandController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
if (widget.useSliverScrollSafeMode! && !expandController.isAnimating && !widget.expand!) {
return SizedBox.shrink();
} else {
return SizeTransition(axisAlignment: -1, axis: widget.axis, sizeFactor: animation, child: Center(child: widget.child));
}
}
}
Add 'value' to your controller while creating it; like this:
expandController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 650),
value: widget.expand ? 650 : 0,
);
Try stoping the animation controller in initState and then calling .forward() whenever you want it to run.
#override
void initState() {
super.initState();
prepareAnimations();
_runExpandCheck();
expandController.stop();
}

The argument type '_ProfileImageState' can't be assigned to the parameter type 'TickerProvider'

The main objective is to allow the user to choose an image from the gallery/camera but in order to make things look good some animation has been used and entire image picking dialogue box has been designed
class _ProfileImageState extends State<ProfileImage>{
#override
File _image;
//ImagePickerHandler imagePicker;
#override
void initState() {
super.initState();
//initiating to start so that transition from one state to another is smooth
var _controller = new AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
imagePicker=new ImagePickerHandler(this.userImage(_image));
}
You need to use the SingleTickerProviderStateMixin mixin to use this as vsync param. You can achieve this by using with keyword here is how:
class _ProfileImageState extends State<ProfileImage> with SingleTickerProviderStateMixin {
#override
File _image;
//ImagePickerHandler imagePicker;
#override
void initState() {
super.initState();
var _controller = new AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
imagePicker=new ImagePickerHandler(this.userImage(_image));
}```
Extending SingleTickerProviderStateMixin fixed the issue:
class _ProfileImageState extends State with SingleTickerProviderStateMixin{

How to achieve this effect with flutter?

hi guys, I have encountered some problems in using flutter. I want to achieve the following effect, but I'm confused. I don't know how to implement it?
I am a novice, I hope to get your help, thank you!
Here is the code that I implemented part of the effect
class _RollImg extends StatefulWidget {
#override
_RollImgState createState() => _RollImgState();
}
class _RollImgState extends State<_RollImg>
with SingleTickerProviderStateMixin {
List headerImage = [
"https://wwc.alicdn.com/avatar/getAvatar.do?userIdStrV2=31CMmjAGPUw03*cOYWkyYNTT&type=taobao",
"https://wwc.alicdn.com/avatar/getAvatar.do?userIdStrV2=huHw8wzAtfMX8wA_MXrnoWTT&type=taobao",
"https://wwc.alicdn.com/avatar/getAvatar.do?userIdStrV2=V6A0RzvlA1i0*G51vpDHXgTT&type=taobao",
"https://wwc.alicdn.com/avatar/getAvatar.do?userIdStrV2=Iptw8l9fR4E8waiiLDV0*NTT&type=taobao",
"https://wwc.alicdn.com/avatar/getAvatar.do?userIdStrV2=8A1dnfk3l4jiK4pekJfCfgTT&type=taobao",
"https://wwc.alicdn.com/avatar/getAvatar.do?userIdStrV2=Qrzh71*ED0NOhRF2LIWWCWTT&type=taobao",
"https://wwc.alicdn.com/avatar/getAvatar.do?userIdStrV2=JFjoiMrl5aQELmtBc_4s7gTT&type=taobao",
"https://wwc.alicdn.com/avatar/getAvatar.do?userIdStrV2=SBGuL_2ypcDh5sU8IzqiwgTT&type=taobao",
"https://wwc.alicdn.com/avatar/getAvatar.do?userIdStrV2=SAbIH2IXAx1neurGXeYNfWTT&type=taobao",
"https://wwc.alicdn.com/avatar/getAvatar.do?userIdStrV2=31CMmjAGPUw03*cOYWkyYNTT&type=taobao"
];
AnimationController controller;
Animation<double> prompterAnimation;
#override
void initState() {
super.initState();
controller = AnimationController(
duration: Duration(milliseconds: 1600),
vsync: this,
)
..addListener(() {
setState(() {});
})
..repeat(reverse: true);
prompterAnimation = Tween<double>(begin: 1.0, end: S(60))
.chain(CurveTween(curve: Curves.easeInCubic))
.chain(CurveTween(curve: Interval(0.3, 0.8)))
.animate(controller);
}
#override
void dispose() {
super.dispose();
controller.dispose();
}
}

How to animate old page during transition in flutter?

I made a custom transition for my iOS project, and now I want to move the project to Flutter. The transition is fading out the old page, and fading in the new one.
But I cannot achieve this by overriding the PageRoute.
I did some research on this:
There's a similar question
Animate route that is going out / being replaced
From the accepted answer, I know there's a parameter 'secondaryAnimation' which may be useful to achieve it, but after trying to use the code from it, I still cannot animate the old page, all transitions have happened to the new page (the 'child' widget).
Can I get an 'old page' instance from the buildTransition method for animating? Or is there a better way to animate the old page?
Thanks!
I think that secondaryAnimation is used when transitioning to another page. So for your initial route, you'd have to specify the animation of it going away using secondaryAnimation and on your second page you use animation to animate how it appears.
It's a bit awkward that you have to use secondaryAnimation when creating the first route, because it means that it will be used for any transition away from that route. So, with PageRouteBuilder, you can't, for example, let the old page slide to the left when transitioning to page B but slide up when transitioning to page C.
I wrote two classes to achieve animating the old page.
PageSwitcherBuilder is a widget builder to animate old page.
PageSwitcherRoute is a route class to navigate new page.
Examples on DartPad
Here is my script.
class PageSwitcherBuilder extends StatefulWidget {
const PageSwitcherBuilder(
{Key? key,
required this.builder,
this.duration = const Duration(milliseconds: 500),
this.reverseDuration = const Duration(milliseconds: 500)})
: super(key: key);
final Duration duration;
final Duration reverseDuration;
final Widget Function(AnimationController controller) builder;
#override
State<PageSwitcherBuilder> createState() => _PageSwitcherBuilderState();
}
class _PageSwitcherBuilderState extends State<PageSwitcherBuilder>
with TickerProviderStateMixin {
late final AnimationController _controller = AnimationController(
vsync: this,
duration: widget.duration,
reverseDuration: widget.reverseDuration,
);
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return widget.builder(_controller);
}
}
class PageSwitcherRoute extends PageRouteBuilder {
PageSwitcherRoute({
required this.controller,
required Widget page,
}) : super(pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return page;
}) {
willDisposeAnimationController = false;
}
#override
final AnimationController controller;
#override
AnimationController createAnimationController() {
return controller;
}
}
You may also check this ZoomPageTransitionsBuilder class to change default transitions.
Workaround that I've come up with is to observe pushes and pops of routes and animte during these.
Create a Route Wrapper using RouteObserver
Run animation on didPushNext
Reverse animation on didPopNext
Wrap all screens that you want to animate on exit and on reenter.
import 'package:flutter/material.dart';
class ScreenSlideTransition extends StatefulWidget {
const ScreenSlideTransition({super.key, required this.child});
final Widget child;
#override
State<ScreenSlideTransition> createState() => _ScreenSlideTransitionState();
}
class _ScreenSlideTransitionState extends State<ScreenSlideTransition>
with RouteAware, TickerProviderStateMixin {
late final AnimationController _controller;
#override
Widget build(BuildContext context) {
final screenWidth = -MediaQuery.of(context).size.width;
return AnimatedBuilder( // Whatever animation you need goes here
animation: _controller,
builder: (BuildContext context, Widget? child) => Transform.translate(
offset: Offset(screenWidth * _controller.value, 0),
child: widget.child));
}
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 1000));
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context)!);
}
#override
void dispose() {
_controller.dispose();
routeObserver.unsubscribe(this);
super.dispose();
}
#override
void didPopNext() {
_controller.reverse();
super.didPopNext();
}
#override
void didPushNext() {
_controller.forward();
super.didPushNext();
}
}
In order to make the above code work make sure to initialise RouteObserver (see docs)
final RouteObserver<ModalRoute<void>> routeObserver = RouteObserver<ModalRoute<void>>();
void main() {
runApp(MaterialApp(
home: Container(),
navigatorObservers: <RouteObserver<ModalRoute<void>>>[ routeObserver ],
));
}
Remember to set the same Duration for AnimationController in ScreenSlideTransition and duration for transitionsBuilder if you want to synchronise in/out animation.