Flutter: UniqueKey not working when removing/recreating widget
Solution 1
You should never hold a value in a view. Your views should ideally get all of their information from models and controllers.
This is because there are more variables in the state than just the slider value I have to preserve.
And yes, if the view is derived from many inputs, all of those inputs should be available to the view at build() time.
Solution 2
You can copy paste run full code below
In this case, you do not need key
You can use Visibility
and set maintainState: true
code snippet
Visibility(
visible: hidden, maintainState: true, child: widget.child)
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(home: MyHomePage());
}
class MyHomePage extends StatefulWidget {
MyHomePage();
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: Text("Problem: UniqueKey not working")),
body: ContentHider(
child: Column(children: [
// This Slider DOES change when hiding/unhiding
// This Slider SHOULDN'T change
CustomWidget(),
]),
));
}
// When pressing the button the "child" gets rendered / not rendered
class ContentHider extends StatefulWidget {
final Widget child;
ContentHider({this.child});
@override
_ContentHiderState createState() => _ContentHiderState();
}
class _ContentHiderState extends State<ContentHider> {
bool hidden = false;
@override
Widget build(BuildContext context) => Center(
child: Column(
children: [
RaisedButton(
onPressed: () {
if (hidden == false)
setState(() => hidden = true);
else
setState(() => hidden = false);
},
child: Text("Hide/Unhide"),
),
Visibility(
visible: hidden, maintainState: true, child: widget.child)
],
),
);
}
// StatfulWidget which contains changable content -> Slider
class CustomWidget extends StatefulWidget {
CustomWidget({Key key}) : super(key: key);
@override
_CustomWidgetState createState() => _CustomWidgetState();
}
class _CustomWidgetState extends State<CustomWidget> {
double _currentSliderValue = 0.0;
@override
Widget build(BuildContext context) {
return Card(
color: Color(0xFFACFFBC),
child: Slider(
value: _currentSliderValue,
min: 0,
max: 100,
label: _currentSliderValue.round().toString(),
onChanged: (double value) {
setState(() {
_currentSliderValue = value;
});
},
),
);
}
}
UnknownScript
Updated on December 26, 2022Comments
-
UnknownScript over 1 year
Situation: In my app I have input cards (with like sliders) which are displayed/hidden by clicking a button.
Problem: When I edit the value of a slider, then hide and unhide again, the value is lost.
I tried using a UniqueKey() but it doesn't solve the problem.
A workaround which doesn't work for me is storing the value elsewhere and the passing it as an initial value to the slider. This is because there are more variables in the state than just the slider value I have to preserve.
import 'package:flutter/material.dart'; final _someKey = UniqueKey(); void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) => MaterialApp(home: MyHomePage()); } class MyHomePage extends StatefulWidget { MyHomePage(); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) => Scaffold( appBar: AppBar(title: Text("Problem: UniqueKey not working")), body: ContentHider( child: Column(children: [ // This Slider DOES change when hiding/unhiding // This Slider SHOULDN'T change CustomWidget( key: _someKey, ), ]), )); } // When pressing the button the "child" gets rendered / not rendered class ContentHider extends StatefulWidget { final Widget child; ContentHider({this.child}); @override _ContentHiderState createState() => _ContentHiderState(); } class _ContentHiderState extends State<ContentHider> { bool hidden = false; @override Widget build(BuildContext context) => Center( child: Column( children: [ RaisedButton( onPressed: () { if (hidden == false) setState(() => hidden = true); else setState(() => hidden = false); }, child: Text("Hide/Unhide"), ), hidden ? Container() : widget.child ], ), ); } // StatfulWidget which contains changable content -> Slider class CustomWidget extends StatefulWidget { CustomWidget({Key key}) : super(key: key); @override _CustomWidgetState createState() => _CustomWidgetState(); } class _CustomWidgetState extends State<CustomWidget> { double _currentSliderValue = 0.0; @override Widget build(BuildContext context) { return Card( color: Color(0xFFACFFBC), child: Slider( value: _currentSliderValue, min: 0, max: 100, label: _currentSliderValue.round().toString(), onChanged: (double value) { setState(() { _currentSliderValue = value; }); }, ), ); } }
-
UnknownScript over 3 yearsI use controllers for my sliders, but these controllers loose theirs state. [Unhidden/Hidden Widget] -> [Stateful Slider Controller] -> [Stateless Slider Wrapper] -> [Slider]
-
Randal Schwartz over 3 yearsI was using controller in the generic sense, as part of the Model/View/Controller triad.
-
UnknownScript over 3 yearsOkay, I understand