I'm trying to create a functionality, where when I click on a FlatButton
inside an Expanded
widget, its flex
changes to 2 and other siblings FlatButton
s flex change to 1.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.ltr,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new ButtonWidget(text: "Hello",selectedColor: Colors.yellow),
new ButtonWidget(text: "This is", selectedColor: Colors.red),
new ButtonWidget(text: "Button", selectedColor: Colors.blue),
],
),
);
}
}
class ButtonWidget extends StatefulWidget {
String text;
MaterialColor selectedColor;
ButtonWidget({this.text, this.selectedColor});
createState() =>
ButtonState(text: this.text, selectedColor: this.selectedColor);
}
class ButtonState extends State<ButtonWidget> {
String text;
MaterialColor selectedColor;
int _flexValue = 1;
ButtonState({this.text, this.selectedColor});
@override
Widget build(BuildContext context) {
return Expanded(
flex: _flexValue,
child: FlatButton(
color: selectedColor,
child: Text(
text,
),
onPressed: () {
setState(() {
_flexValue = 2;
});
},
),
);
}
}
I was trying to find a way, maybe keep track of all of them in an array or something. I searched and found that InheritedWidget
approach is for inherited widgets, not siblings.
I'm sure there's a clean way to do it. But just can't get my hands on it.
Don't try to keep the state of whether it's selected in the button itself. As you've seen it's difficult to keep the state of 3 buttons in sync. Find a place higher up the widget tree where you can maintain that state once. In this case, it's in your App. Make App stateful so that it can remember the state and then your buttons don't need to remember it. They can be told whether they are selected (big) or unselected (small) in their constructor.
So, how does the button tell the parent that it's now become the selected one? There are various strategies, but they all involve:
- calling a method that's been passed down
- calling a method on an InheritedWidget
- sending a message through a stream
- etc
Try this:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
State createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
int selected = 0;
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.ltr,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
ButtonWidget(0, flexValue(0), 'Hello', Colors.yellow, onClick),
ButtonWidget(1, flexValue(1), 'This is', Colors.red, onClick),
ButtonWidget(2, flexValue(2), 'Button', Colors.blue, onClick),
],
),
);
}
void onClick(int i) {
setState(() {
selected = i;
});
}
int flexValue(int index) => (index == selected) ? 2 : 1;
}
class ButtonWidget extends StatelessWidget {
ButtonWidget(this.index, this._flexValue, this.text, this.selectedColor,
this.notifyClick);
final Function notifyClick;
final int index;
final int _flexValue;
final String text;
final MaterialColor selectedColor;
@override
Widget build(BuildContext context) {
return Expanded(
flex: _flexValue,
child: FlatButton(
color: selectedColor,
child: Text(
text,
),
onPressed: () {
notifyClick(index);
},
),
);
}
}
Here you have another way to do that , change your main widget to Stateful
and your Button to Stateless
.
class MyApp2 extends StatefulWidget {
@override
_MyApp2State createState() => _MyApp2State();
}
class _MyApp2State extends State<MyApp2> {
int selectedIndex = -1;
onIndexChanged(int index){
setState(() {
selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.ltr,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new ButtonWidget(
index: 1,
text: "Hello",
selectedColor: Colors.yellow,
selectedIndex: selectedIndex,
onChanged: onIndexChanged
),
new ButtonWidget(
index: 2,
text: "This is",
selectedColor: Colors.red,
selectedIndex: selectedIndex,
onChanged: onIndexChanged),
new ButtonWidget(
index: 3,
text: "Button",
selectedColor: Colors.blue,
selectedIndex: selectedIndex,
onChanged: onIndexChanged),
],
),
);
}
}
class ButtonWidget extends StatelessWidget {
final String text;
final MaterialColor selectedColor;
final int index;
final ValueChanged<int> onChanged;
final int selectedIndex;
ButtonWidget(
{this.text,
this.selectedColor,
this.index,
this.onChanged,
this.selectedIndex});
@override
Widget build(BuildContext context) {
return Expanded(
flex: selectedIndex != null && selectedIndex == index ? 2 : 1,
child: FlatButton(
color: selectedColor,
child: Text(
text,
),
onPressed: () => onChanged(index),
),
);
}
}