I have a statefull widget named Hamburger I have a class named _HamburgerState connected to this class. I have an integer value called _count inside my class named HamburgerState. I want the _count value at the time the add to cart button is pressed inside my HamburgerState class to be imported into my StatelessWidget named "CartPage". I heard it was done but I couldn't do it. When I write the code below, I get an error like this. '_HamburgerState' doesn't conform to the bound 'ChangeNotifier?' of the type parameter 'T'.
Try using a type that is or is a subclass of 'ChangeNotifier?'.
class Hamburger extends StatefulWidget {
const Hamburger({super.key});
#override
State<Hamburger> createState() => _HamburgerState();
}
class _HamburgerState extends State<Hamburger> {
int _count = 1;
void _incrementCount() {...
void _decrementCount() {...
#override
Widget build(BuildContext context) {
Color coloricon = Provider.of<iconcolor>(context).coloricon;
return ChangeNotifierProvider.value(
value: this,
child: Scaffold(...
);
}
}
class AppIcon2 extends ChangeNotifier {...
class CountNotifier extends ChangeNotifier {
int _count;
int get count => _count;
set count(int value) {
_count = value;
notifyListeners();
}
}
I tried with Provider but I don't know if it works
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
am following this Bloc's official example and I couldn't find a way how to access the state without that if statement.
Let's have the example below, I would like to display a specific text based on the initial value of showText, the only possible solution to access the state is via:
if(statement is ExampleInitial) {state.showText? return Text("yes") : return Text("no")}
But am finding this solution hard to implement when you have more values with initial values. Or am I doing this wrong?
////////// bloc
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
ExampleBloc() : super(const ExampleInitial()) {
on<ExampleStarted>(_onExampleStarted);
}
void _onExampleStarted(ExampleStarted event, Emitter<ExampleState> emit) {
emit(const ExampleInitial());
}
}
////////// event
part of 'example_bloc.dart';
abstract class ExampleEvent extends Equatable {
const ExampleEvent();
}
class ExampleStarted extends ExampleEvent {
#override
List<Object> get props => [];
}
////////// state
part of 'example_bloc.dart';
abstract class ExampleState extends Equatable {
const ExampleState();
}
////////// state
class ExampleInitial extends ExampleState {
final bool showText = false;
const ExampleInitial();
#override
List<Object> get props => [showText];
}
// ui
class CreateExampleScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocBuilder<ExampleBloc, ExampleState>(
builder: (context, state) {
return state.showText ? Text("yes") :Text("no"); // can't access to state.showText
});
}
}
You can declare a variable inside Bloc Class which will be global and need to be set inside the 'bloc.dart' file like in the case of Provider Package. This variable does not need state to be checked before accessing it in UI. You can access this value from the Navigation tree using context.
////////// bloc
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
ExampleBloc() : super(const ExampleInitial()) {
on<ExampleStarted>(_onExampleStarted);
}
bool showText = false;
void _onExampleStarted(ExampleStarted event, Emitter<ExampleState> emit) {
emit(const ExampleInitial());
}
}
// ui
class CreateExampleScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocProvider.of<ExampleBloc>(context).showText
? const Text('Yes')
: const Text('No');
}
}
There is another way in which you declare abstract State Class to always have the boolean value. So, whatever new class extends those State will have inherited boolean value from parent class. This concept is called inheritance in OOP.
////////// state
abstract class ExampleState extends Equatable {
const ExampleState();
final bool showText = false;
}
////////// state
class ExampleInitial extends ExampleState {
const ExampleInitial();
// You can also set ExampleInitial to accept showText and send it to its
// parent class using 'super' method in constructor,
// if parent class has constructor with 'showText' as boolean
#override
List<Object> get props => [];
}
// ui
class CreateExampleScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocBuilder<ExampleBloc, ExampleState>(builder: (context, state) {
return state.showText ? const Text("yes") : const Text("no");
});
}
}
A pragmatic usecase for different State Classes having different state variables is as follows:
Let's account for three states while fetching data from api
-if(state is DataLoadingState),
// there is no need for state
-if(state is DataLoadedState)
// state need to have a variable named weatherData containing temperatures, cities and so on.
-if(state is ErrorWhileLoadingState)
// state needs to have a reason for the error. For example: errorMsg: 'Internal Server Error'
So, you need to check the state before accessing its values.
I want to trigger a boolean variable 'runBackdropBlur' in the state class as per below code.
To do this I want to be able to call the method turnOnBackdropBlur() (from another widget), and this method in turn, when called will change this variable in it's state class by use of global key.
I have been following this tutorial, to achieve a simple state management solution for this case:
tutorial
However, I run into these two errors in flutter, i cannot fix...
"Named parameters must be enclosed in curly braces ('{' and '}')."
"The default value of an optional parameter must be constant."
class Backdrop extends StatefulWidget {
Backdrop(key : _myKey);
GlobalKey<_BackdropState> _myKey = GlobalKey<_BackdropState>();
void turnOnBackdropBlur() {
_myKey.currentState!.runBackdropBlur = true;
}
#override
_BackdropState createState() => _BackdropState();
}
class _BackdropState extends State<Backdrop> {
bool runBackdropBlur = false;
//etc
With some tricks you can do everything you want. You can give a pointer of a method to the owner widget as follows:
import 'dart:developer';
import 'package:flutter/cupertino.dart';
class Backdrop extends StatefulWidget {
final Map<String, Function> listener = new Map<String, Function>();
void setnBackdropBlurTrue() => listener.containsKey("BackdropBlurTrue")
? listener["BackdropBlurTrue"].call()
: log("BackdropBlurTrue key is null");
void setnBackdropBlurFalse() => listener.containsKey("BackdropBlurFalse")
? listener["BackdropBlurFalse"].call()
: log("BackdropBlurFalse key is null");
#override
_BackdropState createState() => _BackdropState();
}
class _BackdropState extends State<Backdrop> {
bool runBackdropBlur = false;
void setRunBackdropBlurTrue() => runBackdropBlur = true;
void setRunBackdropBlurFalse() => runBackdropBlur = false;
#override
Widget build(BuildContext context) {
return Container();
}
_BackdropState() {
widget.listener.putIfAbsent("BackdropBlurTrue", () => setRunBackdropBlurTrue);
widget.listener.putIfAbsent("BackdropBlurFalse", () => setRunBackdropBlurFalse);
}
}
In my project, I pass data from one widget to another using this code:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
TranslatorSignUpStep2(transModel: this._translatorModel),
),
);
Then I retrive it in the other widget by the code below:
class TranslatorSignUpStep2 extends StatefulWidget {
final TranslatorModel transModel;
TranslatorSignUpStep2({this.transModel});
#override
_TranslatorSignUpStep2State createState() => _TranslatorSignUpStep2State();
}
The problem is, in the TranslatorSignUpStep2 class I want to assign the passed-in transModel to another variable so I write this code
class _TranslatorSignUpStep2State extends State<TranslatorSignUpStep2> {
TranslatorModel _translatorModel = widget.transModel;
}
But it seems like the widget can't be used outside the build method so I get error saying
The instance member 'widget' can't be accessed in an initializer.. Anyone know how to get over this ?
you can access widget in initState function like this.
class _TranslatorSignUpStep2State extends State<TranslatorSignUpStep2> {
TranslatorModel _translatorModel ;
#override
void initState() {
_translatorModel = widget.transModel;
}
}
Just add the keyword late while initializing:
class TranslatorSignUpStep2 extends StatefulWidget {
final TranslatorModel transModel;
TranslatorSignUpStep2({this.transModel});
#override
_TranslatorSignUpStep2State createState() => _TranslatorSignUpStep2State();
}
class _TranslatorSignUpStep2State extends State<TranslatorSignUpStep2> {
late TranslatorModel _translatorModel = widget.transModel;
}
try this code :
TranslatorSignUpStep2 :
class TranslatorSignUpStep2 extends StatefulWidget {
final TranslatorModel transModel;
TranslatorSignUpStep2({this.transModel});
#override
_TranslatorSignUpStep2State createState() => _TranslatorSignUpStep2State(this.transModel);
}
TranslatorSignUpStep2 class :
class _TranslatorSignUpStep2State extends State<TranslatorSignUpStep2> {
_TranslatorSignUpStep2State(TranslatorModel _tempModel ){
this._translatorModel =_tempModel;
};
TranslatorModel _translatorModel ;
}
Add static keyword when innitializing
class OrderDetails extends StatefulWidget {
int selectedDays;
OrderDetails({
this.range,)};
#override
_OrderDetailsState createState() => _OrderDetailsState();
}
class _OrderDetailsState extends State<OrderDetails> {
String getRange;
#override
void initState() {
super.initState();
getRange = widget.range;
}
I looked at the docs of dart for generics.
abstract class StringCache {
String getByKey(String key);
void setByKey(String key, String value);
}
abstract class ObjectCache {
Object getByKey(String key);
void setByKey(String key, Object value);
}
The above two is replaceed by one single generic type T with below code
abstract class Cache<T> {
T getByKey(String key);
void setByKey(String key, T value);
}
Where the use of T is seen clearly. but not sure where the state class uses
class _CounterState extends State<Counter> {
int _counter = 0;
void _increment() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
RaisedButton(
onPressed: _increment,
child: Text('Increment'),
),
Text('Count: $_counter'),
],
);
}
}
T is a generic type parameter and extends StatefulWidget is a constraint for what types T can be set to.
With
class _CounterState extends State<Counter> {
T is set to type Counter (which has to be a StatefulWidget).
Passing Counter as type allows you to use
widget.foo
to reference field foo in Counter from _CounterState and you get autocompletion and static type checking.