How to achieve this effect with flutter? - 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();
}
}

Related

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();
}

Flutter determinate Linear Progress Bar not animating after the value changes

I want my linear progress bar to update progressively in stages, each time a user answers a question correctly in a quiz I have made.
I can't seem to get the progress bar to animate upon the value changes, however.
To note:
-My animation runs successfully, if I call my _animationController.forward from initState() (with some test values in the tween).
-I notify my AnimationController to run via notifications triggered using the Provider package as shown in the code below, when a question has been correctly answered, which is working.
-there are two values (original and new) that are input into the animation tween to tell the progress bar how much it should animate each time, are also correctly updating as this log shows.
I/flutter (18664): original value 0.0 and new value 0.0
I/flutter (18664): original value 0.0 and new value 0.25
import 'package:flutter/material.dart';
import 'package:learn_to_read/controllers/answerManager.dart';
import 'package:provider/provider.dart';
class AnswerProgressBar extends StatefulWidget {
const AnswerProgressBar({Key? key}) : super(key: key);
#override
_AnswerProgressBarState createState() => _AnswerProgressBarState();
}
class _AnswerProgressBarState extends State<AnswerProgressBar>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _anim;
late double _originalValue = 0;
late double _newValue = 0;
late int _localPoints;
late double _valueCompleted;
#override
void initState() {
double _originalValue = 0.0;
double _newValue = 0.0;
_animationController = AnimationController(
duration: Duration(milliseconds: 800), vsync: this);
_anim = Tween<double>(begin: _originalValue, end: _newValue)
.animate(_animationController)..addListener(() {
setState(() {
});
});
_localPoints = 0;
_valueCompleted = 0;
super.initState();
}
#override
void didChangeDependencies() {
_originalValue = _newValue;
if (Provider.of<AnswerManager>(context).pageTilesCompleted &&
_valueCompleted != 0) {
_localPoints++;
} else {
_localPoints = Provider.of<AnswerManager>(context).points;
}
_valueCompleted =
_localPoints / Provider.of<AnswerManager>(context).totalTilesPerPage;
_newValue = _valueCompleted;
_animationController.forward();
super.didChangeDependencies();
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
print('original value $_originalValue and new value $_newValue');
return AnimatedBuilder(
animation: _animationController,
builder: (context, i) => LinearProgressIndicator(
value: _anim.value,
backgroundColor: Colors.grey
),
);
}
}
Use set state
This will change the state as user will answer

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{

Stateful widget dispose method not called

I have a list if widgets that I swipe off the screen. On swipe, i remove the first widget from the list but i realized the dispose method of that widget is not called therefore the AnimationContoller is still held by flutter and used for the subsequent widgets. Animation for the subsequent widgets are ended by the time they are brought to the front. This makes my app not behave as expected. To test this, I print a string in the initState and dispose method of the widgets. The initState prints but the dispose method does not. Any help please ?
class ProfileWidget extends StatefulWidget {
ProfileWidget({Key key}) : super(key: key);
#override
State<StatefulWidget> createState() => _ProfileWidgetState();
}
class _ProfileWidgetState extends State<ProfileWidget> with TickerProviderStateMixin {
#override
void initState() {
super.initState();
print("New init");
_animationController = new AnimationController(
vsync: this,
duration: const Duration(milliseconds: 400),
);
_fadeAnimationController = new AnimationController(
vsync: this,
duration: const Duration(milliseconds: 200),
);
_fadeAnimation = new Tween(
begin: 0.0,
end: 1.0,
).animate(_fadeAnimationController);
_fadeAnimationController.forward();
}
#override
void dispose() {
print("Disposing");
if (_animationController != null) {
_animationController.dispose();
}
if (_fadeAnimationController != null) {
_fadeAnimationController.dispose();
}
super.dispose();
}
}
it's a known bug in flutter and the discussion is ongoing: https://github.com/flutter/flutter/issues/40940
even if you copy examples from official docs, it will not get called: https://flutter.dev/docs/cookbook/networking/web-sockets#complete-example
however flutter devs claim that this a desired behavior. Please voice your support in the github issue if you think it should be fixed.

Flutter manage animation controller from outside of class

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