I've tried to populate the dropdown menu button with the data from the SQLite database.
Then on the onTap Function I wanted to navigate to the selected category.
When I tap on the category it does not navigate.
I have saved each category with an id in the database which is used the identify the selected item.
Here is the code:
'''
class _HomeState extends State<Home> {
TodoService _todoService;
var _selectedValue;
var _categories = List<DropdownMenuItem>();
List<Todo>_todoList=List<Todo>();
#override
initState(){
super.initState();
_loadCategories();
}
_loadCategories() async {
var _categoryService = CategoryService();
var categories = await _categoryService.readCategory();
categories.forEach((category) {
setState(() {
_categories.add(DropdownMenuItem(
child: Text(category['name']),
value: category['name'],
onTap: ()=>Navigator.of(context).push(MaterialPageRoute(builder:(context)=>TodosByCategory(category: category['name'],))),
));
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _globalKey,
appBar: AppBar(
actions: <Widget>[
DropdownButtonHideUnderline(
child: DropdownButton(
value: _selectedValue,
items: _categories,
dropdownColor: Colors.blue,
style: TextStyle(color: Colors.white,fontSize: 16.0),
iconDisabledColor: Colors.white,
iconEnabledColor: Colors.white,
onChanged: (value) {
setState(() {
_selectedValue = value;
});
},
),
),
'''
Here is the todosByCategory():
'''
class _TodosByCategoryState extends State<TodosByCategory> {
List<Todo>_todoList=List<Todo>();
TodoService _todoService=TodoService();
#override
initState(){
super.initState();
getTodosByCategories();
}
getTodosByCategories()async{
var todos=await _todoService.readTodoByCategory(this.widget.category);
todos.forEach((todo){
setState(() {
var model= Todo();
model.title=todo['title'];
model.dueDate=todo['dueDate'];
_todoList.add(model);
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Todos By Category'),
),
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: _todoList.length,
itemBuilder: (context, index){
return Padding(
padding: EdgeInsets.only(top:8.0, left: 8.0, right: 8.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
elevation: 8.0,
child: ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(_todoList[index].title)
],
),
subtitle: Text(_todoList[index].dueDate),
// trailing: Text(_todoList[index].dueDate),
),
),
);
},),
)
],
),
);
}
}
'''
Please help me out.
Instead of writing the navigation code inside onTap of DropdownMenuItem, you can write it inside onChanged of DropdownButton where you are also getting the category name string as the value. It should work then.
Related
I am a beginner in Flutter. I am trying to add a new list item widget to screen when floating action button is pressed. How do I achieve this?
I am trying to create a list of items. When the floating action button is clicked, a dialog box is prompted and user is asked to enter details. I want to add a new list item with these user input details.
This is my input_page.dart file which I am calling in main.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class MedPage extends StatefulWidget {
#override
_MedPageState createState()=> _MedPageState();
}
class _MedPageState extends State<MedPage> {
Future<String>createAlertDialog(BuildContext context) async{
TextEditingController customController= new TextEditingController();
return await showDialog(context: context,builder: (context) {
return AlertDialog(
title: Text("Name of the Pill"),
content: TextField(
controller: customController,
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("OK"),
onPressed: (){
Navigator.of(context).pop(customController.text.toString()); // to go back to screen after submitting
}
)
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My med app'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget> [
Expanded(
child: ListView(
padding: const EdgeInsets.all(8),
children: <Widget>[
ReusableListItem(Color(0xFFd2fddf),"Name 1"),
ReusableListItem(Colors.orange,"Name 2"),
ReusableListItem(Color(0xFF57a1ab), "Name 3"),
],
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){
print("Clicked");
createAlertDialog(context).then((onValue){
print(onValue);
setState(() {
});
});
},
child: Icon(Icons.add),
),
);
}
}
class ReusableListItem extends StatelessWidget {
ReusableListItem(this.colour,this.pill);
Color colour;
String pill;
#override
Widget build(BuildContext context) {
return Container(
height: 50,
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(15.0)
),
child: Center(
child: Text(pill)
),
);
}
}
You don't need to change much in your code, maintain a variable that stores the values entered to be able to show them in the list. You should use Listview.builder() in order to dynamically render the items.
Here's your code:
class MedPage extends StatefulWidget {
#override
_MedPageState createState() => _MedPageState();
}
class _MedPageState extends State<MedPage> {
List<String> items = [];
Future<String> createAlertDialog(BuildContext context) async {
TextEditingController customController = new TextEditingController();
return await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Name of the Pill"),
content: TextField(
controller: customController,
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("OK"),
onPressed: () {
Navigator.of(context).pop(customController.text
.toString()); // to go back to screen after submitting
})
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My med app'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
return ReusableListItem(Color(0xFFd2fddf), items[index]);
},
itemCount: items.length,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
print("Clicked");
createAlertDialog(context).then((onValue) {
// print(onValue);
setState(() {
items.add(onValue);
});
});
},
child: Icon(Icons.add),
),
);
}
}
class ReusableListItem extends StatelessWidget {
ReusableListItem(this.colour, this.pill);
final Color colour;
final String pill;
#override
Widget build(BuildContext context) {
return Container(
height: 50,
margin: const EdgeInsets.all(8),
decoration:
BoxDecoration(color: colour, borderRadius: BorderRadius.circular(15.0)),
child: Center(child: Text(pill)),
);
}
}
Firstly you need to use ListView.builder() rather than ListView because you have dynamic content. Also you need to hold your items in a list.
// create a list before
ListView.builder(
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return Text(list[index]);
}
)
When you click on FloatingActionButton() you will call AlertDialog() method.
FloatingActionButton(
onPressed: (){
AlertDialog(
content: Form(), // create your form here
actions: [
// add a button here
]
)
})
This method will show a dialog(you will add a form inside of the dialog). When the user completes the form(after clicking the button) you will add a new object to the list and update the state with setState({})
onPressed: (){
setState({
// add new object to the list here
});
Navigator.pop(context); // this will close the dialog
}
I've created a button that allows the user to add a credit card, the cards are being added to a Listview.builder.
The problem is that when I have multiple cards and I select one, it selects all of them, it's probably a state problems but I didn't find (yet) how to fix it, here is the dartpad : [dartpad][1] of my code if you can check it and maybe show me what I'm doing wrong, it's probably failing inside the buildBody but I'm not really sure and I have not successfully found a solution yet.
You simply have to tap two times on 'Add a card' and you will see when checking one of them, both will get selected.
For some reason the link isnt working through the shortcut so here it is https://dartpad.dev/b0aaaa2901aa3ac67426d9bdd885abb1:
I modified your dartpad code to get the behaviour you are trying to achive:
The code is provided below:
The issue was that you are using the same bool value _isSelected for the two Checkboxes.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: InformationsBancairesPage(),
),
),
);
}
}
class InformationsBancairesPage extends StatefulWidget {
#override
_InformationsBancairesPageState createState() =>
_InformationsBancairesPageState();
}
class _InformationsBancairesPageState extends State<InformationsBancairesPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(
'Payer ou recevoir un paiement'.toUpperCase(),
style: TextStyle(fontSize: 19, color: Colors.black),
),
centerTitle: true,
backgroundColor: Colors.white,
iconTheme: IconThemeData(color: Colors.black),
),
body: Padding(
padding: const EdgeInsets.all(15.0),
child: ListView(
children: <Widget>[
InputAddCarte(),
],
),
),
);
}
}
class InputAddCarte extends StatefulWidget {
#override
_InputAddCarteState createState() => _InputAddCarteState();
}
class _InputAddCarteState extends State<InputAddCarte> {
// create a list of bool values for your checkboxes
List<bool> _selectedList = [false, false];
int value = 0;
void initState() {
super.initState();
}
_addCard() {
setState(() {
value = value + 1;
print(value);
});
}
Widget buildBody(BuildContext context, int indexClicked) {
return LabeledCheckbox(
label: 'Card credit',
padding: const EdgeInsets.symmetric(horizontal: 20.0),
// pass the value of the checkbox at the selected index
value: _selectedList[indexClicked],
onChanged: (bool newValue) {
setState(() {
// pass the value of the checkbox at the selected index
_selectedList[indexClicked] = newValue;
});
},
);
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ButtonTheme(
minWidth: 250,
child: RaisedButton(
color: Color(0xff00cc99),
child: Text(
'ADD A CARD'.toUpperCase(),
style: TextStyle(color: Colors.white, fontSize: 18),
),
onPressed: _addCard,
),
),
// Show the cards when you press 'Ajouter une carte'
ListView.builder(
shrinkWrap: true,
itemCount: this.value,
itemBuilder: (BuildContext context, int value) {
// display two cards maximum
if (value < 2) {
// pass the index of the selected checkbox
return buildBody(context, value);
}
return Container();
},
),
ButtonTheme(
minWidth: 250,
child: RaisedButton(
color: Colors.orange,
child: Text(
'Delete a card'.toUpperCase(),
style: TextStyle(color: Colors.white, fontSize: 18),
),
onPressed: () {},
),
)
],
);
}
}
// Create custom checkbox for the list of cards
class LabeledCheckbox extends StatelessWidget {
const LabeledCheckbox({
this.label,
this.padding,
this.value,
this.onChanged,
});
final String label;
final EdgeInsets padding;
final bool value;
final Function onChanged;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
onChanged(!value);
},
child: Padding(
padding: padding,
child: Row(
children: <Widget>[
Expanded(child: Text(label)),
Checkbox(
value: value,
onChanged: (bool newValue) {
onChanged(newValue);
},
),
],
),
),
);
}
}
I have designed a news application in flutter where I have an app bar with tabs following it. In the tabbarview I have a list of news. on click of the news, it will show details description and image of the news(as shown in the image). When I try to put the app bar in that file. Two app bar appears. What would the possible way sort it out?
Here is the code:
appBar: AppBar(
title: Text(""),
backgroundColor: Color(0xFF125688), //#125688 //FFFF1744
actions: <Widget>[
Container(
alignment: Alignment.topRight,
child: FlatButton(
onPressed: () {},
padding: EdgeInsets.fromLTRB(0, 10.0, 8.0, 0),
child: Text(
date,
style: TextStyle(
color: Colors.white,
),
)),
)
],
bottom: TabBar(
tabs: <Widget>[
Tab(text: "TOP-HEADLINES"),
Tab(text: "LATEST-NEWS"),
Tab(text: "SPORTS"),
Tab(text: "CRIME-NEWS"),
],
isScrollable: true,
),
),
body: TabBarView(children: [
TopHeadlines(),
LatestNews(),
Sports(),
CrimeNews(),
],
),
CODE FOR TOPHEADLINES()
class TopHeadlines extends StatefulWidget {
int index;
String value_image,value_description,value_title;
TopHeadlines({Key key,this.value_image,this.value_description,this.value_title,this.index}) : super(key:key);
#override
_topHeadlines createState() => _topHeadlines();
}
class _topHeadlines extends State<TopHeadlines> {
List<News> dataList = List();
bool _isLoading = false;
BuildContext context1;
Future<String> loadFromAssets() async {
DateTime oops = DateTime.now();
String d_date = DateFormat('ddMMyyyy').format(oops);
var url = 'https://www.example.com/json-12.json';
print(url);
var response = await http
.get('$url', headers: {"charset": "utf-8", "Accept-Charset": "utf-8"});
String utfDecode = utf8.decode(response.bodyBytes);
return utfDecode;
}
Future loadyourData() async {
setState(() {
_isLoading = true;
});
String jsonString = await loadFromAssets();
String newStr = jsonString.substring(1, jsonString.length - 1);
print(newStr);
Map newStringMap = json.decode(newStr);
var list = new List();
newStringMap.forEach((key, value) {
list.add(value);
});
for (var newsList in list) {
var news = News.fromJson(newsList);
dataList.add(news);
}
print('This is the length' + dataList.length.toString());
print(dataList[0].title);
setState(() {
_isLoading = false;
});
}
#override
void initState() {
super.initState();
loadyourData();
}
#override
Widget build(BuildContext context) {
DateTime oops = DateTime.now();
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Container(
child: _isLoading ? Center(
child: CircularProgressIndicator(),) :
ListView.builder(
itemCount: dataList.length, itemBuilder: (context, index) {
return SizedBox(
height: 130.0,
child: Card(
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
InkWell(
onTap: (){
// dataList;
Navigator.push(context, MaterialPageRoute(builder: (context) {
print(index);
return Newsdetail(value_image: dataList[index].image,value_description: dataList[index].description,value_title: dataList[index].title, );
}));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Expanded(
child: Image.network(
dataList[index].image,
height: 92.5,
width: 75.0,
)),
Expanded(
child: Text(
dataList[index].title,
style: TextStyle(
//title
fontSize: 15.0, color: Colors.grey,
),
),
)
],
),
),
),
],
),
),
);
},
),
));
}
}
Remove the appBars from these views:
TopHeadlines(),
LatestNews(),
Sports(),
CrimeNews(),
Only return the Content you want to display by return a Container or the widget you want to display
I am trying to create a checkbox inside my view. I declared bool variable isChecked= false in my state class, and while writing constructor for checkbox getting the error on my isChecked variable as 'Only static members can be accessed in intializers'. I made the variable as static, which removed the error on bool variable, but giving the same error on setState(). How do i resolve this ?
import 'package:flutter/material.dart';
class CardScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Card Screen',
home: new myPetScreen()
);
}
}
class myPetScreen extends StatefulWidget{
myPetScreen({Key key, this.title}) : super(key: key);
final String title;
#override
_myPetScreenState createState() => new _myPetScreenState();
}
class _myPetScreenState extends State<myPetScreen>{
static bool isChecked = false;
final view = new Column(
children: <Widget>[
//did other UI Implementation here
Container(
child: Flexible(
child: ListView.builder(itemBuilder: (context, position){
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Text(position.toString(), style: TextStyle(fontSize: 14.0, color: Colors.black),),
Spacer(),
Checkbox(
value: isChecked,
onChanged: (value) {
setState(() {
isChecked = value;
});
},
),
],
),
)
);
}
),
),
) ,
],
);
#override Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Card Screen')),
body: view,
);
}
}
make some change take your column code into one method then that method called into widget..
like this way..
Column getView(){
var view = new Column(
children: <Widget>[
//did other UI Implementation here
Container(
child: Flexible(
child: ListView.builder(itemBuilder: (context, position) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Text(
position.toString(),
style: TextStyle(fontSize: 14.0, color: Colors.black),
),
Spacer(),
Checkbox(
value: isChecked,
onChanged: (value) {
changeState(value);
},
),
],
),
));
}),
),
),
],
);
return view;
}
after that called this way..
body: getView()
You are declaring view as a final variable, so it is immutable. change it to a function like so:
Widget get view => Container(
//...
)
Also, don't forget to remove static from the state declaration (Never do that in a stateful wiget).
Here is my code
import 'package:flutter/material.dart';
void main() => runApp(TodoList());
class TodoList extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _TodoListState();
}
}
var TaskTextField;
List taskTextList = [];
var TaskIsImportant = false;
class _TodoListState extends State<TodoList> {
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: "To-Do List V2",
home: Scaffold(
appBar: AppBar(
title: Text("To-Do List V2"),
),
body: Flex(
direction: Axis.vertical,
children: <Widget>[
Flexible(
fit: FlexFit.tight,
child: Column(children: <Widget>[
Container(
child: TextField(
decoration: InputDecoration(
hintText: "Enter title of task to be added"),
onChanged: (taskTextField) {
setState(() {
TaskTextField = taskTextField;
print(TaskTextField);
});
},
),
margin: EdgeInsets.all(16.0),
),
CheckboxListTile(
title: Text("Important"),
activeColor: Colors.blue,
value: TaskIsImportant,
onChanged: (val) {
setState(() {
TaskIsImportant = !TaskIsImportant;
print(TaskIsImportant);
});
},
),
Text(
"Tip: Tap on your task to remove it",
style: TextStyle(fontSize: 15.0),
),
Container(
margin: EdgeInsetsDirectional.fromSTEB(117, 10, 117, 5),
child: Row(
children: <Widget>[
RaisedButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
if (TaskIsImportant) {
taskTextList.add("❗️$TaskTextField");
//taskTitleList.add(TaskDetailField);
} else {
taskTextList.add(TaskTextField);
//taskTitleList.add(TaskDetailField);
}
});
},
),
RaisedButton(
child: Icon(Icons.done_all),
onPressed: () {
setState(() {
taskTextList = [];
});
},
),
],
),
),
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
var title = taskTextList[index];
padding:
EdgeInsets.all(16.0);
return Dismissible(
key: Key(title[index]),
onDismissed: (direction) {
setState(() {
taskTextList.remove(title);
});
},
child: ListTile(
title: Text(
title,
style: TextStyle(fontSize: 20.0),
),
),
);
},
itemCount: taskTextList.length,
),
)
]),
),
],
)));
}
}
When I create four listTiles in the emulator, two errors are given as follows
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following RangeError was thrown building:
flutter: RangeError (index): Invalid value: Not in range 0..3, inclusive: 4
I hope someone can tell me what is wrong with my code. I am running on flutter version 1.3.10. Thanks in advance.
Also to the person that needs more code, here is the full code of main.dart. Hope this will help you find my errors
You are using title[index] but saving the value in title as title = taskTextList[index] which is not an array. So, you are getting range error.