How to set radio buttons in bottomsheet flutter - flutter

I want to make a design in which by clicking on the bottom sheet it will show radio buttons. When I select the radio button it will open the date picker. Below is my code when I click on the radio button it is not selecting the radio button. I am new in flutter so can someone helps me find the mistake in the code?
import 'package:flutter/material.dart';
import 'BottomSheetWidget.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(title: 'Flutter Demo', home: HomeView());
}
}
class HomeView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: MyFloatingButton(),
);
}
}
class MyFloatingButton extends StatefulWidget {
#override
_MyFloatingButtonState createState() => _MyFloatingButtonState();
}
class _MyFloatingButtonState extends State<MyFloatingButton> {
bool _show = true;
#override
Widget build(BuildContext context) {
int _radioValue = 0;
/* var sheetController = showBottomSheet(
context: context,
builder: (context) => BottomSheetWidget());*/
void _handleRadioValueChange(int value) {
setState(() {
_radioValue = value;
});
print("first"+value.toString()+"radiovalue" +_radioValue.toString());
}
return Container(
margin: EdgeInsets.all(10.0),
child: new Wrap(
children: <Widget>[
Center(
child: Container(
height: 3.0, width: 40.0, color: Color(0xFF32335C))),
SizedBox(
height: 10.0,
),
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Radio(
value: 0,
groupValue: _radioValue,
onChanged: (value) {setState(() {
_radioValue=value;
});
print("radiofirst"+value.toString()+"radiovalue" +_radioValue.toString());
_handleRadioValueChange(value);
},
),
new Text(
'Single Date',
style: new TextStyle(fontSize: 16.0),
),
new Radio(
value: 1,
groupValue: _radioValue,
onChanged: (value) {setState(() {
_radioValue=value;
});
print("radiosecond "+value.toString()+"radiovalue " +_radioValue.toString());
_handleRadioValueChange(value);
},
),
new Text(
'Dual Date',
style: new TextStyle(
fontSize: 16.0,
),
),
],
),
],
),
);
}
}

You can copy paste run full code below
You can move out int _radioValue = 0; and _handleRadioValueChange from build
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(title: 'Flutter Demo', home: HomeView());
}
}
class HomeView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: MyFloatingButton(),
);
}
}
class MyFloatingButton extends StatefulWidget {
#override
_MyFloatingButtonState createState() => _MyFloatingButtonState();
}
class _MyFloatingButtonState extends State<MyFloatingButton> {
bool _show = true;
int _radioValue = 0;
/* var sheetController = showBottomSheet(
context: context,
builder: (context) => BottomSheetWidget());*/
void _handleRadioValueChange(int value) {
setState(() {
_radioValue = value;
});
print("first" + value.toString() + "radiovalue" + _radioValue.toString());
}
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
child: Wrap(
children: <Widget>[
Center(
child: Container(
height: 3.0, width: 40.0, color: Color(0xFF32335C))),
SizedBox(
height: 10.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Radio(
value: 0,
groupValue: _radioValue,
onChanged: (value) {
setState(() {
_radioValue = value;
});
print("radiofirst" +
value.toString() +
"radiovalue" +
_radioValue.toString());
_handleRadioValueChange(value);
},
),
Text(
'Single Date',
style: TextStyle(fontSize: 16.0),
),
Radio(
value: 1,
groupValue: _radioValue,
onChanged: (value) {
setState(() {
_radioValue = value;
});
print("radiosecond " +
value.toString() +
"radiovalue " +
_radioValue.toString());
_handleRadioValueChange(value);
},
),
Text(
'Dual Date',
style: TextStyle(
fontSize: 16.0,
),
),
],
),
],
),
);
}
}

Related

how to control slider value with buttons in flutter ui

how to control slider with add and subtract buttons in flutter UI
Try this code :
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
double _currentSliderValue = 20;
int divisons=20;
#override
Widget build(BuildContext context) {
return Column(
children: [
Row(
children: [
IconButton(
icon: Icon(Icons.remove),
onPressed: () {
setState(() {
_currentSliderValue -= divisons;
});
},
),
Text(_currentSliderValue.toString()),
IconButton(
icon: Icon(Icons.add),
onPressed: () {
setState(() {
_currentSliderValue += divisons;
});
},
),
],
),
Slider(
value: _currentSliderValue,
max: 100,
divisions: 5,
label: _currentSliderValue.round().toString(),
onChanged: (double value) {
setState(() {
_currentSliderValue = value;
});
},
),
],
);
}
}
Hope this helps.
Simplified sample
class MyWidget extends StatefulWidget{
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
int _value = 5;
double min = 1.0;
double max = 20.0;
#override
Widget build(BuildContext context) {
return Column(
children:[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:[
IconButton(onPressed:(){
setState((){
if(_value < max){
/// Add as many as you want
_value++;
}
});
}, icon: const Icon(Icons.add)),
IconButton(onPressed:(){
setState((){
if(_value > min){
/// Subtract as many as you want
_value--;
}
});
}, icon: const Icon(Icons.remove)),
]
),
Slider(
value: _value.toDouble(),
min: min,
max: max,
activeColor: Colors.green,
inactiveColor: Colors.orange,
label: 'Set volume value',
onChanged: (double newValue) {
setState(() {
_value = newValue.round();
});
},
),
]);
}
}
here I have made a demo on learning purpose, it might help u
class _SliderPageState extends State<SliderPage> {
double _currentSliderValue=15.0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(onPressed: (){
setState(() {
if(_currentSliderValue<100)
_currentSliderValue=_currentSliderValue+1;
});
}, icon: Icon(Icons.add)),
Text(_currentSliderValue.round().toString(),style: TextStyle(fontWeight: FontWeight.bold,fontSize: 24),),
IconButton(onPressed: (){
setState(() {
if(_currentSliderValue>1)
_currentSliderValue=_currentSliderValue-1;
});
}, icon: Icon(Icons.remove)),
],),
Slider(
value: _currentSliderValue,
max: 100,
divisions: 100,
//label: _currentSliderValue.round().toString(),
onChanged: (double value) {
setState(() {
_currentSliderValue = value;
});
},
),
],)
),
);
}
}

Open / close filter menu

I have a code that is responsible for building a menu filter. It allows you to filter data by category and then by subcategory.
Initially, subcategories are in a closed state, but when you click on the arrow, they can be opened. Take a look
But my problem is that if I click on the arrow for any category (Country in my case), then all subcategories open at once. Take a look
It's my code
class _FilterDialogUserState extends State<FilterDialogUser> {
Map<String, List<String>?> filters = {};
bool needRefresh = false;
bool isClickedCountry = false;
#override
void initState() {
super.initState();
filters = widget.initialState;
}
List<FilterItem> children = [
FilterItem('Georgia', subitems: [
FilterItem('Tbilisi'),
FilterItem('Batumi'),
]),
FilterItem('Poland', subitems: [
FilterItem('Warsaw'),
FilterItem('Krakow'),
FilterItem('Wroclaw'),
]),
FilterItem('Armenia', subitems: [
FilterItem('Erevan'),
FilterItem('Gyumri'),
]),
];
// Building a dialog box with filters.
#override
Widget build(BuildContext context) {
return SimpleDialog(
title: const Text('Filters',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontFamily: 'SuisseIntl',
)),
contentPadding: const EdgeInsets.all(16),
// Defining parameters for filtering.
children: [
Column(
children: children.map(
(e) {
return Column(
children: [
InkWell(
onTap: () async {
setState(() {
isClickedCountry = !isClickedCountry;
});
},
child: Row(
children: [
Checkbox(
value: e.selected,
onChanged: (value) => setState(() {
e.subitems.forEach((element) =>
element.selected = value as bool);
e.selected = value as bool;
}),
),
Text(e.text),
const Spacer(),
isClickedCountry
? const Icon(Icons.arrow_circle_up)
: const Icon(Icons.arrow_circle_down)
],
),
),
if (e.subitems.isNotEmpty)
!isClickedCountry
? Container()
: Padding(
padding: const EdgeInsets.fromLTRB(30, 0, 0, 0),
child: Column(
children: e.subitems.map((e) {
return Row(children: [
Checkbox(
value: e.selected,
onChanged: (value) => setState(() {
e.selected = value as bool;
}),
),
Text(e.text),
]);
}).toList(),
),
)
],
);
},
).toList(),
),
]);
}
}
class FilterItem {
final String text;
bool selected;
List<FilterItem> subitems;
FilterItem(
this.text, {
this.selected = false,
this.subitems = const [],
});
}
Tell me, is it possible to change my code so that not all subcategories are opened, but only the one that the user clicks on?
The each main filter item must be controlled one by one.
Define List isClickedCountry variable
Save and load state from List isClickedCountry variable
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _buildBody() {
return FilterDialogUser();
}
}
class FilterDialogUser extends StatefulWidget {
FilterDialogUser({Key key}) : super(key: key);
#override
State<FilterDialogUser> createState() => _FilterDialogUserState();
}
class _FilterDialogUserState extends State<FilterDialogUser> {
Map<String, List<String>> filters = {};
bool needRefresh = false;
List<bool> isClickedCountry = List.filled(3, false);
#override
void initState() {
super.initState();
// filters = widget.initialState;
}
List<FilterItem> children = [
FilterItem('Georgia', subitems: [
FilterItem('Tbilisi'),
FilterItem('Batumi'),
]),
FilterItem('Poland', subitems: [
FilterItem('Warsaw'),
FilterItem('Krakow'),
FilterItem('Wroclaw'),
]),
FilterItem('Armenia', subitems: [
FilterItem('Erevan'),
FilterItem('Gyumri'),
]),
];
// Building a dialog box with filters.
#override
Widget build(BuildContext context) {
return SimpleDialog(
title: const Text('Filters',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontFamily: 'SuisseIntl',
)),
contentPadding: const EdgeInsets.all(16),
// Defining parameters for filtering.
children: [
Column(
children: children.map(
(e) {
final int index = children.indexOf(e);
return Column(
children: [
InkWell(
onTap: () async {
setState(() {
isClickedCountry[index] = !isClickedCountry[index];
});
},
child: Row(
children: [
Checkbox(
value: e.selected,
onChanged: (value) => setState(() {
e.subitems.forEach((element) =>
element.selected = value as bool);
e.selected = value as bool;
}),
),
Text(e.text),
const Spacer(),
isClickedCountry[index]
? const Icon(Icons.arrow_circle_up)
: const Icon(Icons.arrow_circle_down)
],
),
),
if (e.subitems.isNotEmpty)
!isClickedCountry[index]
? Container()
: Padding(
padding: const EdgeInsets.fromLTRB(30, 0, 0, 0),
child: Column(
children: e.subitems.map((e) {
return Row(children: [
Checkbox(
value: e.selected,
onChanged: (value) => setState(() {
e.selected = value as bool;
}),
),
Text(e.text),
]);
}).toList(),
),
)
],
);
},
).toList(),
),
]);
}
}
class FilterItem {
final String text;
bool selected;
List<FilterItem> subitems;
FilterItem(
this.text, {
this.selected = false,
this.subitems = const [],
});
}

Flutter ChangeNotifier was used after being disposed

I have checked mukltiple posts on this matter, but none has helped, while some stopped the error (e.g. adding a variable that stops the function to notifylistener after its disposed), it certainly didnt fix it.
My Goal is to make a shopping list that just records the state of each checkbox in a tab and displays it using navigator.push and back using pop
Source Code:
home.dart
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
import 'package:loginpage/main.dart';
import 'package:badges/badges.dart';
import 'package:provider/provider.dart';
import 'tabPage.dart';
import 'mobileList.dart';
import 'itemList.dart';
class HomePage extends StatefulWidget {
HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
LoginPage loginPage = LoginPage();
TabPage? tabPage;
#override
void initState() {
super.initState();
tabPage = TabPage(
key: GlobalKey<TabPageState>(),
tabNum: 10,
controlNum: 3,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home Page"),
leading: IconButton(
onPressed: () {
//Back to Login Page
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginPage()));
},
icon: Image.asset('assets/images/backbtn.png'),
),
actions: [
ChangeNotifierProvider(
create: (context) => tabPage!.checkBoxInfo,
child: Consumer<CheckBoxInfo>(
builder: (context, checkBoxInfo, child) {
return Badge(
position: BadgePosition.topEnd(top: 0, end: 0),
shape: BadgeShape.square,
borderRadius: BorderRadius.circular(20),
badgeContent: Text(checkBoxInfo.checked.toString()),
animationType: BadgeAnimationType.scale,
animationDuration: Duration(milliseconds: 50),
child: IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ItemList(
checkBoxInfo: tabPage!.checkBoxInfo)));
},
icon: Icon(Icons.shopping_cart)),
);
},
),
),
],
),
body: SafeArea(
child: Scaffold(
body: Center(
child: Column(
children: <Widget>[
SizedBox(height: 30),
Text('This is the Home Page'),
SizedBox(height: 20),
Text(loginPage.username),
//Tab Page
Container(
child: tabPage,
),
TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MobileList(data: data)));
},
child: Text("Mobile List")),
],
),
),
),
),
floatingActionButton: Container(
decoration:
BoxDecoration(color: Colors.grey[800], shape: BoxShape.circle),
child: IconButton(
color: Colors.lightBlue,
onPressed: () {
// tabPage!.tabindex == tabPage!.tabNum - 1
// ? tabPage!.tabindex = 0
// : tabPage!.tabindex += 1;
// //callback method
// //GlobalKey method
// //Set Global Key
// (tabPage!.key as GlobalKey<TabPageState>) //Casting
// .currentState
// ?.tabSetState();
// // tabPageKey.currentState?.tabSetState();
(tabPage!.key as GlobalKey<TabPageState>)
.currentState!
.scrollToOffset(100, Duration(milliseconds: 200));
},
icon: const Icon(Icons.ac_unit_outlined)),
),
);
}
}
tabPage.dart
import 'package:flutter/material.dart';
import 'dart:developer';
import 'package:loginpage/pages/home.dart';
class TabPage extends StatefulWidget {
TabPage({Key? key, required this.tabNum, required this.controlNum})
: super(key: key);
final int controlNum;
final int tabNum;
final String _example = "";
CheckBoxInfo checkBoxInfo = CheckBoxInfo();
int tabindex = 0;
#override
State<StatefulWidget> createState() => TabPageState();
}
class TabPageState extends State<TabPage> {
List<String> tabTitles = [];
List<List<Widget>> tabs = [];
ScrollController? _scrollController;
void scrollToOffset(increment, duration) {
_scrollController!.animateTo(_scrollController!.offset + increment,
duration: duration, curve: Curves.ease);
}
void tabSetState() {
setState(() {});
}
#override
void initState() {
super.initState();
tabTitles = createTabTitles(widget.tabNum);
_scrollController = ScrollController(initialScrollOffset: 20);
_scrollController!.addListener(() {
print(_scrollController!.offset);
});
widget.checkBoxInfo
.initCheckBox(widget.controlNum, widget.tabNum, tabTitles);
}
#override
Widget build(BuildContext context) {
tabs = createTabs(widget.tabNum);
return SafeArea(
child: Column(
children: [
SizedBox(
height: 10,
),
Container(
margin: EdgeInsets.only(left: 20.0, right: 20.0),
decoration: BoxDecoration(
border: Border.all(width: 3, color: Colors.black)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _scrollController,
child: Row(
// children: tabTitles
// .asMap()
// .map((i, title) => MapEntry(
// i,
// TextButton(
// onPressed: () {
// setState(() {
// widget.tabindex = i;
// });
// },
// child: Text(tabTitles[i]),
// )))
// .values
// .toList()
// children: tabTitles.map((title) => TextButton(
// onPressed: () {
// setState(() {
// widget.tabindex = i;
// });
// },
// child: Text(tabTitles[i]),
// )).toList(),
children: createTabBtns(),
),
),
Padding(
padding: EdgeInsets.all(5),
child: Column(
children: tabs[widget.tabindex],
),
)
]),
),
],
),
);
}
List<Widget> createTabBtns() {
List<Widget> btnList = [];
for (int i = 0; i < tabTitles.length; i++) {
btnList.add(Container(
decoration: BoxDecoration(
border: Border(
right: BorderSide(width: 1, color: Colors.grey),
bottom: widget.tabindex == i
? BorderSide(width: 4, color: Colors.blue[400]!)
: BorderSide(width: 4, color: Colors.grey[400]!))),
child: TextButton(
onPressed: () {
setState(() {
widget.tabindex = i;
});
},
child: Text(tabTitles[i]),
),
));
}
return btnList;
}
List<List<Widget>> createTabs(tabNum) {
List<List<Widget>> tabList = [];
for (int i = 0; i < tabNum; i++) {
List<Widget> tabContent = [
Align(
alignment: Alignment.centerLeft,
child: Text(
tabTitles[i] + " Items",
),
),
...createCheckBoxList(widget.controlNum, tabTitles[i])
];
tabList.add(tabContent);
}
return tabList;
}
List<Widget> createCheckBoxList(controlNum, tabTitle) {
List<Widget> CBList = [];
for (int i = 0; i < controlNum; i++) {
String checkBoxName = '${tabTitle} Item $i';
CBList.add(CheckboxListTile(
title: Text('${tabTitle} Item $i'),
value: widget.checkBoxInfo.isChecked(checkBoxName),
onChanged: (newValue) {
setState(() {
widget.checkBoxInfo.setCheckBox(checkBoxName, newValue!);
});
}));
}
return CBList;
}
List<String> createTabTitles(tabNum) {
List<String> tabTitles = [];
for (int i = 0; i < tabNum; i++) {
tabTitles.add("A" + i.toString());
}
return tabTitles;
}
}
class CheckBoxInfo extends ChangeNotifier {
Map<String, bool> checkBoxState = {};
int checked = 0;
bool disposed = false;
void setCheckBox(String name, bool state) {
checkBoxState[name] = state;
checkChecked();
notifyListeners();
}
bool isChecked(String name) {
return checkBoxState[name]!;
}
void initCheckBox(int controlNum, int tabNum, List<String> tabTitles) {
for (int i = 0; i < tabNum; i++) {
String checkBoxName = '${tabTitles[i]} ';
for (int i = 0; i < controlNum; i++) {
setCheckBox(checkBoxName + 'Item $i', false);
}
}
}
void checkChecked() {
int _checked = 0;
checkBoxState.forEach((key, value) {
_checked += value == true ? 1 : 0;
});
checked = _checked;
}
}
itemList.dart
import 'dart:collection';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:loginpage/pages/tabPage.dart';
import 'dart:developer';
import 'package:provider/provider.dart';
import 'home.dart';
class ItemList extends StatefulWidget {
ItemList({Key? key, required this.checkBoxInfo}) : super(key: key);
final CheckBoxInfo checkBoxInfo;
#override
State<StatefulWidget> createState() => ItemListState();
}
class ItemListState extends State<ItemList> {
List<Widget> itemList = [];
#override
void initState() {
super.initState();
itemList = setItemList(widget.checkBoxInfo);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Item List"),
leading: IconButton(
onPressed: () {
//Back to Home Page
Navigator.pop(context);
},
icon: Image.asset('assets/images/backbtn.png'),
),
),
body: SafeArea(
child: Container(
child: ChangeNotifierProvider(
create: (context) => widget.checkBoxInfo,
child: Consumer<CheckBoxInfo>(
builder: (context, checkBoxInfo, child) {
return Column(
children: itemList,
);
},
),
))),
);
}
List<Widget> setItemList(CheckBoxInfo checkBoxInfo) {
List<Widget> tempItemList = [];
checkBoxInfo.checkBoxState.forEach((key, value) {
if (checkBoxInfo.checkBoxState[key]!) {
tempItemList.add(Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 2),
),
child: Padding(
padding: EdgeInsets.all(8),
child: Row(
children: [
Text(
key,
overflow: TextOverflow.ellipsis,
),
SizedBox(
width: 20,
),
Icon(value ? Icons.check : Icons.cancel_outlined)
],
),
),
));
}
});
return tempItemList;
}
}
THe error is the following: A CheckBoxInfo was used after being disposed.
I dont know why it doesnt work, and according to my senior, the provider should work sort of like the local storage in web.
I think there is all sorts of things going wrong here.
You create your TabPage widget on the fly, and you put your state - checkBoxInfo - in it. And then you expose it through ChangeNotifierProvider. After that you add the TabPage to the Widget tree - which will eventually create it's state object...
As soon as you navigate from the page that shows your TabPage, it's state object and the widget itself will be disposed. And your ChangeNotifierProvider is gone, too.
The thing is: it's not your ChangeNotifierProvider that is holding your state, it is the widget underneath it.
Edit: here's the code that should work. I commented out some navigation (Login Page etc.) to make it work.
In the code, ChangeNotifierProvider is above the MaterialApp - making sure it is visible in all pages you try to navigate to.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<CheckBoxInfo>(
create: (context) => CheckBoxInfo(3, 10), //tabPage!.checkBoxInfo,
child: MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: HomePage(),
),
),
));
}
}
class HomePage extends StatelessWidget {
HomePage({Key? key}) : super(key: key);
final _tabKey = GlobalKey<TabPageState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Home Page"),
leading: IconButton(
onPressed: () {
//Back to Login Page
// Navigator.push(
// context, MaterialPageRoute(builder: (context) => LoginPage()));
},
icon: const Icon(Icons.arrow_back), //.asset('assets/images/backbtn.png'),
),
actions: [
Consumer<CheckBoxInfo>(
builder: (context, checkBoxInfo, child) {
return IconButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const ItemList()));
},
icon: const Icon(Icons.shopping_cart),
);
},
),
]),
body: SafeArea(
child: Scaffold(
body: Center(
child: Column(
children: <Widget>[
const SizedBox(height: 30),
const Text('This is the Home Page'),
const SizedBox(height: 20),
const Text("Test"),
//Tab Page
Consumer<CheckBoxInfo>(builder: (context, checkBoxInfo, child) {
return TabPage(key: _tabKey, tabNum: checkBoxInfo.tabNum, controlNum: checkBoxInfo.controlNum);
}),
TextButton(
onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => MobileList(data: data)));
},
child: const Text("Mobile List")),
],
),
),
),
),
floatingActionButton: Container(
decoration: BoxDecoration(color: Colors.grey[800], shape: BoxShape.circle),
child: IconButton(
color: Colors.lightBlue,
onPressed: () {
_tabKey.currentState!.scrollToOffset(100, const Duration(milliseconds: 200));
},
icon: const Icon(Icons.ac_unit_outlined)),
),
);
}
}
class TabPage extends StatefulWidget {
const TabPage({Key? key, required this.tabNum, required this.controlNum}) : super(key: key);
final int controlNum;
final int tabNum;
#override
State<StatefulWidget> createState() => TabPageState();
}
class TabPageState extends State<TabPage> {
List<List<Widget>> tabs = [];
ScrollController? _scrollController;
int tabindex = 0;
void scrollToOffset(increment, duration) {
_scrollController!.animateTo(_scrollController!.offset + increment, duration: duration, curve: Curves.ease);
}
void tabSetState() {
setState(() {});
}
#override
void initState() {
super.initState();
_scrollController = ScrollController(initialScrollOffset: 20);
_scrollController!.addListener(() {
print(_scrollController!.offset);
});
}
#override
Widget build(BuildContext context) {
var checkBoxInfo = Provider.of<CheckBoxInfo>(context, listen: false);
tabs = createTabs(checkBoxInfo);
return SafeArea(
child: Column(
children: [
const SizedBox(
height: 10,
),
Container(
margin: const EdgeInsets.only(left: 20.0, right: 20.0),
decoration: BoxDecoration(border: Border.all(width: 3, color: Colors.black)),
child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _scrollController,
child: Row(
children: createTabBtns(checkBoxInfo.tabTitles),
),
),
Padding(
padding: const EdgeInsets.all(5),
child: Column(
children: tabs[tabindex],
),
)
]),
),
],
),
);
}
List<Widget> createTabBtns(List<String> tabTitles) {
List<Widget> btnList = [];
for (int i = 0; i < widget.tabNum; i++) {
btnList.add(Container(
decoration: BoxDecoration(
border: Border(
right: const BorderSide(width: 1, color: Colors.grey),
bottom: tabindex == i
? BorderSide(width: 4, color: Colors.blue[400]!)
: BorderSide(width: 4, color: Colors.grey[400]!))),
child: TextButton(
onPressed: () {
setState(() {
tabindex = i;
});
},
child: Text(tabTitles[i]),
),
));
}
return btnList;
}
List<List<Widget>> createTabs(CheckBoxInfo checkBoxInfo) {
List<List<Widget>> tabList = [];
for (int i = 0; i < widget.tabNum; i++) {
List<Widget> tabContent = [
Align(
alignment: Alignment.centerLeft,
child: Text(
checkBoxInfo.tabTitles[i] + " Items",
),
),
...createCheckBoxList(checkBoxInfo, checkBoxInfo.tabTitles[i])
];
tabList.add(tabContent);
}
return tabList;
}
List<Widget> createCheckBoxList(checkBoxInfo, tabTitle) {
List<Widget> cBList = [];
for (int i = 0; i < widget.controlNum; i++) {
String checkBoxName = '$tabTitle Item $i';
cBList.add(CheckboxListTile(
title: Text('$tabTitle Item $i'),
value: checkBoxInfo.isChecked(checkBoxName),
onChanged: (newValue) {
setState(() {
checkBoxInfo.setCheckBox(checkBoxName, newValue!);
});
}));
}
return cBList;
}
}
class CheckBoxInfo extends ChangeNotifier {
Map<String, bool> checkBoxState = {};
int checked = 0;
// bool disposed = false;
List<String> tabTitles = [];
int controlNum;
int tabNum;
CheckBoxInfo(this.controlNum, this.tabNum) {
for (int i = 0; i < tabNum; i++) {
String tabTitle = "A" + i.toString();
tabTitles.add(tabTitle);
for (int i = 0; i < controlNum; i++) {
setCheckBox(tabTitle + ' Item $i', false);
}
}
}
void setCheckBox(String name, bool state) {
checkBoxState[name] = state;
checkChecked();
notifyListeners();
}
bool isChecked(String name) {
return checkBoxState[name]!;
}
void checkChecked() {
int _checked = 0;
checkBoxState.forEach((key, value) {
_checked += value == true ? 1 : 0;
});
checked = _checked;
}
}
class ItemList extends StatelessWidget {
const ItemList({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
var checkBoxInfo = Provider.of<CheckBoxInfo>(context, listen: false);
var itemList = setItemList(checkBoxInfo);
return Scaffold(
appBar: AppBar(
title: const Text("Item List"),
leading: IconButton(
onPressed: () {
//Back to Home Page
Navigator.pop(context);
},
icon: const Icon(Icons.arrow_back),
),
),
body: SafeArea(
child: Consumer<CheckBoxInfo>(
builder: (context, checkBoxInfo, child) {
return Column(
children: itemList,
);
},
),
));
}
List<Widget> setItemList(CheckBoxInfo checkBoxInfo) {
List<Widget> tempItemList = [];
checkBoxInfo.checkBoxState.forEach((key, value) {
if (value) {
tempItemList.add(Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 2),
),
child: Padding(
padding: const EdgeInsets.all(8),
child: Row(
children: [
Text(
key,
overflow: TextOverflow.ellipsis,
),
const SizedBox(
width: 20,
),
Icon(value ? Icons.check : Icons.cancel_outlined)
],
),
),
));
}
});
return tempItemList;
}
}
#override
void dispose() {
_disposed = true;
super.dispose();
}
#override
void notifyListeners() {
if (!_disposed) {
super.notifyListeners();
}
}

how to pass from object state to object and then pass it to another screen

I need your help,
At first I have two pages, both of them are stateful widget, one of them is the main screen, 2nd page has data and i want to pass it to the main screen
mainpage
code
#override
_PriceScreenState createState() => _PriceScreenState();
}
class _PriceScreenState extends State<PriceScreen> {
String selectedCurrency = 'USD';
String bitcoinValueInUSD;
int dropNumber;
void getCurrenciesBitcoin() async {
try {
CoinData coinData = CoinData();
double usdPrice = await coinData.getCurrencies();
setState(() {
bitcoinValueInUSD = usdPrice.toStringAsFixed(0);
});
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
getCurrenciesBitcoin();
return Scaffold(
appBar: AppBar(
title: Text('🤑 Coin Ticker'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 0),
child: Card(
color: Colors.lightBlueAccent,
elevation: 5.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 28.0),
child: Text(
'1 BTC = $bitcoinValueInUSD $selectedCurrency',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
),
),
),
Container(
height: 150.0,
alignment: Alignment.center,
padding: EdgeInsets.only(bottom: 30.0),
color: Colors.lightBlue,
child: GetDropDownMenu(
selectedCurrency: ,
),
),
],
),
);
}
}
and this is the second page
class GetDropDownMenu extends StatefulWidget {
#override
_GetDropDownMenuState createState() => _GetDropDownMenuState();
}
class _GetDropDownMenuState extends State<GetDropDownMenu> {
String selectedCurrency;
List<DropdownMenuItem<String>> getDropDownItem() {
List<DropdownMenuItem<String>> dropDownItems = [];
for (String currency in currenciesList) {
var newItem = DropdownMenuItem(
child: Text(currency),
value: currency,
);
dropDownItems.add(newItem);
}
return dropDownItems;
}
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: selectedCurrency,
items: getDropDownItem(),
onChanged: (value) {
setState(() {
selectedCurrency = value;
});
});
}
}
, what i need is to pass the selectedCurrency value from 2nd page to the main page to be equal selectedCurrency variable there
You can add callback function in the constructor to return the dropdown value.
For example
class GetDropDownMenu extends StatefulWidget {
final Function(String) onSubmitted;
const GetDropDownMenu({Key key, this.onSubmitted}) : super(key: key);
#override
_GetDropDownMenuState createState() => _GetDropDownMenuState();
}
class _GetDropDownMenuState extends State<GetDropDownMenu> {
String selectedCurrency;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: selectedCurrency,
items: getDropDownItem(),
onChanged: (value) {
setState(() {
selectedCurrency = value;
});
widget.onSubmitted(value);
});
}
}
How to use:
GetDropDownMenu(
onSubmitted: (val) {
print("Result value on dropdown: $val");
},
)
The easiest way:
1. From 1st Screen navigate to others as:
Navigator.pushNamed(context, "second",arguments: selectedCurrency);
},
2. On Second Screen in build method get as :
#override
Widget build(BuildContext context) {
var passedValue = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(title: Text("Second")),
body: Container(
child: Column(
children: <Widget>[
Text("PassedValue : $passedValue"),
],
),
),
);
}
Hope it will be useful

List for a class clears out after making new widget

Im trying to learn flutter, but i have stumbled upon a problem i can't solve. I have a class MyApp/MyAppState that has a list of widgets (ovelser), that is used in a listVeiw.builder.
import './barbutton.dart';
import './ovelser.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
// This widget is the root of your application.
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
List<Widget> ovelser = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("progresjon"),
backgroundColor: Colors.blue,
actions: <Widget>[AddButton(nameOvelse)],
),
body: ListView.builder(
itemCount: ovelser.length,
itemBuilder: (context, index) {
final Widget ovelse = ovelser[index]; // lagrer bare ovelse objektet
return Dismissible(
// dismissible gjør det mulig å slette ting i listView
key: UniqueKey(),
onDismissed: (direction) {
//hva som skjer når man skal slette
setState(() {
ovelser.removeAt(index);
});
},
background: Container(
color: Colors.red,
),
//child er hva som skal være objektet som kan slettes
child: ovelse,
);
},
),
);
}
void addOvelse(String name) {
setState(() {
ovelser.add(Ovelser(name));
});
print(ovelser.length);
}
nameOvelse(BuildContext context) {
TextEditingController custumcontroller = TextEditingController();
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("new activity"),
content: TextField(
controller: custumcontroller,
),
actions: <Widget>[
FlatButton(
child: Text("create"),
onPressed: () {
String activityName = " " + custumcontroller.text;
addOvelse(activityName);
Navigator.of(context).pop();
},
)
],
);
},
);
}
}
the list ovelser takes in Ovelser objects. these objects have a class that has a list that takes in integers (progresjonsList) that i can add to via an AlertDialog.
Code for the class with progresjonList in int:
import './ovleseraddbutton.dart';
class Ovelser extends StatefulWidget {
final String name;
Ovelser(this.name);
#override
OvelserState createState() => OvelserState();
}
class OvelserState extends State<Ovelser> {
List<int> progresjonList = [];
#override
Widget build(BuildContext context) {
return Container(
height: 80,
width: double.infinity,
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
border: Border(
top: BorderSide(width: 0.5, color: Colors.grey),
bottom: BorderSide(width: 0.5, color: Colors.grey),
)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
child: Container(
child: Text(widget.name,
overflow: TextOverflow.fade,
softWrap: false,
maxLines: 1,
style: TextStyle(
fontStyle: FontStyle.italic,
fontSize: 20,
fontWeight: FontWeight.bold)),
)),
OvelserAddbutton(addvalue)
]),
);
}
void insertValue(int value) {
setState(() {
this.progresjonList.add(value);
});
}
addvalue(BuildContext context) {
TextEditingController custumcontroller = TextEditingController();
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("add new value"),
content: TextField(
controller: custumcontroller,
keyboardType: TextInputType.number,
),
actions: <Widget>[
FlatButton(
child: Text("add"),
onPressed: () {
String stringnumber = custumcontroller.text;
int number = int.parse(stringnumber);
insertValue(number);
print(number);
print(progresjonList.length);
print(this.progresjonList);
Navigator.of(context).pop();
},
)
],
);
},
);
}
}
the problem is every time i create a new widget in ovelser (the list that is used in ListView) the lists with integers (progresjonList) clears out so they are empty and dont retain the values previously added by the AlertDialog. I dont understand how i can keep that from happening, so that i keep the integers added. Can anyone help me? thank you in advance:)
there are tow other small files that only have icon widgets in them that i dont think are the problem, but if you need them here they are:)
class AddButton extends StatelessWidget {
final Function setInFunction;
AddButton(this.setInFunction);
#override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.add),
onPressed: () => setInFunction(context),
);
}
}
import 'package:flutter/material.dart';
class OvelserAddbutton extends StatelessWidget {
final Function setInFunction;
OvelserAddbutton(this.setInFunction);
#override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.add),
onPressed: () => setInFunction(context),
);
}
}
```
progessjonList is local to Ovelser class. You need to pass overserList to Ovelser class.
class Ovelser extends StatefulWidget {
final String name;
final List<int> list;
Ovelser(this.name, this.list);
#override
OvelserState createState() => OvelserState();
}
Then when you want to add to the list in OvelserState just use
widget.list.add(/*add int here*/);
Which I see is in your insertValue function
void insertValue(int value) {
setState(() {
widget.list.add(value);
});
}
The list you pass in will be a reference to the ovelser list from the original class.