Flutter: Continuation of the future - flutter

I go from page 1 to page 2. The counting process starts on page 2. As this continues, I return to page 1. Even if I exit page 2, the process continues. Why is this happening? How can I prevent this?
Future.delayed keeps working when I return to page 1 from page 2.
This is page 1. There is only one button to go to page 2.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:untitled1/page2.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> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.black38,
),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => Page2()));
},
child: Text(
'Page 2',
),
),
],
),
),
);
}
}
This is page 2.
import 'package:flutter/material.dart';
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage2(),
);
}
}
class MyHomePage2 extends StatefulWidget {
#override
_MyHomePage2State createState() => _MyHomePage2State();
}
class _MyHomePage2State extends State<MyHomePage2> {
int d=0;
#override
void initState() {
// TODO: implement initState
for (int c = 0; c < 25; c++) {
Future.delayed(Duration(seconds: c), () {
setState(() {
d++;
});
});
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
' $d',
),
],
),
),
);
}
}

if(!mounted){
return;
}
It happened thanks to the above. If I write one, it will probably suffice. I don't know if this is a valid solution.
void initState() {
// TODO: implement initState
for (int c = kk; c < 25; c++) {
if(!mounted){
return;
}
Future.delayed(Duration(seconds: c), () {
if(!mounted){
return;
}
setState(() {
d++;
});
});
if(!mounted){
return;
}
}
super.initState();
}

Related

how to unfocus texfield and hide keybaord on paste flutter

I have a textfield on which i mostly paste content so i want to unfocus textfield and hide keybaord on paste so i have achive to handle on paste using textfield selectionControls but the problem is focusing and keybaord which is reopening i have tired all focus methods to unfocus here is my code
import 'package:flutter/material.dart';
main() => runApp(const App());
class App extends StatelessWidget {
const App({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(home: Home());
}
}
class Home extends StatelessWidget {
const Home({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8),
child: Center(
child: TextField(
selectionControls: MySelectionControls(
onPaste: () {
print('onPaste');
// FocusManager.instance.primaryFocus?.unfocus();
// Focus.of(context).unfocus();
// FocusScope.of(context).unfocus();
// FocusScope.of(context).requestFocus(FocusNode());
// FocusScopeNode currentFocus = FocusScope.of(context);
// if (!currentFocus.hasPrimaryFocus) {
// currentFocus.focusedChild?.unfocus();
// }
},
),
),
),
),
),
);
}
}
class MySelectionControls extends MaterialTextSelectionControls {
final Function onPaste;
MySelectionControls({required this.onPaste});
#override
Future<void> handlePaste(TextSelectionDelegate delegate) {
onPaste();
return super.handlePaste(delegate);
}
}
Try this one
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({key});
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
TextSelectionControls? _textSelectionControls;
#override
void initState() {
// TODO: implement initState
super.initState();
_textSelectionControls = MySelectionControls(onPaste: onPaste);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8),
child: Center(
child: Column(
children: [
TextField(
selectionControls: _textSelectionControls,
),
],
),
),
),
),
);
}
Future<void> onPaste(final TextSelectionDelegate? delegate) async {
Future.delayed(Duration(milliseconds: 100), () {
FocusScope.of(context).requestFocus(FocusNode());
});
}
}
class MySelectionControls extends MaterialTextSelectionControls {
MySelectionControls({required this.onPaste});
ValueChanged<TextSelectionDelegate> onPaste;
#override
Future<void> handlePaste(TextSelectionDelegate delegate) async {
onPaste(delegate);
return super.handlePaste(delegate);
}
}
I have tested this and its working

Flutter initState called every time I re-enter a page

I have three pages, A, B, C, and I navigate between them through a Drawer.
My goal is to get initState to be called only once (when the page is inserted in the widget tree), so that the state of each page is not reinitialized when I return to it.
My fist try was to use Navigator.of(context).PushNamed(routeName) as shown in the code below.
Probably this doesn't work because if from A I call B and then A again, the navigator stack is
[A] --> [B, A] --> [A, B, A] and not
[A] -> [B, A] --> [A]
so a navigation based on pop() should be more appropriate. I tried with
onTap: () {
Navigator.of(context).canPop()
? Navigator.of(context)
.popUntil(ModalRoute.withName(PageA.routeName))
: Navigator.of(context).pushNamed(PageA.routeName);
},
instead of onTap: () => Navigator.of(context).pushNamed(PageA.routeName)
But it doesn't work: when I tap on a drawer item a black screen appears, without any exception or warning, as if the navigator called a blank screen...
What am I doing wrong? Any idea how to fix?
This is my code:
main.dart
import 'package:flutter/material.dart';
import 'page_c.dart';
import 'page_a.dart';
import 'page_b.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Navigation test',
home: PageA(),
routes: {
PageA.routeName: (ctx) => PageA(),
PageB.routeName: (ctx) => PageB(),
PageC.routeName: (ctx) => PageC(),
},
);
}
}
my_drawer.dart
import 'package:flutter/material.dart';
import 'page_b.dart';
import 'page_c.dart';
import 'page_a.dart';
class MyDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: [
SizedBox(
height: 100,
),
ListTile(
title: Text('PAGE A'),
onTap: () => Navigator.of(context).pushNamed(PageA.routeName)),
ListTile(
title: Text('PAGE B'),
onTap: () => Navigator.of(context).pushNamed(PageB.routeName)),
ListTile(
title: Text('PAGE C'),
onTap: () => Navigator.of(context).pushNamed(PageC.routeName)),
],
),
);
}
}
page_a.dart
import 'package:flutter/material.dart';
import 'my_drawer.dart';
class PageA extends StatefulWidget {
static const routeName = '/route-a';
#override
_PageAState createState() => _PageAState();
}
class _PageAState extends State<PageA> {
#override
void initState() {
print('PAGE A INIT STATE');
super.initState();
}
// void didChangeDependencies() {
// print('PAGE A DID CHANGE DEPENDECIES');
// super.didChangeDependencies();
// }
// #override
// void dispose() {
// print('PAGE A DISPOSE');
// super.dispose();
// }
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('PAGE A')),
drawer: MyDrawer(),
body: Center(
child: Text('A', style: TextStyle(fontSize: 100)),
),
);
}
}
page_b.dart
import 'package:flutter/material.dart';
import 'my_drawer.dart';
class PageB extends StatefulWidget {
static const routeName = '/route-b';
#override
_PageBState createState() => _PageBState();
}
class _PageBState extends State<PageB> {
#override
void initState() {
print('PAGE B INIT STATE');
super.initState();
}
// void didChangeDependencies() {
// print('PAGE B DID CHANGE DEPENDECIES');
// super.didChangeDependencies();
// }
// #override
// void dispose() {
// print('PAGE B DISPOSE');
// super.dispose();
// }
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('PAGE B')),
drawer: MyDrawer(),
body: Center(
child: Text('B', style: TextStyle(fontSize: 100)),
),
);
}
}
page_c.dart
import 'package:flutter/material.dart';
import 'my_drawer.dart';
class PageC extends StatefulWidget {
static const routeName = '/route-c';
#override
_PageCState createState() => _PageCState();
}
class _PageCState extends State<PageC> {
#override
void initState() {
print('PAGE C INIT STATE');
super.initState();
}
// void didChangeDependencies() {
// print('PAGE C DID CHANGE DEPENDECIES');
// super.didChangeDependencies();
// }
// #override
// void dispose() {
// print('PAGE C DISPOSE');
// super.dispose();
// }
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('PAGE C')),
drawer: MyDrawer(),
body: Center(
child: Text('C', style: TextStyle(fontSize: 100)),
),
);
}
}

Need Help in getting respective value from a custom widget

I am a noob in flutter and i need help with this. So I made this counter widget where you can increase and decrease the counter value with button, and called that widget two times in my root widget. now I want to get respective counter value of those counter widget separately for each time I call my counter widget. How do I achieve that.
this is my main.dart file
class _MyHomePageState extends State<MyHomePage> {
int count;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
CounterContainer(count, ValueKey(1)),
Text('first counter : ${CounterContainer(count, ValueKey(1)).count}'),
CounterContainer(count, ValueKey(2)),
Text('second counter : ${CounterContainer(count, ValueKey(2)).count}'),
],
),
),
);
}
}
this is my Counter_widget
class CounterContainer extends StatefulWidget {
int count;
CounterContainer(this.count, ValueKey<int> valueKey);
#override
_CounterContainerState createState() => _CounterContainerState();
}
class _CounterContainerState extends State<CounterContainer> {
int _counter = 0;
void _incrementCounter() {
setState(() {
widget.count = ++_counter;
print('------------>${widget.count}');
});
}
void _decrementCounter() {
setState(() {
if (_counter > 0) {
widget.count = --_counter;
print('------------>${widget.count}');
}
});
}
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
FlatButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
Text('$_counter'),
FlatButton(
onPressed: _decrementCounter,
child: Icon(Icons.remove),
),
],
);
}
}
You can copy paste run full code below
You can define two counters counter1 and counter2 and pass callback to do refresh
working demo
code snippet
void _incrementCounter() {
setState(() {
...
});
widget.callback();
}
void _decrementCounter() {
setState(() {
...
});
widget.callback();
}
...
CounterContainer counter1;
CounterContainer counter2;
void refresh() {
print("refresh");
setState(() {});
}
#override
void initState() {
counter1 = CounterContainer(count, ValueKey(1), refresh);
counter2 = CounterContainer(count, ValueKey(2), refresh);
super.initState();
}
...
children: <Widget>[
counter1,
Text('first counter : ${counter1.count}'),
counter2,
Text('second counter : ${counter2.count}'),
],
full code
import 'package:flutter/material.dart';
class CounterContainer extends StatefulWidget {
int count;
VoidCallback callback;
CounterContainer(this.count, ValueKey<int> valueKey, this.callback);
#override
_CounterContainerState createState() => _CounterContainerState();
}
class _CounterContainerState extends State<CounterContainer> {
int _counter = 0;
void _incrementCounter() {
setState(() {
widget.count = ++_counter;
print('------------>${widget.count}');
});
widget.callback();
}
void _decrementCounter() {
setState(() {
if (_counter > 0) {
widget.count = --_counter;
print('------------>${widget.count}');
}
});
widget.callback();
}
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
FlatButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
Text('$_counter'),
FlatButton(
onPressed: _decrementCounter,
child: Icon(Icons.remove),
),
],
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int count;
CounterContainer counter1;
CounterContainer counter2;
void refresh() {
print("refresh");
setState(() {});
}
#override
void initState() {
counter1 = CounterContainer(count, ValueKey(1), refresh);
counter2 = CounterContainer(count, ValueKey(2), refresh);
super.initState();
}
#override
Widget build(BuildContext context) {
print('${counter1.count}');
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
counter1,
Text('first counter : ${counter1.count}'),
counter2,
Text('second counter : ${counter2.count}'),
],
),
),
);
}
}

flutter: child widget not rebuilt after parent rebuild

Version:
Flutter-Version: 1.12.14 channel dev
Dart-Version: 2.7.0
Question:
I wan write a Todo App. when i click floatbutton add a new Todo, but in some cases its not work well.
The problem in Scaffold.body, detials in code.
it work well when i use TodoPage(todoList: _todoList).
_pageList.elementAt(_activeIndex) is not work when i submit textfield .
I found the print('Build Home')print after submit but print('Build TodoPage') not print.
why???
My Code:
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget{
#override
Widget build(BuildContext context){
return MaterialApp(
title: 'TodoList',
home: Home(),
);
}
}
class Home extends StatefulWidget{
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home>{
List<String> _todoList = ['a', 'b', 'c'];
TextEditingController _controller;
List<Widget> _pageList;
int _activeIndex;
Widget _curPage;
#override
void initState(){
super.initState();
_activeIndex = 0;
_pageList = [TodoPage(todoList: _todoList,), OtherPage()];
_curPage = _pageList[_activeIndex];
_controller = TextEditingController();
}
#override
Widget build(BuildContext context){
print('build Home');
return Scaffold(
appBar: AppBar(title: Text('Todo'),),
body: _pageList.elementAt(_activeIndex), // this is not work
// body: TodoPage(todoList: _todoList,), // this is work well
floatingActionButton: FloatingActionButton(
onPressed: _openDlg,
child: Icon(Icons.add),
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.list), title: Text('Todo')),
BottomNavigationBarItem(icon: Icon(Icons.favorite), title: Text('Other')),
],
currentIndex: _activeIndex,
selectedItemColor: Colors.blue,
onTap: _onMenuTap,
),
);
}
_onMenuTap(int index){
setState(() {
_activeIndex = index;
});
}
_openDlg(){
showDialog(
context: context,
builder: (BuildContext context){
return SimpleDialog(
children: <Widget>[
TextField(
controller: _controller,
),
SimpleDialogOption(
child: FloatingActionButton(child: Text('submit'), onPressed: _addTodo,),
)
],
);
}
);
}
_addTodo(){
print(_controller.text);
setState(() {
_todoList.add(_controller.text);
});
}
}
class TodoPage extends StatefulWidget{
TodoPage({Key key, this.todoList}): super(key: key);
List<String> todoList;
_TodoPageState createState() => _TodoPageState();
}
class _TodoPageState extends State<TodoPage>{
#override
void initState(){
super.initState();
}
#override
Widget build(BuildContext context){
print('build TodoPage');
return Column(
children: _buildTodoList(),
);
}
List <Widget> _buildTodoList(){
return widget.todoList.map((todo){
return Text(todo, style: TextStyle(fontSize: 30),);
}).toList();
}
}
class OtherPage extends StatelessWidget{
#override
Widget build(BuildContext context){
return Center(child: Text('Other Page'));
}
}
That is logical.
You are reusing an existing instance of a Widget, and widgets are immutable.
As such, the framework notice that the instance of the widget did not change and doesn't call build to optimize performances.
Your problem being, you violated the rule of widgets being immutable, which makes this optimization break your app.
What you did:
class MyState extends State<MyStatefulWidget> {
SomeWidget myWidget = SomeWidget()..someProperty = "initial value";
void onSomething() {
setState(() {
myWidget.someProperty = "new value";
});
}
#override
Widget build(BuildContext context) {
return myWidget;
}
}
What you should instead do:
class MyState extends State<MyStatefulWidget> {
SomeWidget myWidget = SomeWidget(someProperty: "initial value");
void onSomething() {
setState(() {
myWidget = SomeWidget(someProperty: "new value");
});
}
#override
Widget build(BuildContext context) {
return myWidget;
}
}
Alternatively, just don't cache the widget instance at all.

Flutter switch between fragments by supporting back to previous fragment

in this link in SF, #martinseal1987 show us how can we use separated widgets link with android fragments.
I implemented this solution on my project and after running project i dont have any problem to show first widgets as an Fragment, but when i press to back button my screen goes to black and couldn't back to previous widgets as an fragment
i think that is should be this:
Problem is on navigateBack and customPop methods and i can attach fragment by pressing on button
import 'package:flutter/material.dart';
void main()
{
runApp(MaterialApp(
title: 'AndroidMonks',
home: Scaffold(
appBar: AppBar(
title: Text('Androidmonks'),
backgroundColor: Colors.orangeAccent,
),
body: Home(),
),
));
}
class Home extends StatefulWidget {
Home({
Key key,
}) : super(key: key);
#override
State<Home> createState()=>_Home();
}
class _Home extends State<Home> {
String title = "Title";
int _currentIndex = 0;
final List<int> _backstack = [0];
#override
Widget build(BuildContext context) {
navigateTo(_currentIndex);
//each fragment is just a widget which we pass the navigate function
List<Widget> _fragments =[Fragment1(),Fragment2(),Fragment3()];
//will pop scope catches the back button presses
return WillPopScope(
onWillPop: () {
customPop(context);
},
child: Scaffold(
body: Column(
children: <Widget>[
RaisedButton(
child:Text('PRESS'),
onPressed: (){
_currentIndex++;
navigateTo(_currentIndex);
},
),
Expanded(
child: _fragments[_currentIndex],
),
],
),
),
);
}
void navigateTo(int index) {
_backstack.add(index);
setState(() {
_currentIndex = index;
});
_setTitle('$index');
}
void navigateBack(int index) {
setState(() {
_currentIndex = index;
});
_setTitle('$index');
}
customPop(BuildContext context) {
if (_backstack.length - 1 > 0) {
navigateBack(_backstack[_backstack.length - 1]);
} else {
_backstack.removeAt(_backstack.length - 1);
Navigator.pop(context);
}
}
//this method could be called by the navigate and navigate back methods
_setTitle(String appBarTitle) {
setState(() {
title = appBarTitle;
});
}
}
class Fragment2 extends StatefulWidget {
#override
State<Fragment2> createState() => _Fragment2();
}
class _Fragment2 extends State<Fragment2> {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text("_Fragment2"),
onPressed: (){
}),
);
}
}
class Fragment1 extends StatefulWidget {
#override
State<Fragment1> createState() => _Fragment1();
}
class _Fragment1 extends State<Fragment1> {
#override
Widget build(BuildContext context) {
return Center(
child: Text("_Fragment1"),
);
}
}
class Fragment3 extends StatefulWidget {
#override
State<Fragment3> createState() => _Fragment3();
}
class _Fragment3 extends State<Fragment3> {
#override
Widget build(BuildContext context) {
return Center(
child: Text("_Fragment3"),
);
}
}
I fixed some logic in your code please carefully check the changes, if you have any question don't hesitate, here is the working code
import 'package:flutter/material.dart';
void main()
{
runApp(MaterialApp(
title: 'AndroidMonks',
home: Scaffold(
appBar: AppBar(
title: Text('Androidmonks'),
backgroundColor: Colors.orangeAccent,
),
body: Home(),
),
));
}
class Home extends StatefulWidget {
Home({
Key key,
}) : super(key: key);
#override
State<Home> createState()=>_Home();
}
class _Home extends State<Home> {
String title = "Title";
List<Widget> _fragments =[Fragment1(),Fragment2(),Fragment3()];
int _currentIndex = 0;
final List<int> _backstack = [0];
#override
Widget build(BuildContext context) {
//navigateTo(_currentIndex);
//each fragment is just a widget which we pass the navigate function
//will pop scope catches the back button presses
return WillPopScope(
onWillPop: () {
return customPop(context);
},
child: Scaffold(
body: Column(
children: <Widget>[
RaisedButton(
child:Text('PRESS'),
onPressed: (){
_currentIndex++;
navigateTo(_currentIndex);
},
),
Expanded(
child: _fragments[_currentIndex],
),
],
),
),
);
}
void navigateTo(int index) {
_backstack.add(index);
setState(() {
_currentIndex = index;
});
_setTitle('$index');
}
void navigateBack(int index) {
setState(() {
_currentIndex = index;
});
_setTitle('$index');
}
Future<bool> customPop(BuildContext context) {
print("CustomPop is called");
print("_backstack = $_backstack");
if (_backstack.length > 1) {
_backstack.removeAt(_backstack.length - 1);
navigateBack(_backstack[_backstack.length - 1]);
return Future.value(false);
} else {
return Future.value(true);
}
}
//this method could be called by the navigate and navigate back methods
_setTitle(String appBarTitle) {
setState(() {
title = appBarTitle;
});
}
}
class Fragment2 extends StatefulWidget {
#override
State<Fragment2> createState() => _Fragment2();
}
class _Fragment2 extends State<Fragment2> {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text("_Fragment2"),
onPressed: (){
}),
);
}
}
class Fragment1 extends StatefulWidget {
#override
State<Fragment1> createState() => _Fragment1();
}
class _Fragment1 extends State<Fragment1> {
#override
Widget build(BuildContext context) {
return Center(
child: Text("_Fragment1"),
);
}
}
class Fragment3 extends StatefulWidget {
#override
State<Fragment3> createState() => _Fragment3();
}
class _Fragment3 extends State<Fragment3> {
#override
Widget build(BuildContext context) {
return Center(
child: Text("_Fragment3"),
);
}
}
You can achieve this type of navigation using LocalHistoryRoute.of(context).addLocalHistoryEntry and Navigator.pop().