Reputation: 105
I'm trying to load content of a step base on a selection. For instance if user select option B then a different set of options load on the next step. This is what I have so far which is working but content is not being loaded dynamically: The goal is if a select a "New Car" a different set of options should load.
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _currentStep = 0;
List<RadioModel> step0 = [
RadioModel(false, "New", Icons.directions_car),
RadioModel(false, "Used", Icons.directions_car),
];
List<RadioModel> step1 = [
RadioModel(false, "Honda", Icons.local_shipping),
RadioModel(false, "Toyota", Icons.title)
];
List<RadioModel> step3 = [
RadioModel(false, "Red", Icons.radio_button_checked),
RadioModel(false, "Orage", Icons.radio_button_checked)
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.grey),
backgroundColor: Colors.white,
elevation: 2,
title: Text("Buy Car".toUpperCase(),
style: TextStyle(
color: Colors.grey[700],
fontSize: 17,
)),
// leading: IconButton(
// icon: Icon(Icons.close, size: 28),
// onPressed: () {
// Navigator.of(context).pop();
//
// }),
),
body: Theme(
data: ThemeData(primaryColor: Colors.indigoAccent),
child:
Stepper(
type: StepperType.vertical,
currentStep: _currentStep,
onStepTapped: (int step) => setState(() => _currentStep = step),
onStepContinue:
_currentStep < 2 ? () => setState(() => _currentStep += 1) : null,
onStepCancel:
_currentStep > 0 ? () => setState(() => _currentStep -= 1) : null,
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) =>
Container(
height: 70,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
_currentStep == 0
? Text("")
: RaisedButton(
onPressed: onStepCancel,
textColor: Colors.grey,
textTheme: ButtonTextTheme.normal,
child: Row(children: <Widget>[
const Icon(Icons.chevron_left),
Text("PREV")
]),
),
RaisedButton(
onPressed: onStepContinue,
textColor: Colors.white,
color: Colors.indigoAccent,
textTheme: ButtonTextTheme.normal,
child: Row(children: <Widget>[
_currentStep >= 2
? Icon(Icons.done)
: Icon(Icons.chevron_right),
_currentStep >= 2 ? Text("DONE") : Text("NEXT")
]),
),
],
),
),
steps: <Step>[
Step(
title: Text(
"Car",
style: TextStyle(
fontSize: 15,
color: Colors.grey[600],
),
),
content: Column(
children: <Widget>[
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left:8.0,bottom:10),
child: Text(
"What type of car?:",
style: TextStyle(
fontSize: 17,
color: Colors.black,
),
),
),
],
),
SelectableCard(options: step0),
],
),
isActive: _currentStep >= 0,
state:
_currentStep >= 0 ? StepState.complete : StepState.disabled,
),
Step(
title: Text(
"Brand",
style: TextStyle(
fontSize: 15,
color: Colors.grey[600],
),
),
content: Column(
children: <Widget>[
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left:8.0,bottom:10),
child: Text(
"Made Company?",
style: TextStyle(
fontSize: 17,
color: Colors.black,
),
),
),
],
),
SelectableCard(options: step1),
],
),
isActive: _currentStep >= 1,
state:
_currentStep >= 1 ? StepState.complete : StepState.disabled,
),
Step(
title: Text(
"Color",
style: TextStyle(
fontSize: 15,
color: Colors.grey[600],
),
),
content: SelectableCard(options: step3),
isActive: _currentStep >= 2,
state:
_currentStep >= 3 ? StepState.complete : StepState.disabled,
),
],
),
),
);
}
Widget _commentary(){
return TextFormField(
keyboardType: TextInputType.multiline,
maxLines: 3,
decoration: InputDecoration(
labelText: 'i.e - Concurrent Area',
),
);
}
}
class SelectableInLineCard extends StatefulWidget {
final List<RadioModel> options;
SelectableInLineCard({@required this.options});
@override
_SelectableInLineCardState createState() => _SelectableInLineCardState();
}
class _SelectableInLineCardState extends State<SelectableInLineCard> {
List<RadioModel> sampleData = new List<RadioModel>();
void initState() {
// TODO: implement initState
super.initState();
sampleData = widget.options;
}
@override
Widget build(BuildContext context) {
return GridView.builder(
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 12),
),
itemCount: sampleData.length,
itemBuilder: (context, index) {
return Card(
shape: sampleData[index].isSelected
? RoundedRectangleBorder(
side: BorderSide(color: Colors.indigoAccent, width: 2.0),
borderRadius: BorderRadius.circular(4.0))
: RoundedRectangleBorder(
side: BorderSide(color: Colors.grey[200], width: 2.0),
borderRadius: BorderRadius.circular(4.0)),
color: Colors.white,
elevation: 0,
child: InkWell(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
onTap: () {
setState(() {
sampleData.forEach((element) => element.isSelected = false);
sampleData[index].isSelected = true;
//print(sampleData[index].time);
});
},
child: GridTile(
child: FlatButton(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
sampleData[index].time,
style: TextStyle(
fontSize: 15,
color: sampleData[index].isSelected ? Colors.indigoAccent : Colors.grey[500],
),
),
],
),
],
),
),
),
),
);
},
);
}
}
class SelectableCard extends StatefulWidget {
final List<RadioModel> options;
SelectableCard({@required this.options});
@override
_SelectableCardState createState() => _SelectableCardState();
}
class _SelectableCardState extends State<SelectableCard> {
List<RadioModel> sampleData = new List<RadioModel>();
@override
void initState() {
// TODO: implement initState
super.initState();
sampleData = widget.options;
}
@override
Widget build(BuildContext context) {
return GridView.builder(
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 2.5),
),
itemCount: sampleData.length,
itemBuilder: (context, index) {
return Card(
shape: sampleData[index].isSelected
? RoundedRectangleBorder(
side: BorderSide(color: Colors.indigoAccent, width: 2.0),
borderRadius: BorderRadius.circular(4.0))
: RoundedRectangleBorder(
side: BorderSide(color: Colors.grey[200], width: 2.0),
borderRadius: BorderRadius.circular(4.0)),
color: Colors.white,
elevation: 0,
child: InkWell(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
onTap: () {
setState(() {
sampleData.forEach((element) => element.isSelected = false);
sampleData[index].isSelected = true;
});
},
child: GridTile(child: RadioItem(sampleData[index])),
),
);
},
);
}
}
class RadioItem extends StatelessWidget {
final RadioModel _item;
RadioItem(this._item);
@override
Widget build(BuildContext context) {
return Center(
child: FlatButton(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(_item.icon, color:_item.isSelected ? Colors.indigoAccent : Colors.grey[500], size: 35,),
Text(
_item.time,
style: TextStyle(
fontSize: 15,
color: _item.isSelected ? Colors.indigoAccent : Colors.grey[500],
),
),
],
),
),
);
}
}
class RadioModel {
bool isSelected;
String time;
IconData icon;
RadioModel(this.isSelected, this.time, this.icon);
}
Here is how the app look so far.
Upvotes: 4
Views: 4897
Reputation: 54367
Edit
You can use Map
to Map int
to List<RadioModel>
Use Map<int, List<RadioModel>>
to control step1' multi selection
and retrun with step1Index[answer[0]]
code snippet
Map<int, List<RadioModel>> step1Index = {
0: [
RadioModel(false, "Honda", Icons.local_shipping),
RadioModel(false, "Toyota", Icons.title)
],
1: [
RadioModel(false, "abc", Icons.local_shipping),
RadioModel(false, "def", Icons.title)
],
};
List<RadioModel> choiceNextStep() {
return step1Index[answer[0]];
}
You can copy paste run full code below
Full working demo please see below
Step 1: Use List<int> answer = [null, null, null];
to keep step choice
Step 2: Use the StatefulBuilder
to refresh step
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Stepper(
Step 3 : SelectableCard pass parameter by condition
SelectableCard(options: answer[0] == 0 ? step1 : step1_1, step: 1)
Step 4 : SelectableCardState
move sampleData = widget.options;
from initState()
to build
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
List<int> answer = [0, 0, 0];
class _HomePageState extends State<HomePage> {
int _currentStep = 0;
List<RadioModel> step0 = [
RadioModel(false, "New", Icons.directions_car),
RadioModel(false, "Used", Icons.directions_car),
];
Map<int, List<RadioModel>> step1Index = {
0: [
RadioModel(false, "Honda", Icons.local_shipping),
RadioModel(false, "Toyota", Icons.title)
],
1: [
RadioModel(false, "abc", Icons.local_shipping),
RadioModel(false, "def", Icons.title)
],
};
//step1Index
List<RadioModel> step1 = [
RadioModel(false, "Honda", Icons.local_shipping),
RadioModel(false, "Toyota", Icons.title)
];
List<RadioModel> step1_1 = [
RadioModel(false, "abc", Icons.local_shipping),
RadioModel(false, "def", Icons.title)
];
List<RadioModel> step3 = [
RadioModel(false, "Red", Icons.radio_button_checked),
RadioModel(false, "Orage", Icons.radio_button_checked)
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.grey),
backgroundColor: Colors.white,
elevation: 2,
title: Text("Buy Car".toUpperCase(),
style: TextStyle(
color: Colors.grey[700],
fontSize: 17,
)),
// leading: IconButton(
// icon: Icon(Icons.close, size: 28),
// onPressed: () {
// Navigator.of(context).pop();
//
// }),
),
body: Theme(
data: ThemeData(primaryColor: Colors.indigoAccent),
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Stepper(
type: StepperType.vertical,
currentStep: _currentStep,
onStepTapped: (int step) => setState(() => _currentStep = step),
onStepContinue: _currentStep < 2
? () => setState(() => _currentStep += 1)
: null,
onStepCancel: _currentStep > 0
? () => setState(() => _currentStep -= 1)
: null,
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) =>
Container(
height: 70,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
_currentStep == 0
? Text("")
: RaisedButton(
onPressed: onStepCancel,
textColor: Colors.grey,
textTheme: ButtonTextTheme.normal,
child: Row(children: <Widget>[
const Icon(Icons.chevron_left),
Text("PREV")
]),
),
RaisedButton(
onPressed: onStepContinue,
textColor: Colors.white,
color: Colors.indigoAccent,
textTheme: ButtonTextTheme.normal,
child: Row(children: <Widget>[
_currentStep >= 2
? Icon(Icons.done)
: Icon(Icons.chevron_right),
_currentStep >= 2 ? Text("DONE") : Text("NEXT")
]),
),
],
),
),
steps: <Step>[
Step(
title: Text(
"Car",
style: TextStyle(
fontSize: 15,
color: Colors.grey[600],
),
),
content: Column(
children: <Widget>[
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0, bottom: 10),
child: Text(
"What type of car?:",
style: TextStyle(
fontSize: 17,
color: Colors.black,
),
),
),
],
),
SelectableCard(options: step0, step: 0),
],
),
isActive: _currentStep >= 0,
state:
_currentStep >= 0 ? StepState.complete : StepState.disabled,
),
Step(
title: Text(
"Brand",
style: TextStyle(
fontSize: 15,
color: Colors.grey[600],
),
),
content: Column(
children: <Widget>[
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0, bottom: 10),
child: Text(
"Made Company?",
style: TextStyle(
fontSize: 17,
color: Colors.black,
),
),
),
],
),
SelectableCard(options: choiceNextStep(), step: 1)
],
),
isActive: _currentStep >= 1,
state:
_currentStep >= 1 ? StepState.complete : StepState.disabled,
),
Step(
title: Text(
"Color",
style: TextStyle(
fontSize: 15,
color: Colors.grey[600],
),
),
content: SelectableCard(options: step3, step: 2),
isActive: _currentStep >= 2,
state:
_currentStep >= 3 ? StepState.complete : StepState.disabled,
),
],
);
}),
),
);
}
List<RadioModel> choiceNextStep() {
return step1Index[answer[0]];
/*if (answer[0] == 0) {
return step1;
} else {
return step1_1;
}*/
}
Widget _commentary() {
return TextFormField(
keyboardType: TextInputType.multiline,
maxLines: 3,
decoration: InputDecoration(
labelText: 'i.e - Concurrent Area',
),
);
}
}
class SelectableInLineCard extends StatefulWidget {
final List<RadioModel> options;
SelectableInLineCard({@required this.options});
@override
_SelectableInLineCardState createState() => _SelectableInLineCardState();
}
class _SelectableInLineCardState extends State<SelectableInLineCard> {
List<RadioModel> sampleData = new List<RadioModel>();
void initState() {
// TODO: implement initState
super.initState();
sampleData = widget.options;
}
@override
Widget build(BuildContext context) {
return GridView.builder(
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 12),
),
itemCount: sampleData.length,
itemBuilder: (context, index) {
return Card(
shape: sampleData[index].isSelected
? RoundedRectangleBorder(
side: BorderSide(color: Colors.indigoAccent, width: 2.0),
borderRadius: BorderRadius.circular(4.0))
: RoundedRectangleBorder(
side: BorderSide(color: Colors.grey[200], width: 2.0),
borderRadius: BorderRadius.circular(4.0)),
color: Colors.white,
elevation: 0,
child: InkWell(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
onTap: () {
setState(() {
sampleData.forEach((element) => element.isSelected = false);
sampleData[index].isSelected = true;
//print(sampleData[index].time);
});
},
child: GridTile(
child: FlatButton(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
sampleData[index].time,
style: TextStyle(
fontSize: 15,
color: sampleData[index].isSelected
? Colors.indigoAccent
: Colors.grey[500],
),
),
],
),
],
),
),
),
),
);
},
);
}
}
class SelectableCard extends StatefulWidget {
final List<RadioModel> options;
final int step;
SelectableCard({@required this.options, @required this.step});
@override
_SelectableCardState createState() => _SelectableCardState();
}
class _SelectableCardState extends State<SelectableCard> {
List<RadioModel> sampleData = new List<RadioModel>();
@override
void initState() {
// TODO: implement initState
super.initState();
//sampleData = widget.options;
//print(sampleData.toString());
}
@override
Widget build(BuildContext context) {
sampleData = widget.options;
print(sampleData.toString());
return GridView.builder(
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 2.5),
),
itemCount: sampleData.length,
itemBuilder: (context, index) {
return Card(
shape: sampleData[index].isSelected
? RoundedRectangleBorder(
side: BorderSide(color: Colors.indigoAccent, width: 2.0),
borderRadius: BorderRadius.circular(4.0))
: RoundedRectangleBorder(
side: BorderSide(color: Colors.grey[200], width: 2.0),
borderRadius: BorderRadius.circular(4.0)),
color: Colors.white,
elevation: 0,
child: InkWell(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
onTap: () {
setState(() {
sampleData.forEach((element) => element.isSelected = false);
sampleData[index].isSelected = true;
print('step ${widget.step}');
print('index ${index}');
answer[widget.step] = index;
print(answer[widget.step]);
});
},
child: GridTile(child: RadioItem(sampleData[index])),
),
);
},
);
}
}
class RadioItem extends StatelessWidget {
final RadioModel _item;
RadioItem(this._item);
@override
Widget build(BuildContext context) {
return Center(
child: FlatButton(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
_item.icon,
color: _item.isSelected ? Colors.indigoAccent : Colors.grey[500],
size: 35,
),
Text(
_item.time,
style: TextStyle(
fontSize: 15,
color:
_item.isSelected ? Colors.indigoAccent : Colors.grey[500],
),
),
],
),
),
);
}
}
class RadioModel {
bool isSelected;
String time;
IconData icon;
RadioModel(this.isSelected, this.time, this.icon);
}
Upvotes: 8