Flutter - Boolean value keeps reseting after Navigator.pop() gets called - flutter

I have a class called Counter,
int value1;
bool isValueValid;
class Counter {
void init(Data data) {
if(data == null) {
value1 = 0;
isValueValid = true;
}
}
}
The method init() of Counter is called in the initState() of my app,
void initState() {
Counter().init(widget.data);
super.initState();
}
The value of value1 or isValueValid gets set to 0 and false respectively on the onTap() of the MaterialButton, however when I navigate to another page and then come back to the same page using Navigator.pop(), the value of isValueValid becomes true again even though it should be false. My method Counter().init is not called anywhere else my app.
MaterialButton(
height: 40,
onPressed: () {
if(value1 >= 1 || isValueValid) {
print('loop entered');
value1 = 0;
isValueValid = false;
setState(() {}
// I need to call `setState` to change the color of a `Container` which is dependent on the bool `isValueValid`
}
});

Related

How to define a function in a text widget?

void valuerandomer() {
Future.delayed(Duration(milliseconds: 500), () {
int count = 0;
int max = 1000;
int min = 1;
Random rnd = new Random();
while (count != -1) {
count++;
value += rnd.nextInt(6) + (-5);
}
if (value > (max - 1)) {
value = 999;
} else if (value < 0) {
value = 0;
}
print(value);
});
}
I want the function to print every 500 miliseconds in the text widget so the value parameter starts with the value of 75 and changes every 500 milliseconds with this function.
How do I do that?
How do I declare this function in the text widget like Text('$valuerandomer')? cuz its just dont work. I tried just to type there $value but still doesnt work
For every x time, try using Timer.periodic
Timer? _timer;
String text = "initText";
#override
void dispose() {
_timer?.cancel();
super.dispose();
}
void valuerandomer() {
_timer = Timer.periodic(
Duration(milliseconds: 500),
(t) {
//perform your work
text = "newText ";
setState(() {});
},
);
}
Use funtion
Timer.periodic(Duration(/..),(timer){
//Put your logic
setState((){});
})

Undefined name '_change' when I tried to call it inside a method | flutter

I declared a counter as int and call it in a method, but i got an error of undefined counter name inside a method. //_flutter
Code:
//...proceed from statefulWidget
int _change = 0;
List view = [ ("jS), ("reactN") ];
//Method
void _myList () {
setState(() {
_change += 1;
});
}// End statefulWidget
I was wondering if there is any way I can get help to solve this little bug!
int change = 0;
List<String> view = ["jS", "reactN"];
// Your Method
void _myList () {
setState(() {
change = change + 1;
});
}
/// call your method like
onTap: () {
_myList();
}

Managing multiple setState() methods in single class?

I am creating a timer when it will come to 0. It will navigate to the next Page.(Not created navigation yet). Till the timer is on user can answer the questions. The problem is I want to start the timer as the StartGame() file opens. In main.dart I have created a navigation for this on click on button. But when this page loads it automatically calls both ( in void getNum() and startTime() ) setState methods() one by one. Therefore answers (options) that I created as buttons automatically changes without onPressed by user. But I only want startTime() method to be called once as widget builds / inits. then after the getNum() method on every click of user.
How do i make these two setState() methods to be called individually without affecting each other.
class StartGame extends StatefulWidget {
StartGameState createState() => StartGameState();
}
class StartGameState extends State<StartGame> {
int no1, no2, no3, no4, inp1, inp2;
int pos;
int res;
List<int> answers;
GenerateQuestion g = new GenerateQuestion();
void getNum() {
answers = g.generateNum();
pos = g.answerPosition();
inp1 = g.generateValue();
inp2 = g.generateValue();
res = inp1 + inp2;
answers.add(res);
answers.shuffle();
setState(() {
no1 = answers[0];
no2 = answers[1];
no3 = answers[2];
no4 = answers[3];
print("set state 1 called");
});
} // void get Num ends here
//counter timer starts from herer
int counter = 10;
Timer timer;
void startTime() {
counter = 10;
timer = new Timer.periodic(Duration(seconds: 1), (timer) {
if (counter > 0) {
setState(() {
counter--;
print("set state 2 called");
});
} else {
timer.cancel();
}
});
}
You can achieve this using the initState() method, it gets only called once when the widget is built.
class _StartGameState extends State<StartGame> {
#override
void initState() {
startTime(); //this function only gets called once
super.initState();
}
//your Code...

Flutter detect triple tap

I would like to be able to detect a triple tap (or even more) in a Flutter widget, although GestureDetector only has detection for double-tap built in.
What is the easiest way for me to detect a triple tap on a widget?
(I want continually clicking on a part of the screen to unlock some developer options)
Was a bit lazy with this one, in reality it's not that hard
// init
int lastTap = DateTime.now().millisecondsSinceEpoch;
int consecutiveTaps = 0;
GestureDetector(
onTap: () {
int now = DateTime.now().millisecondsSinceEpoch;
if (now - lastTap < 1000) {
print("Consecutive tap");
consecutiveTaps ++;
print("taps = " + consecutiveTaps.toString());
if (consecutiveTaps > 4){
// Do something
}
} else {
consecutiveTaps = 0;
}
lastTap = now;
},
child: ...
)
I tried the method mentioned here, but it didn't work for me. GestureDetector onTap is called only once,
regardless of the number of taps. Probably something has changed in flutter (I'm on the beta channel).
However, I dug into the source code of flutter and come to the solution (https://api.flutter.dev/flutter/gestures/SerialTapGestureRecognizer-class.html):
import "package:flutter/gestures.dart";
RawGestureDetector(gestures: {
SerialTapGestureRecognizer:
GestureRecognizerFactoryWithHandlers<SerialTapGestureRecognizer>(
() =>SerialTapGestureRecognizer(), (SerialTapGestureRecognizer instance) {
instance.onSerialTapDown = (SerialTapDownDetails details) {
if (details.count == 3) print("Consecutive tap 3");
};
})
I took a little different approach. Instead of having to compare timestamps, I set a Timer, which will reset the tapped state. But each time there is a tap, the old timer is canceled.
Timer? devPageClickTimer;
num devPageTapped = 0;
final devPageTapGoal = 5;
GestureDetector(
onTap: () {
devPageTapped++;
if (devPageTapped >= devPageTapGoal) {
router.push(const DeveloperRoute());
}
if (devPageClickTimer != null) {
devPageClickTimer!.cancel();
}
devPageClickTimer = Timer(const Duration(milliseconds: 200), () => devPageTapped = 0);
},
I have tried this method with reduced timeout and with both double and triple tap
int lastTap = DateTime.now().millisecondsSinceEpoch;
int consecutiveTaps = 1;
GestureDetector(
onTap: () {
int now = DateTime.now().millisecondsSinceEpoch;
if (consecutiveTaps == 1) {
print("taps = " + consecutiveTaps.toString());
lastTap = now;
}
if (now - lastTap < 300) {
print("Consecutive tap");
consecutiveTaps++;
print("taps = " + consecutiveTaps.toString());
if (consecutiveTaps == 3) {
print("Consecutive tap 3");
} else if (consecutiveTaps == 2) {
print("Consecutive tap 2");
}
} else {
consecutiveTaps = 1;
}
lastTap = now;
},
child: \\child);
Relevant solution.
Here is flexible reusable multiple tap widget based on Listener widget that reports raw pointer events:
class AppMultipleTap extends StatefulWidget {
final Widget child;
final VoidCallback onMultipleTap;
final int taps;
final Duration duration;
const AppMultipleTap({
super.key,
required this.child,
required this.onMultipleTap,
/// feel free to override these values
this.taps = 3,
this.duration = const Duration(milliseconds: 600),
});
#override
State<AppMultipleTap> createState() => _AppMultipleTapState();
}
class _AppMultipleTapState extends State<AppMultipleTap> {
/// in _count we store current number of taps
int _count = 0;
Timer? _timer;
#override
Widget build(BuildContext context) {
return Listener(
onPointerDown: (_) {
if (_timer == null) _startTimer();
_count++;
},
child: widget.child,
);
}
void _startTimer() {
_timer = Timer(widget.duration, () {
/// you can change this condition to ==, if you need 100% match
if (_count >= widget.taps) {
widget.onMultipleTap.call();
}
_timer = null;
_count = 0;
});
}
}
Then you can use it like that:
#override
Widget build(BuildContext context) {
return AppMultipleTap(
onMultipleTap: /// Do some action
I like this simple approach, without so many nested if blocks.
// Variables in the state class
var startTap = timeNow;
var consecutiveTaps = 0;
static const int serialTaps = 4;
static const int tapDurationInMs = 1000;
static int get timeNow => DateTime.now().millisecondsSinceEpoch;
// Build method
GestureDetector(
onTap: () {
final now = timeNow;
final userExceededTapDuration = now - startTap > tapDurationInMs;
if (userExceededTapDuration) {
consecutiveTaps = 0;
startTap = now;
}
consecutiveTaps++;
if (consecutiveTaps == serialTaps) {
// widget.onTap();
}
},
);

Flutter- detect memory leak

I'm little bit confused because I was thinking there are no memory leak in flutter since there is no concept of weak (if I'm correct).
I'm running this on iOS device.
I'm trying to play videos and initialize some videos beforehand so that user can see it without delay.
To do that I prepared six VideoPlayerController and make those always being initialized while current video is playing.
There are three more initialized VideoPlayerController next to current one and two more initialized ones before current one like image below.
With this logic I play video very smoothly back and forth. But after play about ten videos, app crush because of memory issue.
I tried every function Future, async, await but still eats lots of memories.
I'm not sure but it might be NotificationListener?
Since onNotification returns bool not Future or
is this something to do with main thread or something?
Does anyone know how to fix this memory issue?
Code:
class _SwiperScreenState extends State<SwiperScreen> {
VideoPlayerController _firstController;
VideoPlayerController _secondController;
VideoPlayerController _thirdController;
VideoPlayerController _fourthController;
VideoPlayerController _fifthController;
VideoPlayerController _sixthController;
List<VideoPlayerController> _controllers;
List<String> urls = [
'https://firebasestorage.googleapis.com/v0/b/waitingboy-34497.appspot.com/o/video%2F8-21%2F1534825377992OsfJfKsdf90K8sf?alt=media&token=12245ee4-1598-4f7e-ba28-a9eb72ca474e',
'http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_20mb.mp4',
'https://firebasestorage.googleapis.com/v0/b/waitingboy-34497.appspot.com/o/video%2F8-21%2F1534825377992OsfJfKsdf90K8sf?alt=media&token=12245ee4-1598-4f7e-ba28-a9eb72ca474e',
'http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_20mb.mp4',
];
int currentIndex = 0; //refer to current playing controller index
int videosIndex = 0; //refer to current playing urls index
bool _didGetNotification(ScrollNotification notification) {
if (notification is UserScrollNotification) {
if (notification.direction.toString() == 'ScrollDirection.reverse') {
//swipe to left so add one more video
videosIndex++;
//modify index so that always in the range of 0 ~ 5.
if (currentIndex <= 2) {
final int prepareIndex = currentIndex + 3;
urls.add(
'https://firebasestorage.googleapis.com/v0/b/waitingboy-34497.appspot.com/o/video%2F8-21%2F1534825377992OsfJfKsdf90K8sf?alt=media&token=12245ee4-1598-4f7e-ba28-a9eb72ca474e');
_initVideo(urls[videosIndex], prepareIndex);
} else {
final int prepareIndex = (currentIndex + 3) - 6;
urls.add(
'http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_20mb.mp4');
_initVideo(urls[videosIndex], prepareIndex);
}
}
if (notification.direction.toString() == 'ScrollDirection.forward') {
//swipe to right so back one more video
videosIndex--;
//modify index so that always in the range of 0 ~ 5 .
if (currentIndex >= 2) {
final int videoIndex = videosIndex - 2;
final int prepareIndex = currentIndex - 2;
_initVideo(urls[videoIndex], prepareIndex);
} else {
final int videoIndex = videosIndex - 2;
final int prepareIndex = 4 + currentIndex;
_initVideo(urls[videoIndex], prepareIndex);
}
}
}
return true;
}
Future _initVideo(String url, int initIndex) async {
if (_controllers[initIndex] != null) {
await _controllers[initIndex].dispose();
}
_controllers[initIndex] = new VideoPlayerController.network(url);
await _controllers[initIndex].initialize().then((_) async => await _controllers[initIndex].setLooping(true));
setState(() {});
}
Future _initFirstThree() async {
for (int i = 1; i < urls.length; i++) {
await _initVideo(urls[i], i);
}
}
#override
void initState() {
_controllers = [
_firstController,
_secondController,
_thirdController,
_fourthController,
_fifthController,
_sixthController
];
_initVideo(urls[0], 0).then((_) => _controllers[0].play());
_initFirstThree();
super.initState();
}
#override
void deactivate() {
_controllers[currentIndex].setVolume(0.0);
_controllers[currentIndex].pause();
super.deactivate();
}
#override
void dispose() {
_controllers.forEach((con) {
con.dispose();
});
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Swiper'),
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.disc_full),
onPressed: () {
Navigator
.of(context)
.push(MaterialPageRoute(builder: (context) => Dissmiss()));
},
)
],
),
body: new NotificationListener(
onNotification: _didGetNotification,
child: new Swiper(
itemCount: 6,
itemBuilder: (BuildContext context, int index) {
return _controllers[index].value.initialized
? new AspectRatio(
aspectRatio: _controllers[index].value.aspectRatio,
child: new VideoPlayer(_controllers[index]),
)
: new Center(child: new CircularProgressIndicator());
},
loop: urls.length > 6 ? true : false,
onIndexChanged: (i) async {
currentIndex = i;
final int pauseIndex = i == 0 ? 5 : i - 1;
await _controllers[pauseIndex].pause().then((_) async {
await _controllers[i].play();
});
},
),
),
);
}
}