When I leave a page when I work with flutter and then re-enter it, the old values are saved.
I don't want this to happen.
For example, when I first enter:
int number = 1;
class TestPage extends StatefulWidget {
#override
_TestPageState createState() => _TestPageState();
}
bool donus = true;
class _TestPageState extends State<TestPage> {
List<Todo> sorular = new List<Todo>();
#override
void initState() {
print(donus);
super.initState();
getTodos();
}
bool pressAttention = true;
String ileri = "İleri", geri = "Geri";
#override
Widget build(BuildContext context) {number++;
print(number);
output:1
Second entry to the page:
output:2
I do not know how to fix this.
The scope of your number variable is outside the scope of your page and its state.
number is essentially static or global, and its lifetime is tied to your application's. Tighten up its scope so that it is declared within your state class and initialise it in your initState method (for private non-final variables).
class TestPage extends StatefulWidget {
#override
_TestPageState createState() => _TestPageState();
}
bool donus = true;
class _TestPageState extends State<TestPage> {
List<Todo> sorular = new List<Todo>();
int _number;
#override
void initState() {
_number = 1;
print(donus);
super.initState();
getTodos();
}
bool pressAttention = true;
String ileri = "İleri", geri = "Geri";
#override
Widget build(BuildContext context) {
_number++; // You probably don't want to increment every time you build,
// but I have no idea what you're using `number` for.
print(_number);
Your donus variable is also global, which is unlikely to be what you had intended. Dart is an object-oriented language; refer to the language tour for more details on classes, scope, etc.
Related
I need to expose a couple of functions of a Stateful Widget. Since these functions depend on the state of the widget, I created a variable to store the state.
However, I am getting a compile time warning:
This class (or a class that this class inherits from) is marked as '#immutable', but one or more of its instance fields aren't final.
My Code:
class ItemWidget extends StatefulWidget {
final Record record;
final Function additem;
final Function removeItem;
var state;
ItemWidget(this.record, this.additem, this.removeItem);
#override
_ItemWidgetState createState() {
return this.state = new _ItemWidgetState();
}
// These are public functions which I need to expose.
bool isValid() => state.validate();
void validate() => state.validate();
}
Is there a better way /correct way of achieving this?
Thanks.
You should write the function on state, and access it via GlobalKey.
import 'package:flutter/material.dart';
class ItemWidget extends StatefulWidget {
final Record record;
final Function additem;
final Function removeItem;
const ItemWidget(
Key? key,
this.record,
this.additem,
this.removeItem,
) : super(key: key);
#override
ItemWidgetState createState() => ItemWidgetState();
}
class ItemWidgetState extends State<ItemWidget> {
bool isValid() {
return true;
}
void validate() {}
#override
Widget build(BuildContext context) {
// TODO: implement build
throw UnimplementedError();
}
}
https://api.flutter.dev/flutter/widgets/GlobalKey-class.html
I'm new to Riverpod and am trying to migrate an app over from Provider. If I had a TextField and wanted to set its value based on my Provider model, I would do this:
class MyWidget extends StatefulWidget{
const MyWidget({ Key? key }) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
var controller = TextEditingController();
#override
void didChangeDependencies() {
super.didChangeDependencies();
//Set the value here...
var model = Provider.of<Model>(context);
controller.text = model.name;
}
Widget build(BuildContext context) {
return TextField(controller: controller)
}
}
As I understand it, didChangeDependencies() would listen to changes from Provider.of<Model>(context) and update my controller accordingly.
I'm trying to pull off the same thing with Provider, but I can't ever get the TextField's value to show up.
class MyWidget extends ConsumerStatefulWidget {
const MyWidget({Key? key}) : super(key: key);
#override
ConsumerState<ConsumerStatefulWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends ConsumerState<MyWidget> {
var controller = TextEditingController();
#override
void didChangeDependencies() {
super.didChangeDependencies();
//Trying the same thing here...
final name = ref.watch(providerName);
controller.text = name;
}
Widget build(BuildContext context) {
final name = ref.watch(providerName);
return Column(
children: [
//This doesn't work:
TextField(controller: controller),
//I know my provider has the value, because this works fine:
Text(name),
]
}
}
How can I get my TextEditingController's text property to update?
From Riverpod official website
///1.Create a [StateNotifier] sub-class, StateNotifier is something where you can define functions that can change your state like in this state is of String type, you also can use objects (Classes instead of primitive types)
class Counter extends StateNotifier<String> {
Counter() : super('');
void changeText(String text){
state=text;
}
///2.Create a provider [StateNotifierProvider] with this you can use in your widget
final counterProvider = StateNotifierProvider<Counter, String>((ref) {
return Counter();
});
///3.Consume the Provider this is how we can attach state with our widget
class Home extends ConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
final text = ref.watch(counterProvider);
return Text('$text');
}
}
so here you can add you widget like button and onTap executes the code like
onTap()=>changeText(textController.text);
So your text [Text('$text');] will automatically change.
String inputText = controller.text;
I stumped into a problem where I need to use a StatefulWidget parameter in its state class when it's constructed, but I couldn't find a way to do it since using widget.[whatever variable name] in the state's class constructor returns an unexpected null value, and the initState function only runs when the widget is being drawn to the screen.
For example:
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
final String text;
Test(this.text);
final state = _TestState();
#override
_TestState createState() => state;
}
class _TestState extends State<Test> {
String? changingText;
void updateChangingText(String moreText){
changingText = changingText! + moreText;
}
#override
void initState() {
super.initState();
changingText = widget.text;
}
#override
Widget build(BuildContext context) {
return Text(changingText!);
}
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
var w = Test('test');
w.state.updateChangingText(' text');
return MaterialApp(home: Scaffold(body:
Test('test text')
));
}
}
void main() {
runApp(App());
}
This doesn't work since changingText is being updated before initState gives it its initial value since it only runs when Text is being drawn to the screen and this:
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
final String text;
Test(this.text);
final state = _TestState();
#override
_TestState createState() => state;
}
class _TestState extends State<Test> {
String? changingText;
void updateChangingText(String moreText){
changingText = changingText! + moreText;
}
_TestState(){
changingText = widget.text;
}
#override
Widget build(BuildContext context) {
return Text(changingText!);
}
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
var w = Test('test');
w.state.updateChangingText(' text');
return MaterialApp(home: Scaffold(body:
Test('test text')
));
}
}
void main() {
runApp(App());
}
doesn't work either since you can't use widget.[whatever] in state class constructors (for some reason).
So what can I do to use widget parameters in the state class before the widget is drawn to the screen?
Thanks in advance for the help
You should use the initState method present in the State for this instead of the constructor
#override
void initState() {
changingText = widget.text;
super.initState();
}
I have a simple code snippet:
class CreateNewViewPage extends StatefulWidget {
final ComponentConfiguration currentComponentConfiguration = ComponentConfiguration(1, 1);
final Components components = Components(currentComponentConfiguration);
#override
State<StatefulWidget> createState() => _CreateNewViewPage();
}
Unfortunately, when I want to send currentComponentConfiguration to the Components class construct, I get the following information: The instance member 'currentComponentConfiguration' can't be accessed in an initializer.
How can I fix this problem?
You can't use a non-static variable for initialzing another non-static variable. Either make currentComponentConfiguration a static member or do components object creation in State class (_CreateNewViewPageState).
Using Static
class CreateNewViewPage extends StatefulWidget {
static final ComponentConfiguration currentComponentConfiguration = ComponentConfiguration(1, 1);
final Components components = Components(currentComponentConfiguration);
#override
_CreateNewViewPageState createState() => _CreateNewViewPageState();
}
Using State class
class CreateNewViewPage extends StatefulWidget {
final ComponentConfiguration currentComponentConfiguration = ComponentConfiguration(1, 1);
#override
_CreateNewViewPageState createState() => _CreateNewViewPageState();
}
class _CreateNewViewPageState extends State<CreateNewViewPage> {
Components components;
#override
void initState() {
super.initState();
components = Components(widget.currentComponentConfiguration);
}
#override
Widget build(BuildContext context) {
return Text('Hello, World!', style: Theme.of(context).textTheme.headline4);
}
}
I have 2 screens in my Flutter app: a list of records and a screen for creating and editing records.
If I pass an object to the second screen that means I am going to edit this and if I pass null it means that I am creating a new item. The editing screen is a Stateful widget and I am not sure how to use this approach https://flutter.io/cookbook/navigation/passing-data/ for my case.
class RecordPage extends StatefulWidget {
final Record recordObject;
RecordPage({Key key, #required this.recordObject}) : super(key: key);
#override
_RecordPageState createState() => new _RecordPageState();
}
class _RecordPageState extends State<RecordPage> {
#override
Widget build(BuildContext context) {
//.....
}
}
How can I access recordObject inside _RecordPageState?
To use recordObject in _RecordPageState, you have to just write widget.objectname like below
class _RecordPageState extends State<RecordPage> {
#override
Widget build(BuildContext context) {
.....
widget.recordObject
.....
}
}
Full Example
You don't need to pass parameters to State using it's constructor.
You can easily access these using widget.myField.
class MyRecord extends StatefulWidget {
final String recordName;
const MyRecord(this.recordName);
#override
MyRecordState createState() => MyRecordState();
}
class MyRecordState extends State<MyRecord> {
#override
Widget build(BuildContext context) {
return Text(widget.recordName); // Here you direct access using widget
}
}
Pass your data when you Navigate screen :
Navigator.of(context).push(MaterialPageRoute(builder: (context) => MyRecord("WonderWorld")));
class RecordPage extends StatefulWidget {
final Record recordObject;
RecordPage({Key key, #required this.recordObject}) : super(key: key);
#override
_RecordPageState createState() => new _RecordPageState(recordObject);
}
class _RecordPageState extends State<RecordPage> {
Record recordObject
_RecordPageState(this. recordObject); //constructor
#override
Widget build(BuildContext context) {. //closure has access
//.....
}
}
example as below:
class nhaphangle extends StatefulWidget {
final String username;
final List<String> dshangle;// = ["1","2"];
const nhaphangle({ Key key, #required this.username,#required this.dshangle }) : super(key: key);
#override
_nhaphangleState createState() => _nhaphangleState();
}
class _nhaphangleState extends State<nhaphangle> {
TextEditingController mspController = TextEditingController();
TextEditingController soluongController = TextEditingController();
final scrollDirection = Axis.vertical;
DateTime Ngaysx = DateTime.now();
ScrollController _scrollController = new ScrollController();
ApiService _apiService;
List<String> titles = [];
#override
void initState() {
super.initState();
_apiService = ApiService();
titles = widget.dshangle; //here var is call and set to
}
I have to Navigate back to any one of the screens in the list pages but when I did that my onTap function stops working and navigation stops.
class MyBar extends StatefulWidget {
MyBar({this.pageNumber});
final pageNumber;
static const String id = 'mybar_screen';
#override
_MyBarState createState() => _MyBarState();
}
class _MyBarState extends State<MyBar> {
final List pages = [
NotificationScreen(),
AppointmentScreen(),
RequestBloodScreen(),
ProfileScreen(),
];
#override
Widget build(BuildContext context) {
var _selectedItemIndex = widget.pageNumber;
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
elevation: 0,
backgroundColor: Colors.white,
unselectedItemColor: Colors.grey.shade700,
selectedItemColor: Color(kAppColor),
selectedIconTheme: IconThemeData(color: Color(kAppColor)),
currentIndex: _selectedItemIndex,
type: BottomNavigationBarType.fixed,
onTap: (int index) {
setState(() {
_selectedItemIndex = index;
});
},
You should use a Pub/Sub mechanism.
I prefer to use Rx in many situations and languages. For Dart/Flutter this is the package: https://pub.dev/packages/rxdart
For example, you can use a BehaviorSubject to emit data from widget A, pass the stream to widget B which listens for changes and applies them inside the setState.
Widget A:
// initialize subject and put it into the Widget B
BehaviorSubject<LiveOutput> subject = BehaviorSubject();
late WidgetB widgetB = WidgetB(deviceOutput: subject);
// when you have to emit new data
subject.add(deviceOutput);
Widget B:
// add stream at class level
class WidgetB extends StatefulWidget {
final ValueStream<LiveOutput> deviceOutput;
const WidgetB({Key? key, required this.deviceOutput}) : super(key: key);
#override
State<WidgetB> createState() => _WidgetBState();
}
// listen for changes
#override
void initState() {
super.initState();
widget.deviceOutput.listen((event) {
print("new live output");
setState(() {
// do whatever you want
});
});
}
In my app, often instead of using stateful widgets, I use mainly ChangeNotifierProvider<T> in main.dart, some model class
class FooModel extends ChangeNotifier {
var _foo = false;
void changeFooState() {
_foo = true;
notifyListeners();
}
bool getFoo () => _foo;
}
and
var foo = context.read<FooModel>();
# or
var foo = context.watch<FooModel>();
in my stateless widgets. IMO this gives me more precise control over the rebuilding upon runtime state change, compared to stateful widgets.
The recipe can be found in the official docs, the concept is called "lifting state up".