Here is my class
class Home extends StatelessWidget {
and the Checkbox goes here.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
TextField(
controller: ctrlMotherName,
decoration: InputDecoration(
labelText: "Name of Mother",
border: OutlineInputBorder()
)
),
SizedBox(height: 10,),
Checkbox(
value: false,
onChanged: (bool val){
},
),
I can't able to check the checkbox. Same issue found when I use Radiobutton also.
You need to use a StatefulWidget since you're dealing with changing values. I've provided an example:
class MyAppOne extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyAppOne> {
bool _myBoolean = false;
#override
Widget build(BuildContext context) {
return Center(
child: Checkbox(
value: _myBoolean,
onChanged: (value) {
setState(() {
_myBoolean = value; // rebuilds with new value
});
},
),
);
}
}
One way you can achieve this is using the provider package. I tried to create the shortest possible app to show how you can use it. The neat part is that you get to keep your widget stateless.
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Home(),
);
}
}
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ChangeNotifierProvider(
create: (_) => CheckboxProvider(),
child: Consumer<CheckboxProvider>(
builder: (context, checkboxProvider, _) => Checkbox(
value: checkboxProvider.isChecked,
onChanged: (value) {
checkboxProvider.isChecked = value ?? true;
},
),
),
),
),
);
}
}
class CheckboxProvider with ChangeNotifier {
bool _isChecked = false;
bool get isChecked => _isChecked;
set isChecked(bool value) {
_isChecked = value;
notifyListeners();
}
}
It took me quite some time to understand the package but it is very useful and recommended if you want an easier way to manage state in your application. Here's a video from the Flutter team explaining how to use Provider. I would still recommend spending some time looking further into it.
P.S.: Don't forget to change the pubspec.yaml file.
think of flutter like javascript and pass the position as a parameter to the medCheckedChanged function in the list builder. when the dart parser evaluates the expression or lambda function it will invoke the method with the position parameter as a value.
class testWidget2 extends StatefulWidget {
testWidget2({Key key}) : super(key: key);
int numberLines = 50;
List<bool> checkBoxValues = [];
#override
_testWidget2State createState() => _testWidget2State();
}
class _testWidget2State extends State<testWidget2> {
_medCheckedChanged(bool value, int position) {
setState(() => widget.checkBoxValues[position] = value);
}
#override
void initState() {
// TODO: implement initState
super.initState();
int i = 0;
setState(() {
while (i < widget.numberLines) {
widget.checkBoxValues.add(false);
i++;
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: ListView.builder(
itemCount: widget.checkBoxValues.length,
itemBuilder: (context, position) {
return Container(
height: MediaQuery.of(context).size.width * .06,
width: MediaQuery.of(context).size.height * .14,
alignment: Alignment(0, 0),
child: Checkbox(
activeColor: Color(0xff06bbfb),
value: widget.checkBoxValues[position],
onChanged: (newValue) {
_medCheckedChanged(newValue, position);
}, //pass to medCheckedChanged() the position
),
);
})));
}
}
You can use StateProvider from the Riverpod package to achieve this.
final checkboxProvider = StateProvider<bool>((ref) => false);
class CheckboxWidget extends StatelessWidget {
const CheckboxWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
children: [
Consumer(
builder: (context, ref, _) {
return Checkbox(
value: ref.watch(checkboxProvider),
onChanged: (value) {
ref.read(checkboxProvider.state).state = value!;
},
);
}
),
Text('On'),
],
);
}
}
Related
I want to use bottomNavigationBar with listview, I tried each one of them separately and they work fine, but when I use them together, the bottomNavigationBar doesn't work, you can press the icons but nothing happens.
note: I'm using an older version of dart to avoid null-safety which is dumb, but the reason is the book I read is from 2019 so I couldn't follow without using an older version.
note 2: I'm very new to programming.
main.dart
//#dart=2.9
import 'package:flutter/material.dart';
import 'package:ch8_bottom_navigation/pages/home.dart';
void main() => runApp(Myapp());
class Myapp extends StatelessWidget {
//this widget is the root of the app
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Starter Template',
theme: ThemeData (
primarySwatch: Colors.blue,
platform: TargetPlatform.iOS,
),
home: Home(),
);
}
}
home.dart
//#dart=2.9
import 'package:flutter/material.dart';
import 'discover.dart';
import 'home2.dart';
import 'account.dart';
class Home extends StatefulWidget {
const Home({Key key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _currentIndex = 0;
List _listPages = [];
Widget _currentPage;
#override
void initState() {
super.initState();
_listPages
..add(Home2())
..add(Discover())
..add(Account());
_currentPage = Discover();
}
void _changePage(int selectedIndex) {
setState(() {
_currentIndex = selectedIndex;
_currentPage = _listPages[selectedIndex];
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView.builder(
itemCount:20 ,
itemBuilder: (BuildContext context , int index) {
if (index >= 0 && index <= 0) {
return Home2 (index:index);
}
else return null;
},
),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.live_tv),
label: ('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.explore_outlined),
label: ('Discover'),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_box_outlined),
label: ('Account'),
),
],
onTap: (selectedIndex) => _changePage(selectedIndex),
),
);
}
}
home2.dart
//#dart=2.9
import 'package:flutter/material.dart';
class Home2 extends StatelessWidget {
const Home2({Key key , #required this.index}) : super(key: key);
final int index;
#override
Widget build(BuildContext context) {
return Container(
child:Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
color: Colors.white70,
child: ListTile(
leading: Image(
image: AssetImage('assets/images/blackwidow.jpg'),
),
title: Text('Black Widow'),
subtitle: Text('By Disney'),
trailing: Icon(Icons.movie),
selected: true,
onTap: () {
print('Trapped on Row $index');
},
),
)
);
}
}
body: SafeArea(child: _currentPage),
or
body: SafeArea(child: _listPages[selectedIndex]),
Did you try this way?
I am working with flutter. I create a DropDown menu in the menu_list.dart file. I want to use the value selected from the user in (menu_list.dart file) in the add_screen.dart file. So, that I can upload it in the FireStore with other user information. The code is attached below.
I am glad if someone helps.
'add_Screen.dart'
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:database/widgets/menu_list.dart';
import 'package:flutter/material.dart';
class AddScreen extends StatelessWidget {
String? personname, personphone, vall;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add Data"),
),
body: Column(
children: [
Container(
child: MenuList(),
),
SizedBox(
height: 15,
),
Container(
child: TextFormField(
onChanged: (String name) {
getStudentName(name);
},
decoration: InputDecoration(
labelText: "Name",
focusedBorder: OutlineInputBorder(),
),
),
),
SizedBox(
height: 15,
),
Container(
child: TextFormField(
onChanged: (String phone) {
getStudentPhone(phone);
},
decoration: InputDecoration(
labelText: "PhoneNumber",
focusedBorder: OutlineInputBorder(),
),
),
),
SizedBox(
height: 15,
),
Container(
child: RaisedButton(
child: Text("Add"),
onPressed: createData,
),
),
],
),
);
}
createData() {
Future<void> documentReference = FirebaseFirestore.instance
.collection("Students")
.doc("subcollection")
.collection("collectionPath")
.doc()
.set(
{
"PersonName": personname,
"PersonPhone": personphone,
},
);
}
getStudentName(name) {
this.personname = name;
}
getStudentPhone(phone) {
this.personphone = phone;
}
}
`
----------------------------------------------------------------------------------------------
'menu_list.dart'
`
import 'package:flutter/material.dart';
class MenuList extends StatefulWidget {
const MenuList({Key? key}) : super(key: key);
#override
_MenuListState createState() => _MenuListState();
}
class _MenuListState extends State<MenuList> {
final items = ['Maths', 'Urdu', 'English', 'Simple'];
String? value;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: value,
isExpanded: true,
items: items.map(buildMenuItem).toList(),
onChanged: (value) => setState(
() => this.value = value,
),
);
}
}
DropdownMenuItem<String> buildMenuItem(String item) => DropdownMenuItem(
value: item,
child: Text(
item,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 30,
),
),
);
`
I think the best option for you, without overegineering the code, would be to pass a callback function that is received as parameter for the onChanged parameter of the DropdownButton.
It would look something like this:
In add_screen:
String _itemSelected;
MenuList(onChanged: (value) {
_itemSelected = value;
})
In menu_list:
class MenuList extends StatefulWidget {
final Function(String) onChanged;
const MenuList({required this.onChanged, Key? key}) : super(key: key);
#override
_MenuListState createState() => _MenuListState();
}
class _MenuListState extends State<MenuList> {
final items = ['Maths', 'Urdu', 'English', 'Simple'];
String? value;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: value,
isExpanded: true,
items: items.map(buildMenuItem).toList(),
onChanged: widget.onChanged
);
}
}
I apologize if the code doesn't compile directly since I'm not able to compile it at the time.
Feel free to reach me if you have any questions
class AddScreen extends StatefulWidget {
#override
_AddScreenState createState() => _AddScreenState();
}
class _AddScreenState extends State<AddScreen> {
// make stateful
String? personname, personphone, vall, dropdownValue;
// define value for dropdownValue
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add Data"),
),
body: Column(
children: [
Container(
child: MenuList(dropdownValue: dropdownValue),
// call MenuList as above passing dropdown value;
),
...
// other children
],
),
);
}
}
// menu_list.dart
import 'package:flutter/material.dart';
class MenuList extends StatefulWidget {
String dropdownValue;
// pass the value here
MenuList({Key? key, this.dropdownValue}) : super(key: key);
#override
_MenuListState createState() => _MenuListState();
}
class _MenuListState extends State<MenuList> {
final items = ['Maths', 'Urdu', 'English', 'Simple'];
// String? value;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: widget.dropdownValue,
// set the value here
isExpanded: true,
items: items.map(buildMenuItem).toList(),
onChanged: (value) => setState(
() => widget.dropdownValue = value,
// set the value here
),
);
}
}
In this code, I want to show indexed widgets by changing the index from the Navigation drawer i.e. The main MaterialApp shows widget according to the index(widgetIndex). The index is updated but the widget does not change until I hot reload it. So, I want it to reload the MyApp widget from the drawer widget.
main.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:indexed/page1.dart';
import 'package:indexed/page2.dart';
import 'drawer.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
//set widgetIndex(int widgetIndex) {widgetIndex = DrawerS.widgetIndex;}
int widgetIndex = SideDrawerState.widgetIndex;
#override
Widget build(BuildContext context)
{
return MaterialApp(
home: Container(
child: IndexedStack(
index: widgetIndex,
children: <Widget>[
Page1(), //A Scaffold wid.
Page2(), //A Scaffold wid.
],
),
),
);
}
}
drawer.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class SideDrawer extends StatefulWidget {
#override
SideDrawerState createState() => SideDrawerState();
}
class SideDrawerState extends State<SideDrawer> {
static int widgetIndex = 0;
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
ListTile(
contentPadding: EdgeInsets.only(top: 50),
title: Text('1'),
onTap: () async {
setState(() => widgetIndex = 0);
Navigator.of(context).pop();
},
),
ListTile(
title: Text('2'),
onTap: (){
setState(() => widgetIndex = 1);
Navigator.of(context).pop();
},
),
],
),
);
}
}
You can create a function field in your SideDrawer that takes an index as a parameter.
Call the function passing the appropriate parameter in the onTap of each ListTile.
In your MyApp create a variable with initial value of 0 then when setting the SideDrawer add the onTap attribute then change the value of the in the setState
Like this
class MyApp2 extends StatefulWidget {
#override
MyApp2State createState() => MyApp2State();
}
class MyApp2State extends State<MyApp2> {
var widgetIndex = 0;
#override
Widget build(BuildContext context)
{
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: SafeArea(
child: Container(
child: IndexedStack(
index: widgetIndex,
children: <Widget>[
Text("djdhjhd"),
Text("nonono")
],
),
),
),
drawer: SideDrawer(
onTap: (index){
setState(() {
widgetIndex = index;
});
},
),
);
}
}
class SideDrawer extends StatefulWidget {
final Function(int index) onTap;
SideDrawer({this.onTap});
#override
SideDrawerState createState() => SideDrawerState();
}
class SideDrawerState extends State<SideDrawer> {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
ListTile(
contentPadding: EdgeInsets.only(top: 50),
title: Text('1'),
onTap: () async {
widget.onTap(0);
Navigator.of(context).pop();
},
),
ListTile(
title: Text('2'),
onTap: (){
widget.onTap(1);
Navigator.of(context).pop();
},
),
],
),
);
}
}
The output:
I hope this helps you.
I am building an app and in it, I have the names of people in a list from which I could add/delete, etc.. The problem is this list is not saved when I close the app, which is inconvenient.
I heard you can use shared Preferences to save simple objects like this, without complicating things like using SQLite and json.
So I'd like to know what's the suggested way to persist this data and load it etc.
Thanks in Advance and have a great day :)
Here is the code:
import 'package:flutter/material.dart';
import 'package:zakif_yomi3/NewPerson.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.purple,
),
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> {
final List<String> people = [];
void _addNewPerson(String name) {
setState(() {
people.add(name);
});
}
void _startAddNewPerson(BuildContext ctx) {
showModalBottomSheet(
context: ctx,
builder: (_) {
return GestureDetector(
onTap: () {},
child: NewPerson(_addNewPerson),
behavior: HitTestBehavior.opaque,
);
},
);
}
void _deletePerson(int value ) {
setState(() {
people.removeAt(value);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
'People',
style: TextStyle(fontSize: 30),
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () => _startAddNewPerson(context),
)
],
),
body: ListView.builder(
itemCount: this.people.length,
itemBuilder: (context, value) {
return Card(
color: Colors.amberAccent[200],
elevation: 3,
child: Container(
child: ListTile(
leading: Text(value.toString()),
title: Text(
people[value],
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
_deletePerson(value);
},
),
),
),
);
},
),
);
}
}
And the NewPerson object:
import 'package:flutter/material.dart';
class NewPerson extends StatefulWidget {
final Function addTx;
NewPerson(this.addTx);
#override
_NewPersonState createState() => _NewPersonState();
}
class _NewPersonState extends State<NewPerson> {
final _nameController = TextEditingController();
void _submitData() {
final name = _nameController.text;
widget.addTx(
name
);
Navigator.of(context).pop();
}
#override
Widget build(BuildContext context) {
return Card(
elevation: 5,
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
TextField(
decoration: InputDecoration(labelText: 'Name'),
controller: _nameController,
onSubmitted: (_) => _submitData(),
),
RaisedButton(
child: Text('Add Person'),
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).textTheme.button.color,
onPressed: _submitData,
),
],
),
),
);
}
}
You could use this functions to persist and load data from shared preferences.
Get SharedPreferences from here.
To persist data to SharedPreferences, called after adding or deleting a new element to the list.
_persistData() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setStringList("persons", _people);
}
To load data from SharedPreferences, usually called in initState.
_loadData() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
_people = preferences.getStringList("persons");
});
}
I'm making an app that looks like an WhatsApp clone, it has 3 tabs which contain different ListViews and other Widgets. So, the first tab is a ListView that displays a list of all the chats of the user. I have the chat feature working correctly with firestore.
Child of the first TabBarView is a ListView which displays the thumbnails, names and last messages for all the users. The problem is even though the widget is loading data correctly from firestore. The ListView is blank for some reason. I'm sure that it has all the correct data. When I switch tabs though and switch back to the first tab the ListView shows chats just for a second then it disappears. I have no idea why this is happening, please Help!
Here is the ListView widget that displays chats:
import 'package:classroom_app/Services/app_state.dart';
import 'package:classroom_app/Services/app_events.dart';
import 'package:classroom_app/Widgets/classroom_app.dart';
import 'package:flutter/material.dart';
class ChatList extends StatefulWidget {
final String userId;
ChatList(#required this.userId);
#override
_ChatListState createState() => _ChatListState();
}
class _ChatListState extends State<ChatList> {
Widget buildRow(BuildContext context, ChatItem chat) {
return Row(
children: <Widget>[
Container(
height: 100.0,
width: 100.0,
child: ClipOval(
child: Image.network(
chat.photoUrl,
fit: BoxFit.cover,
),
),
padding: EdgeInsets.all(12.0),
),
Column(
children: <Widget>[
Text(
chat.userName,
style: TextStyle(fontSize: 15.0),
),
/*Text(chat.displayMessage,
style: TextStyle(fontSize: 8.0, color: Colors.grey)),*/
],
),
/*Text(
chat.unseenCount.toString(),
style: TextStyle(color: Colors.white, background: Paint()),
),*/
],
);
}
#override
void didUpdateWidget(Widget oldWidget) {
print(ClassroomApp.of(context).chat.currentState.listOfUserChats.toString());
super.didUpdateWidget(oldWidget);
}
#override
Widget build(BuildContext context) {
ClassroomApp.of(context).chat.dispatch(GetAllConversations(widget.userId));
return StreamBuilder(
stream: ClassroomApp.of(context).chat.state,
builder: (context, snapshot) {
if(snapshot.hasData) {
if(snapshot.data.listOfUserChats == [] || snapshot.data.listOfUserChats == null) {
return Center(child: Text('You don\'t have any chats. Try adding a Classmate.'),);
} else {
return ListView.builder(
itemBuilder: (context, index) => buildRow(context, snapshot.data.listOfUserChats[index]),
itemCount: snapshot.data.listOfUserChats.length,
);
}
} else {
return Center(child: CircularProgressIndicator(),);
}
},
);
}
}
And here is my homepage widget which contians the TabBarView.
import 'package:classroom_app/Services/app_state.dart';
import 'package:classroom_app/Widgets/chat_list.dart';
import 'package:classroom_app/Widgets/classroom_app.dart';
import 'package:classroom_app/Services/app_events.dart';
import 'package:flutter/material.dart';
enum UserOptions { AddClassmate, Settings, SignOut }
class HomePage extends StatefulWidget {
HomePage({Key key, #required this.title, #required this.userAuth})
: super(key: key);
final String title;
final AuthenticationState userAuth;
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
final List<Tab> appBarTabs = [
Tab(text: 'CHATS'),
Tab(text: 'LECTURES'),
Tab(text: 'DOUBTS'),
];
String _userName;
TabController _tabController;
TextEditingController _editingController;
#override
void initState() {
_tabController = TabController(vsync: this, length: appBarTabs.length);
_editingController = TextEditingController();
super.initState();
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(fontSize: 25, color: Colors.
bottom: TabBar(
labelColor: Colors.white,
controller: _tabController,
tabs: appBarTabs,
isScrollable: false,
),
),
body: TabBarView(
controller: _tabController,
children: <Widget>[
Container(
child: ChatList(widget.userAuth.user.uid),
),
Center(child: Text('This is lectures view.')),
Center(child: Text('This is doubts view.')),
],
),
);
}
}
I've added a GIF, to show the behaviour of ListView
I'm also adding code for the chatBloc component as well as the ClassroomApp InheritedWidget
class ChatBloc extends Bloc<ChatEvent, ChatState> {
final ChatService _chatService = ChatService();
#override
ChatState get initialState => ChatState(null, null);
#override
Stream<ChatState> mapEventToState(
ChatState currentState, ChatEvent event) async* {
if (event is StartConversation) {
_chatService.startNewConversation(event.senderId, event.recieverName);
yield ChatState(
await _chatService.getAllMessagesByUserId(event.senderId), null);
}
if (event is GetAllConversations) {
List<ChatItem> chatList =
await _chatService.getAllMessagesByUserId(event.userId);
yield ChatState(chatList, null);
}
}
}
ClassroomApp InheritedWidget:
import 'package:flutter/material.dart';
import 'package:classroom_app/Services/bloc_serviec.dart';
class ClassroomApp extends InheritedWidget {
final AuthBloc auth = AuthBloc();
final ChatBloc chat = ChatBloc();
ClassroomApp({Widget child}) : super(child: child);
#override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static ClassroomApp of(BuildContext context) =>
context.inheritFromWidgetOfExactType(ClassroomApp);
}