When should I override debugFillProperties in Flutter? - flutter

Why should I use debugFillProperties in the stateful widget in Flutter? I have seen Some flutter Built-in stateful widgets Like Slider using this method.
I went through Flutter Docs given here. I'm still not able to understand the practical usage of debugFillProperties. When or why use it?
I tried It in My example code, Still Not able to understand. I did not find any docs or relevant information was found about this method in Flutter.
double? min;
#override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
print("--------------Debug-------------");
properties.add(IntProperty('min', min, defaultValue: 5, ifNull: "nulll"));
}

By overriding the debugFillProperties function, we can show the current value of a variable (state) in the Details Tree
example:
without overriding this method:
class _MyHomePageState extends State<MyHomePage> {
late MyColorScheme _myColorScheme;
int _counter = 0;
#override
void initState() {
_myColorScheme = MyColorScheme(Colors.black, Colors.white);
super.initState();
}
}
with overriding this method:
class _MyHomePageState extends State<MyHomePage> {
late MyColorScheme _myColorScheme;
int _counter = 0;
#override
void initState() {
_myColorScheme = MyColorScheme(Colors.black, Colors.white);
super.initState();
}
#override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(IntProperty('_counter', _counter));
properties.add(
DiagnosticsProperty<MyColorScheme>('myColorScheme', _myColorScheme));
}
}

Also, the information from debugFillProperties will be shown in the output from a debugDumpApp call.
See Debugging App Programmatically -> Widget Tree section for more details.

Related

How to access a bloc's current state's property in the initState?

I have a global bloc that wraps the materiapApp widget and I am able to get the bloc inside my deep nested widget tree. However, I would like to access the current state's property.
#override
void initState() {
super.initState();
_internetConnectionBloc = BlocProvider.of<InternetConnectionBloc>(context);
//I am able to get the bloc but I would like to access it's current state's property
}
States:
abstract class InternetConnectionState extends Equatable {
const InternetConnectionState();
#override
List<Object> get props => [];
}
class InternetConnectionInitial extends InternetConnectionState {}
class InternetConnectionStatusUpdated extends InternetConnectionState {
final InternetConnectionType connectionType;
const InternetConnectionStatusUpdated(this.connectionType);
#override
List<Object> get props => [connectionType];
}
I would like to access the InternetConnectionStatusUpdated state's connectionType property in the initState instead of blocListenerin the build method.
try this in initState
var connectionType = BlocProvider.of<InternetConnectionBloc>(context).state.connectionType;
I fixed it like this:
#override
void initState() {
super.initState();
_internetConnectionBloc = BlocProvider.of<InternetConnectionBloc>(context);
final state = _internetConnectionBloc!.state;
if(state is InternetConnectionStatusUpdated){ // --> this way dart
//analyze was able to understand the state type
print(state.connectionType);
}
}

Drive Animation with ValueNotifier

I have ValueNotifier<double> that I need to pass to FadeTransition's opacity. Issue is that this opacity parameter is of type Animation<double>.
What would be minimal way of converting ValueNotifier<double> to Animation<double>. Is there any Animation type that allows manually setting the current value?
I know there is AnimationController, but it needs too much boilerplate. It requires a TickerProvider that in this case isn't useful at all.
I'm looking for lightweight Animation<> implementation that is similar to ValueNotifier<>.
So, I created this simple ValueNotifier wrapper. It works, but I'm not sure, if it also needs dispose method.
EDIT: Dispose is not needed since it only passes listeners to an outside ValueNotifier object.
class ValueNotifierWrapperAnimation<T> extends Animation<T>
with AnimationLocalStatusListenersMixin {
ValueNotifierWrapperAnimation(this.valueNotifier);
final ValueNotifier<T> valueNotifier;
#override
AnimationStatus get status => AnimationStatus.forward;
#override
T get value => valueNotifier.value;
#override
void addListener(VoidCallback listener) =>
valueNotifier.addListener(listener);
#override
void removeListener(VoidCallback listener) =>
valueNotifier.removeListener(listener);
#override
void didRegisterListener() {}
#override
void didUnregisterListener() {}
}
EDIT 2: Instead of wrapper, a class that holds it's own value and acts both as ValueNotifier and Animation. Compared to the previous implementation, this removes a requirement to also have a ValueNotifier field somewhere.
class ValueNotifierAnimation<T> extends Animation<T>
with AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
ValueNotifierAnimation(this._value);
T _value;
#override
T get value => _value;
set value(T newValue) {
if (_value == newValue)
return;
_value = newValue;
notifyListeners();
}
#override
AnimationStatus get status => AnimationStatus.forward;
#override
void didRegisterListener() {}
#override
void didUnregisterListener() {}
#override
String toString() => '${describeIdentity(this)}($value)';
}

Remove listener from FocusNode using Flutter Hooks

I started adopting Flutter Hooks recently and REALLY loving it. I was able to convert a few of my StatefulWidgets to HookWidgets, and it's pretty cool. The one thing I'm struggling to figure out is how to properly remove listeners from from a FocusNode created by useFocusNode.
If I do this the StatefulWidget way it seems to be working well (basically following this example from the Flutter docs):
class ItemWidget extends StatefulWidget {
...
}
class _ItemWidgetState extends State<ItemWidget> {
...
late FocusNode _focusNode;
#override
void initState() {
super.initState();
_focusNode = FocusNode(debugLabel: widget.key.toString());
_focusNode.addListener(_handleFocusChange);
}
void _handleFocusChange() {
debugPrint('${_focusNode.debugLabel} has ${_focusNode.hasFocus ? '' : 'lost'} focus');
}
#override
Widget build(BuildContext context) {
...
}
#override
void dispose() {
_focusNode.removeListener(_handleFocusChange);
super.dispose();
}
But then how would I do it using WidgetHook and useFocusNode? I know how to create the FocusNode and add the listener, but then where do I remove it? Should I be using useEffect for that? Unsure how to do it.
Thanks!

How to ensure code is run only once in a widget?

I do have a lot of code that looks like
this:
bool _somethingFromApiLoaded = false;
Something _somethingFromApi;
loadSomething() async {
final something = await ServiceProvider.of(context).apiService.getSomething();
setState(() => _somethingFromApi = something);
}
#override
Widget build(BuildContext context) {
if (!_somethingFromApiLoaded) {
loadSomething();
_somethingFromApiLoaded = true;
}
}
Note how I produce a lot of boilerplate code to ensure loadSomething is only called once.
I wonder if there isn't a lifecycle method to do so that I somehow misinterpret. I can't use initState because it does not have context.
I would try to a use a StatefulWidget and use initState() method.
That is the lifecycle you are referring to.
You should try to use a Future inside the initState()
#override
void initState() {
super.initState(); // make sure this is called in the beggining
// your code here runs only once
Future.delayed(Duration.zero,() {
_somethingFromApi = await ServiceProvider.of(context).apiService.getSomething();
});
}
As User gegobyte said, Context is available in the initState.
But apparently can't be used for everything.
You can use context in initState() by passing it to the widget:
class HomeScreen extends StatefulWidget {
final BuildContext context;
HomeScreen(this.context);
#override
State<StatefulWidget> createState() => new _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
bool _somethingFromApiLoaded = false;
Something _somethingFromApi;
loadSomething() async {
final something = await ServiceProvider.of(widget.context).apiService.getSomething();
setState(() => _somethingFromApi = something);
}
#override
void initState() {
super.initState();
if (!_somethingFromApiLoaded) {
loadSomething();
_somethingFromApiLoaded = true;
}
}
}

flutter - clear the widget cache

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.