I have created the state currentPage for a carousel of images. My three possible events are increment/decrement and set page which will change the currently viewed page of the carousel. I'm using a timer to increment or reset the state after 5 seconds depending on what the currently viewed page is.
#override
void initState() {
super.initState();
Timer.periodic(const Duration(seconds: 5), (Timer timer) {
if (_currentPage < 2) {
context.read<CarouselBloc>().add(IncrementCurrentPage());
} else {
context.read<CarouselBloc>().add(SetCurrentPage(newPage: 0));
}
_pageController.animateToPage(_currentPage,
duration: const Duration(milliseconds: 300), curve: Curves.easeIn);
});
}
I now want to change the _currentPage variable to the state state.currentPage. But I don't know how to access the state from within my void initState function. I'm wrapping my carousel widget with a BlocProvider to read the CarouselBloc from the context and emit the events depending on the current page.
I hope I can get some help regarding the access of the state.currentPage from within the initState function.
try this:
var page = context.read<CarouselBloc>().state.currentPage
Related
Whenever my home page was reloaded my data was updated but I want to reflect data instantly.
That's why I need a method that can refresh my page or method after every 1 second(flutter).
pls, help me.
You can use the Timer.periodic to run a method every Duration you specify and using StatefulWidgetn you can run it in initState like this:
#override
void initState() {
Timer.periodic(Duration(seconds: 1), (timer) {
print("this will execute every second");
});
super.initState();
}
change the print with your method.
in Your init state call the Timer like this
#override
void initState() {
new Timer.periodic(Duration(seconds: 1), (Timer t) => YourMethod());//api call
super.initState();
}
this will update your full screen
This work's for me :smile:
Timer.periodic(Duration(milliseconds: 2200),
(timer) {
'Your Method'
debugPrint('Timer 1 sec ${timer.tick.toString()}');
});
I'm porting a offline Flutter game to online and the only difference in the code is that the new online code where the problem occurs has a active StreamSubscription being listened to. I can't find anything online other than 1 issue saying this is a bug.. any ideas on why dipose() is being called on the initial build?
class _OnlineSequenceState extends State<OnlineSequence> with SingleTickerProviderStateMixin {
//variable initialization would be here
#override
void initState(){
super.initState();
//setup gameRef
gameRef = FirebaseDatabase.instance.reference().child('sequence').child(widget.gameID);
//glow animation init
_setupGlowAnimtation();
//init sounds
_initSounds();
//setup player and card objects and create a stream
_setupGame();
}
#override
void dispose(){
print('disposing'); //prints on the widget being built for the first time
gameDataStream.cancel();
_animation.removeListener(() {});
_animationController.stop();
pool.dispose();
super.dispose();
}
_setupGlowAnimtation() {
_animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 1300));
_animationController.repeat(reverse: true);
_animation = Tween(begin: 1.0, end: 6.4).animate(_animationController)
..addListener(() {
setState(() {});
});
}
_initSounds() async {
drawSound = await pool.load(await rootBundle.load('lib/assets/sounds/draw.wav'));
playCardSound = await (pool.load(await rootBundle.load('lib/assets/sounds/playcard.wav')));
shuffleSound = await (pool.load(await rootBundle.load('lib/assets/sounds/shuffle.wav')));
pool.play(shuffleSound);
}
...
The error turned out to actually be in the prior lobby screen. The host of the game would navigate to in-game screen twice instead of once causing weird dispose() behavior. Once I fixed the double navigation the issue went away.
I am working On Tap Bounce feature on my widget. I have referred to these links for information:
Bouncing Button Flutter
Create on tap bounce on flutter
I got this package named as bouncing_widget, which was good enough for the workaround, but there is one limitation to it, i.e., It is not good for scrolling widget. You cannot scroll the page by tapping on the widget which uses this flutter bouncing widget
Somebody has already created a bug for the above widget, and no solution is found. Here is where you can find the issue: Bouncing Widget GitHub Issue
So, I decided to make my own widget which does the job for me. I have made the widget, and it works fine, but there is a limitation, i.e.,
When you scroll the page by holding on the widget, the widget stays there in one fixed position, that means, like it remains in pressed position
Here is my code:
import 'package:flutter/material.dart';
class CLBounceWidget extends StatefulWidget {
final Function onPressed;
final Widget child;
CLBounceWidget({Key key, #required this.onPressed, #required this.child}): super(key:key);
#override
CLBounceWidgetState createState() => CLBounceWidgetState();
}
class CLBounceWidgetState extends State<CLBounceWidget> with SingleTickerProviderStateMixin{
double _scale;
final Duration duration = Duration(milliseconds: 200);
AnimationController _animationController;
//Getting onPressed Calback
VoidCallback get onPressed => widget.onPressed;
#override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: duration,
lowerBound: 0.0,
upperBound: 0.1
)..addListener((){ setState((){}); });
super.initState();
}
#override
void dispose() {
// TODO: implement dispose
_animationController?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
_scale = 1 - _animationController.value;
return GestureDetector(
onTapDown: _onTapDown,
onTapUp: _onTapUp,
child: Transform.scale(
scale: _scale,
child: widget.child
)
);
}
// Triggering the onPressed callback with a check
void _onTapTrigger(){
if(onPressed != null){
onPressed();
}
}
//Start the animation
_onTapDown(TapDownDetails details){
_animationController.forward();
}
// We revise the animation and notify the user of the event
_onTapUp(TapUpDetails details){
Future.delayed(Duration(milliseconds: 100), (){
_animationController.reverse();
});
//Finally calling the callback function
_onTapTrigger();
}
}
Also: I have tried doing this, without using Future, but with that, Animation only happens when long pressed, just _onTapTrigger() works:
_onTapUp(TapUpDetails details){
_animationController.reverse();
_onTapTrigger();
}
Tried: I have tried using onLongPress, onLongPressEnd, onLongPressMoveUpdate to at least do the _animationController.reverse();, but nothing worked out for me.
I want the widget to stay normal when I scroll the page while holding the widget, like a normal widget performs.
Since, after a long more researches, and hours and hours of toil, I finally found out what I was willing to have in my project. I have created a package on flutter pub.dev to help other developers in need of what the package flutter_bounce has to offer.
You can search for flutter_bounce on the above link, or you can directly go to this: flutter_bounce
To make use of it, you just need to do this:
Bounce(
duration: Duration(milliseconds: 110),
onPressed: (){ YOUR_FUNCTION },
child: YOUR_WIDGET
)
For more details, please feel free to read the README of the link. It has all necessary details. Happy coding :)
Another new package that you guys can try is flutter_bounceable that I've developed. If you guys prefer a much more simple, interactive and customizable bounce widget, then this package is just for you.
Bounceable(
onTap: yourFunction, // set to null if want to disable bounceable
child: YourWidget(),
duration: const Duration(milliseconds: 200), // optional
reverseDuration: const Duration(milliseconds: 200), // optional
curve: Curves.decelerate, // optional
reverseCurve: Curves.decelerate, // optional
);
i am building an chat app. I want whenever the chat class open it scrolled to max initially.
i tried the below code but it's wrong
void initState() {
super.initState();
scrollController = ScrollController();
scrollController.animateTo(scrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 10), curve: Curves.easeOut);
}
I'm also building an app with chatting integrated, and I had the same problem. I fixed it by making it addPostFrameCallback when building. This is called everytime the widget is rebuilt.
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) {
scrollController.jumpTo(positionToScroll);
}
}
You can use animateTo instead of jumpTo and it should still work.
Probably, any scrollable widget is not rendering in initstate yet.
You can try to change the scroll position after your scrollable widget is ready.
Use addPostFrameCallback from SchedulerBinding to force ScrollController to move only when the building process completes, guaranteeing it has an initial position to move from :
Import Scheduler :
import 'package:flutter/scheduler.dart';
Modify your initState() :
void initState() {
super.initState();
scrollController = ScrollController();
SchedulerBinding.instance.addPostFrameCallback((_) => scrollController.animateTo(scrollController.position.maxScrollExtent, duration: Duration(milliseconds: 10), curve: Curves.easeOut));
}
My app contains a couple of pages. In the appbar I have a selfmade stateful widget with a badge that shows the number of new messages. When I swipe to refresh data the badge will run a small animation if the badge value is changed.
The problem is that the badge value comes from a scoped model. How do I run the animation from the scoped model class. I tried to let the scoped model class hold the animationController as well as a function. It works on the first and second screen. But when I am navigating back to the first page again and pull to refresh. It is like the animationController is in bad state.
Code in the scoped model:
Function _runNotificationAnimation;
set runNotificationAnimation(Function fun) => _runNotificationAnimation = fun;
void _setNotificationCount(int count) {
_notificationCount = count;
if (count > 0 && _runNotificationAnimation != null) {
_runNotificationAnimation();
}
notifyListeners();
}
function that runs the animation
runAnim() {
setState(() {
controller.reset();
controller.forward(from: 0.0);
});
}
Error from flutter:
[VERBOSE-2:shell.cc(184)] Dart Error: Unhandled exception:
NoSuchMethodError: The method 'stop' was called on null.
Receiver: null
Tried calling: stop(canceled: true)
0 Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
1 AnimationController.stop (package:flutter/src/animation/animation_controller.dart:650:13)
2 AnimationController.value= (package:flutter/src/animation/animation_controller.dart:349:5)
3 AnimationController.reset (package:flutter/src/animation/animation_controller.dart:370:5)
4 NotificationIconState.runAnim (package:volvopenta/widgets/notificaton_icon.dart:38:16)
5 SettingsModel._setNotificationCount (package:volvopenta/scoped-models/settings-model.dart:57:7)
6 SettingsModel.updateAppData (package:volvopenta/scoped-models/settings-model.dart:185:5)
7 MyMachines.build... (package:volvopenta/pages/fleet.dart:83:27)
8<…>
Since your animation will be built in a stateful Widget, it is better to leave the animationController in that stateful Widget and move only the animation (Tween) in the model class. It is essential that you place the notifyListener(); in the controller.addListerner() and not at the end of the function.
class MyModel extends Model{
Animation animation;
runAnimation(controller) {
animation = Tween(begin: 0,0, end:
400).animate(controller);
controller.forward();
controller.addListener((){
notifyListeners();
});
}
}
You can call this function in your stateful widget as follows:
class _MyScreenState extends State<MyScreen> with
SingleTickerProviderStateMixin{
AnimationController controller;
MyModel myModel = MyModel();
#overide
void initState(){
super.initState();
controller = AnimationController(duration: Duration(seconds: 2), vsync:
this);
myModel.runAnimation(controller);
}
//dispose here
#override
Widget build(Buildcontext context){
return ScopedModel<MyModel>(
model: myModel,
child: Scaffold(
body: Text("Hello", style: TextStyle(fontSize: 13 *
controller.value)),
),
);
}
}