Prevent keyboard from appearing on Flutter - flutter

I made this very simple aplication but im having a problem with it.
On every action that i do (like deleting something) the keyboard opens automatically.
I want to avoid that, and open the keyboard only when i click on the text form field (line 178 on code).
How can i do that?
I know this is something very simple to make, i have tried some things using focusnode, trying to disable the autofocus, but i didnt could make it work the way i need.
import 'dart:convert';
import 'dart:ffi';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MaterialApp(
home: Pedidos(),
));
}
class Pedidos extends StatefulWidget {
#override
_PedidosState createState() => _PedidosState();
}
class _PedidosState extends State<Pedidos> with TickerProviderStateMixin {
TabController _tabController;
final _pecasController = TextEditingController();
List _pecasList = [];
var _firstPress = true;
#override
void initState() {
super.initState();
_tabController = new TabController(length: 3, vsync: this);
}
void _addPecas() {
if ((_pecasController.text.isEmpty) ||
((_pecasController.text.trimLeft() == ("")))) {
print("Campo Vazio");
} else {
setState(() {
Map<String, dynamic> newPeca = Map();
newPeca["title"] = _pecasController.text.trimLeft();
//newPeca["ok"] = false;
_pecasController.text = "";
_pecasList.add(newPeca);
// _saveData();
print(_pecasList);
});
}
}
void _enviar() {
if (_pecasList.length < 1) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Lista vazia"),
actions: <Widget>[
new FlatButton(
child: new Text("Fechar"),
onPressed: () {
Navigator.of(context).pop();
}),
]);
});
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Deseja enviar os itens?"),
actions: <Widget>[
new FlatButton(
child: new Text("Fechar"),
onPressed: () {
Navigator.of(context).pop();
}),
new FlatButton(
child: new Text("Enviar"),
onPressed: () async {
Map<String, String> headers = new Map<String, String>();
headers["Content-type"] = "application/json";
headers["Accept"] = "application/json";
//String str = '{"take":55, "skip":"0"}';
final resp = await http.post('http://172.16.14.109:5000/',
//body: str,
body: jsonEncode(_pecasList),
headers: headers);
if (resp.statusCode == 200) {
if (resp.body == "ok") {
setState(() {
print(_pecasList);
_pecasList.clear();
Navigator.of(context).pop();
});
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(
"Erro: entre em contato com o suporte."),
actions: <Widget>[
new FlatButton(
child: new Text("Fechar"),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pop();
}),
]);
});
}
}
})
],
);
},
);
}
}
void _apagarTudo() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Deseja limpar a lista?"),
actions: <Widget>[
new FlatButton(
child: new Text("Fechar"),
onPressed: () {
Navigator.of(context).pop();
}),
new FlatButton(
child: new Text("Limpar"),
onPressed: () {
setState(() {
_pecasList.clear();
Navigator.of(context).pop();
});
}),
]);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Solicitação de Peças",
style: TextStyle(fontWeight: FontWeight.bold),
),
centerTitle: true,
backgroundColor: Colors.green,
),
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Expanded(
flex: 8,
child: TextFormField(
controller: _pecasController,
keyboardType: TextInputType.text,
style: TextStyle(
color: Colors.black,
fontSize: 18,
),
decoration: InputDecoration(
hintText: ("Adicionar item"),
),
),
),
Padding(
padding: EdgeInsets.only(right: 15),
),
Expanded(
flex: 2,
child: RaisedButton(
child: Icon(Icons.add, color: Colors.amber),
color: Colors.green,
onPressed: _addPecas,
),
)
],
),
),
Divider(
height: 02.0,
),
Expanded(
child: ListView.builder(
itemCount: _pecasList.length,
itemBuilder: (context, index) {
return ListTile(
dense: true,
key:
Key(DateTime.now().millisecondsSinceEpoch.toString()),
title: Text(
_pecasList[index]["title"],
style: TextStyle(fontSize: 15.0),
),
trailing: Icon(
Icons.delete_forever,
color: Colors.redAccent,
),
onLongPress: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title:
new Text("Deseja remover o item da lista?"),
actions: <Widget>[
new FlatButton(
child: new Text("Fechar"),
onPressed: () {
Navigator.of(context).pop();
},
),
new FlatButton(
child: new Text("Excluir"),
onPressed: () {
_pecasList.removeAt(index);
setState(() {
Navigator.of(context).pop();
});
},
),
],
);
},
);
});
}),
),
Row(
mainAxisAlignment: (MainAxisAlignment.center),
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: RaisedButton(
color: Colors.green,
padding: EdgeInsets.all(5.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(4.0),
child: Icon(
Icons.send,
color: Colors.white,
),
),
Padding(
padding: const EdgeInsets.all(2.0),
child: Text(
"Enviar",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
],
),
onPressed: _enviar,
)),
Padding(
padding: const EdgeInsets.all(10.0),
child: RaisedButton(
color: Colors.redAccent,
padding: EdgeInsets.all(5.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(4.0),
child: Icon(
Icons.delete,
color: Colors.white,
),
),
Padding(
padding: const EdgeInsets.all(2.0),
child: Text(
"Limpar",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
],
),
onPressed: () {
_apagarTudo();
}))
],
)
],
),
);
}
}

Try these changes.
I have controlled enabled field of TextFormField. The TextFormField is disabled when you click on RaisedButton to add the item to list. And TextFormField is enabled when you click on itself.
void _addPecas() {
disableTextFormField();
...
}
bool textFormFieldEnabled = true;
void enableTextFormField(){
setState(() {
textFormFieldEnabled = true;
});
}
void disableTextFormField(){
setState(() {
textFormFieldEnabled = false;
});
}
Widget build(BuildContext context) {
....
child: TextFormField(
controller: _pecasController,
keyboardType: TextInputType.text,
enabled: textFormFieldEnabled,
onTap: () => enableTextFormField(),
style: TextStyle(
color: Colors.black,
fontSize: 18,
),
decoration: InputDecoration(
hintText: ("Adicionar item"),
),
),
...
}

Related

Why does ontap change all cards

I am still new to coding and still learning dart. I can't find a solution anywhere. please help. when I run my code, everything works fine but when i add multiple cards, when i tap one, they all change color and have a strikethrough. I am not sure where the problem is. Please can you help, here is my code:
#override
bool _enabled = true;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('To-Do List'),
centerTitle: true,
backgroundColor: Colors.grey[900],
),
body: ListView(children: _getItems()),
backgroundColor: Colors.grey[850],
floatingActionButton: Padding(
padding: const EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: () => _displayDialog(context),
tooltip: 'Add Item',
child: Icon(Icons.add),
backgroundColor: Colors.grey[900],
),
),
);
}
void _addTodoItem(String title) {
//Wrapping it inside a set state will notify
// the app that the state has changed
setState(() {
_todoList.add(title);
});
_textFieldController.clear();
}
final Map<String, bool> _enabledMap = Map<String, bool>();
Widget _buildTodoItem(String title) {
return Padding(
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: InkWell(
onTap: () => setState(() {
item.isTapped = !item.isTapped;
// _enabled = !_enabled;
// _color = Colors.grey;
}),
child: Container(
child: Container(
width: 50,
height: 75,
alignment: Alignment.center,
child: Text(
title,
style: TextStyle(decoration: _enabledMap[title] == true ? TextDecoration.lineThrough, color : null: Colors.grey[700]),
),
color: _color,
),
),
)
);
}
//Generate a single item widget
_displayDialog(BuildContext context) async {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Add a task to your List'),
content: TextField(
controller: _textFieldController,
decoration: const InputDecoration(hintText: 'Enter task here'),
),
actions: <Widget>[
FlatButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('ADD'),
onPressed: () {
Navigator.of(context).pop();
_addTodoItem(_textFieldController.text);
},
),
],
);
});
}
Your onTap method updates the _enabled variable in setState.
That variable is used for all the containers in their TextStyle widget.
In order to select one item, I suggest creating a map that'll store your "enabled" logic, and the key should be a unique String (the title).
Something like below: (not tested)
final Map<String, bool> _enabledMap = Map<String, bool>();
enter code here
Widget _buildTodoItem(String title) {
return Padding(
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: InkWell(
onTap: () => setState(() { if (_enabledMap[title] == null) {_enabledMap[title] = false;} _enabledMap[title] = !_enabledMap[title]; _color = Colors.grey;}),
child: Container(
width: 50,
height: 75,
alignment: Alignment.center,
child: Text(
title,
style: TextStyle(decoration: _enabledMap[title] == true ? TextDecoration.lineThrough, color: Colors.grey[700] : null),
),
color: _color,
),
),
)
);
class Details {
String title;
bool isTapped;
Details({this.title, this.isTapped});
}
class Testing2 extends StatefulWidget {
#override
_Testing2State createState() => _Testing2State();
}
class _Testing2State extends State<Testing2> {
#override
bool _enabled = true;
List<Details> _todoList = [];
List<Widget> lists = [];
TextEditingController _textFieldController = TextEditingController();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('To-Do List'),
centerTitle: true,
backgroundColor: Colors.grey[900],
),
body: _getItems(), //ListView(children: _getItems()),
backgroundColor: Colors.grey[850],
floatingActionButton: Padding(
padding: const EdgeInsets.all(8.0),
child: FloatingActionButton(
onPressed: () => _displayDialog(context),
tooltip: 'Add Item',
child: Icon(Icons.add),
backgroundColor: Colors.grey[900],
),
),
);
}
Widget _getItems() {
return Container(
child:_todoList.length>0? ListView.builder(
itemCount: _todoList.length,
itemBuilder: (context, index) {
return _buildTodoItem(_todoList[index]);
})
:Center(child: Text("It's Empty", style: TextStyle(color: Colors.white),),),
);
}
void _addTodoItem(String title) {
setState(() {
_todoList.add(Details(isTapped: false, title: title));
});
_textFieldController.clear();
}
Widget _buildTodoItem(Details item) {
return Padding(
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: InkWell(
onTap: () => setState(() {
item.isTapped = !item.isTapped;
}),
child: Container(
width: 50,
height: 75,
alignment: Alignment.center,
child: Text(
item.title,
style: TextStyle(
decoration:
item.isTapped ? null : TextDecoration.lineThrough,
color: Colors.grey[700]),
),
color: item.isTapped ? Colors.grey : null,
// _color
),
)));
}
//Generate a single item widget
_displayDialog(BuildContext context) async {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Add a task to your List'),
content: TextField(
controller: _textFieldController,
decoration: const InputDecoration(hintText: 'Enter task here'),
),
actions: <Widget>[
FlatButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('ADD'),
onPressed: () {
Navigator.of(context).pop();
_addTodoItem(_textFieldController.text);
},
),
],
);
});
}
}

Setstate() not working to update suffixIcon inside AlertDialog ? - Flutter

I'm trying to update the suffixIcon in Form for TextFormField's InputDecoration , to check the length of the giving String by onChange function ,but no update . In add I did test on Textcontroller to give it value when the length >= 8 it's worked ,I wish I give a good idea for the issue . thanks in advance for your solution .
import 'package:flutter/material.dart';
bulidDialogChangePass() {
return DialogPass();
}
class DialogPass extends StatefulWidget {
const DialogPass({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return DialogPassState();
}
}
class DialogPassState extends State<DialogPass> {
TextEditingController _fPasswordValue = TextEditingController();
TextEditingController _sPasswordValue = TextEditingController();
final _formKey = GlobalKey<FormState>();
ValueChanged<String>? onChanged;
bool _showIcons = false;
bool _startValidateFPass = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 25.0),
child: Wrap(
children: [
Container(
child: Row(
children: [
Text("Password :"),
TextButton(
onPressed: () {
_showDialog(context);
},
child: Wrap(
direction: Axis.vertical,
alignment: WrapAlignment.end,
children: [Text("Change")],
),
)
],
),
),
],
),
);
}
_showDialog(BuildContext context) async {
var size = MediaQuery.of(context).size;
return await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Stack(
clipBehavior: Clip.none,
children: <Widget>[
Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
controller: _fPasswordValue,
onChanged: (value) {_onChange(_fPasswordValue.text);},
decoration: InputDecoration(
labelText: "New Password",
suffixIcon: _showIcons && _startValidateFPass ? _setIcon() :null,
),
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
controller: _sPasswordValue,
decoration: InputDecoration(
labelText: "Confirm Password",
suffixIcon: _showIcons && _startValidateFPass ? _setIcon() :null, // I will change to check aothers soon
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Wrap(
children: [
OutlinedButton(
style: OutlinedButton.styleFrom(
fixedSize: Size(size.width / 2 - 10, 20),
padding: EdgeInsets.symmetric(horizontal: 50),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
),
onPressed: () {},
child: Text("CANCEL",
style: TextStyle(
fontSize: 14,
letterSpacing: 2.2,
color: Colors.black)),
),
OutlinedButton(
style: OutlinedButton.styleFrom(
fixedSize: Size(size.width / 2 - 10, 20),
backgroundColor: Colors.blue[400],
primary: Colors.black,
padding: EdgeInsets.symmetric(horizontal: 50),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
),
onPressed: () {},
child: Text("Save",
style: TextStyle(
fontSize: 14,
letterSpacing: 2.2,
color: Colors.black)),
),
],
),
),
],
),
),
],
),
);
});
}
_onChange(String value) {
setState(() {
_startValidateFPass = true;
if (value.length >= 8) {
_sPasswordValue.text = "test"; // test to check setState
_showIcons = true;
}
});
}
Icon _setIcon() {
Icon icon;
if(_showIcons){
_sPasswordValue.text = "test"; // test to check setState
print('dfsdfsd');
icon = Icon(
Icons.done_all,
color: Colors.green,
);
}else{
icon = Icon(
Icons.highlight_off,
color: Colors.red,
);
}
return icon;
}
}
Make another stateful widget and make Alertdialog as its child or use stateful builder to accomplish this as
showDialog(
context: context,
builder: (context) {
String contentText = "Your Dialog";
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text("Title"),
content: Text(contentText),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context),
child: Text("Cancel"),
),
TextButton(
onPressed: () {
setState(() {
contentText = "Changed state";
});
},
child: Text("Change"),
),
],
);
},
);
},
);

How to fix when BackdropScaffold frontLayer's elements doesn't appear?

Sorry for the bad title:(!
My app should show in the home screen cards and FloatingActionButton, I've created the cards in separate file, so I'm forwarding the data to it, also to store my data I'm using sqlite which I'm new to it..
the FloatingActionButton should appear when I run the application, and I need it to add new cards. I know that the database is empty now, but why the FloatingActionButton is not appearing?
when running it it looks like this.
I had followed a tutorial in the part when using the sqlite, and this is a part of my homeScreen code :
frontLayer: FutureBuilder<List<Reminder>>(
future: _reminders,
builder: (context, snapshot) {
if (snapshot.hasData) {
_currentReminders = snapshot.data!;
return ListView(children: [
...snapshot.data!.map<Widget>((reminder) {
return ReminderCard(
name: reminder.name, details: reminder.details);
}).followedBy([
Scaffold(
backgroundColor: Colors.amber,
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.black,
child: Icon(Icons.add),
onPressed: () {},
),
)
]).toList(),
Padding(
padding: const EdgeInsets.all(8.0),
),
Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.black,
child: Icon(Icons.add),
onPressed: () {}
this is the full code if I didn't paste the right part of my code: https://github.com/RarLasebai/reminder3/blob/main/lib/ui/Screens/homeScreen.dart
i have cloned your project and did a little changes on the HomeScreen
here is how u should do it
import 'package:flutter/material.dart';
import 'package:backdrop/backdrop.dart';
import 'package:untitled/helper.dart';
import 'package:untitled/models/reminder.dart';
import 'package:untitled/ui/widgets/ReminderCard.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
TextEditingController nameController = TextEditingController();
TextEditingController detailsController = TextEditingController();
final _formKey = GlobalKey<FormState>();
late ReminderCard card;
RHelper helper = RHelper();
late Future<List<Reminder>> _reminders;
late List<Reminder> _currentReminders;
//-------------------------Functions----------------
bool status = true;
#override
void initState() {
super.initState();
helper.initializeDatabase().then((value) => {print("------------donne?")});
_loadReminders();
}
void _loadReminders() {
_reminders = helper.getReminders();
if (mounted) setState(() {});
}
//Screen and appBar frontend
#override
Widget build(BuildContext context) {
return BackdropScaffold(
backgroundColor: Colors.white,
appBar: BackdropAppBar(
centerTitle: true,
title: (Text(
'قائمة التذكيرات',
style: Theme.of(context).textTheme.headline1,
)),
),
headerHeight: 110.0,
frontLayer: FutureBuilder<List<Reminder>>(
future: _reminders,
builder: (context, snapshot) {
if (snapshot.hasData) {
_currentReminders = snapshot.data!;
return ListView(children: [
Column(
children: _currentReminders.map<Widget>((reminder) {
return ReminderCard(
name: reminder.name, details: reminder.details);
}).toList(),
),
Padding(
padding: const EdgeInsets.all(8.0),
),
]);
}
return Center(child: Text("Loading>>.."));
},
),
backLayer: BackdropNavigationBackLayer(
items: [
ListTile(
leading: ImageIcon(AssetImage('icons/to-do-list.png')),
title: Align(
alignment: Alignment.centerRight,
child: Text("التذكيرات",
style: Theme.of(context).textTheme.bodyText2)),
onTap: () {
Navigator.of(context).pushReplacementNamed('home');
}),
Divider(),
ListTile(
leading: ImageIcon(AssetImage('icons/athkar.png')),
title: Align(
alignment: Alignment.centerRight,
child: Text("الأذكار",
style: Theme.of(context).textTheme.bodyText2)),
onTap: () {
Navigator.of(context).pushReplacementNamed('athkar');
}),
Divider(),
ListTile(
leading: ImageIcon(AssetImage('icons/mosque.png')),
title: Align(
alignment: Alignment.centerRight,
child: Text("مواقيت الصلاة",
style: Theme.of(context).textTheme.bodyText2)),
onTap: () {
Navigator.of(context).pushReplacementNamed('adhan');
},
),
Divider(),
ListTile(
leading: ImageIcon(AssetImage('icons/Tasbeeh.png')),
title: Align(
alignment: Alignment.centerRight,
child: Text("تسبيح",
style: Theme.of(context).textTheme.bodyText2)),
onTap: () {
Navigator.of(context).pushReplacementNamed('tasbeeh');
},
),
Divider(),
ListTile(
leading: ImageIcon(AssetImage('icons/quran.png')),
title: Align(
alignment: Alignment.centerRight,
child: Text("مصحف",
style: Theme.of(context).textTheme.bodyText2)),
onTap: () {
Navigator.of(context).pushReplacementNamed('moshaf');
},
),
Divider(),
ListTile(
leading: ImageIcon(AssetImage('icons/tadabur.png')),
title: Align(
alignment: Alignment.centerRight,
child: Text("وقفات تدبرية ",
style: Theme.of(context).textTheme.bodyText2)),
onTap: () {
Navigator.of(context).pushReplacementNamed('tadabur');
}),
Divider(),
ListTile(
leading: ImageIcon(AssetImage('icons/information.png')),
title: Align(
alignment: Alignment.centerRight,
child: Text("تواصل معنا",
style: Theme.of(context).textTheme.bodyText2)),
onTap: () {
Navigator.of(context).pushReplacementNamed('contact');
})
],
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
showModalBottomSheet(
useRootNavigator: true,
context: context,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(24),
),
),
builder: (context) {
return StatefulBuilder(
builder: (context, setModalState) {
return Container(
padding: const EdgeInsets.all(32),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
validator: (String? value) {
if (value!.isEmpty)
return 'Please enter name';
},
controller: detailsController,
style: TextStyle(
color: Colors.black, fontSize: 15.0),
decoration: InputDecoration(
errorStyle: TextStyle(
color: Colors.red, fontSize: 15.0),
labelText: 'اسم التذكير',
labelStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 15.0,
),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(5.0)),
),
),
SizedBox(
height: 10,
),
TextFormField(
controller: nameController,
style: TextStyle(
color: Colors.black, fontSize: 15.0),
decoration: InputDecoration(
labelText: 'التفاصيل',
labelStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 15.0,
),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(5.0)),
),
),
SizedBox(
height: 10,
),
ElevatedButton(
onPressed: () {
setState(() {
if (_formKey.currentState!
.validate()) {
_save();
Navigator.pop(context);
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text(
'تم حفظ التذكير')));
}
});
},
child: Text('حفظ'),
)
],
),
),
);
});
},
);
})
);
}
void _save() {
var _reminder = Reminder(
name: nameController.text, details: detailsController.text, save: 0);
helper.insertReminder(_reminder);
_loadReminders();
}
}
and for a athkar project i really suggest that you use provider or riverpod , or any kind of state management

Textfield returning null; bypassing await

Im making a counter app and want to be able to change the title of the appbar by taking input from the user using an popup input box.
I am trying to have the user input a name(string) in an AlertDialog with textfield in it and trying to recieve the string in the main page by defining a function for the popup which returns the inputted string when confirm button is pressed. I'm assigning a variable to this function using await in the onPressed() of the main page and then displaying the string variable change in a snackbar. however, the snackbar is appearing as soon i tap on the textfield without even submitting or hitting the confirm button. it looks like either the await isnt working or for some reason the Alertdialog's parent function is returning null as soon as I tap on the textfield.
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: CounterApp(),
));
class CounterApp extends StatefulWidget {
#override
_CounterAppState createState() => _CounterAppState();
}
class _CounterAppState extends State<CounterApp> {
int num = 0;
String name = 'MyCounter-1';
Future<String> changeName() async {
final _controller = TextEditingController();
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)
),
title: Text('Change counter name'),
content: TextField(
controller: _controller,
onSubmitted: (str) {
//Navigator.of(context).pop(str);
},
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop(_controller.text.toString());
},
child: Text(
'Confirm',
style: TextStyle(
fontSize: 18.0,
),
),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Cancel',
style: TextStyle(
fontSize: 18.0,
),
),
),
],
);
},
);
}
void snackBar(BuildContext context, String string) {
final snackbar = SnackBar(content: Text('Counter renamed to $string'),);
Scaffold.of(context).showSnackBar(snackbar);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(name),
centerTitle: true,
actions: <Widget>[
IconButton(
onPressed: () {
setState(() {
num = 0;
});
},
icon: Icon(
Icons.refresh,
size: 35.0,
),
),
Builder(
builder: (context) => IconButton(
onPressed: () async {
setState(() async {
name = await changeName();
snackBar(context, name);
});
},
icon: Icon(
Icons.edit,
size: 35.0,
),
),
),
],
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 2,
child: Container(
child: Center(child: Text(
'$num',
style: TextStyle(
fontSize: 75,
),
)),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 10),
child: RaisedButton(
onPressed: () {
setState(() {
num += 1;
});
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25.0)
),
color: Colors.blue,
child: Text(
'+',
style: TextStyle(
fontSize: 100.0,
),
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: RaisedButton(
onPressed: () {
setState(() {
num -= 1;
});
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25.0)
),
color: Colors.grey,
child: Text(
'-',
style: TextStyle(
fontSize: 100.0,
),
),
),
)
],
),
);
}
}
As Soon as I tap on the edit button, this happens:
Image of problem
Just Add await keyword before showDialog() and add return statement at last as shown in the below code.
Future<String> changeName() async {
final _controller = TextEditingController();
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
title: Text('Change counter name'),
content: TextField(
controller: _controller,
onSubmitted: (str) {
//Navigator.of(context).pop(str);
},
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop(_controller.text.toString());
},
child: Text(
'Confirm',
style: TextStyle(
fontSize: 18.0,
),
),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Cancel',
style: TextStyle(
fontSize: 18.0,
),
),
),
],
);
},
);
return _controller.text;
}

Need to change color of selected RadioListTile to green if user selects correct answer and red when wrong answer is selected

I am creating an multiple choice quiz app using flutter, currently when user selects an answer in radio list tile it, will check for correct answer and show a toast message.
Need to update the code to highlight selected answer with green color if answer is correct
and red if the answer is wrong.
If any idea please update the code and share the code. Thanks in advance.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mechanicalaptitude/quiz/models/category.dart';
import 'package:mechanicalaptitude/quiz/models/question.dart';
import 'package:mechanicalaptitude/quiz/ui/pages/quiz_finished.dart';
import 'package:html_unescape/html_unescape.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:admob_flutter/admob_flutter.dart';
class QuizPage extends StatefulWidget {
final List<Question> questions;
final Category category;
const QuizPage({Key key, #required this.questions, this.category})
: super(key: key);
#override
_QuizPageState createState() => _QuizPageState();
}
class _QuizPageState extends State<QuizPage> {
final TextStyle _questionStyle = TextStyle(
fontSize: 18.0, //font size of the questions
fontWeight: FontWeight.bold,
color: Colors.red);
int _currentIndex = 0;
int i = 0;
int hint_index = 0;
var option1;
final Map<int, dynamic> _answers = {};
final GlobalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
Question question = widget.questions[_currentIndex];
final List<dynamic> options = question.incorrectAnswers;
if (!options.contains(question.correctAnswer)) {
options.add(question.correctAnswer);
//options.shuffle();
}
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
key: _key,
appBar: AppBar(
title: Text("Question No. - " + "${_currentIndex + 1}"),
backgroundColor: Colors.indigoAccent,
elevation: 10,
),
body: Center(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.all(15.0),
children: <Widget>[
Center(
child: Card(
elevation: 0.0,
child: Container(
//padding: EdgeInsets.all(0.0),
width: double.infinity,
height: 900,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
//SizedBox(width: 10.0),
Expanded(
child: Text(
HtmlUnescape().convert(
widget.questions[_currentIndex].question),
softWrap: true,
textAlign: TextAlign.justify,
style: _questionStyle,
),
),
],
),
Row(
children: <Widget>[
//SizedBox(width: 10.0),
Expanded(
child: Image.network(
HtmlUnescape().convert(
widget.questions[_currentIndex].qimgurl),
// width: 300,
fit: BoxFit.fitWidth,
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes !=
null
? loadingProgress
.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
},
)),
],
),
//SizedBox(height: 0.0),
Card(
//elevation: 10.0,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
...options.map((option) => RadioListTile(
title: Text(
HtmlUnescape().convert("$option"),
style: TextStyle(color: Colors.black),
),
groupValue: _answers[_currentIndex],
value: option,
onChanged: (value) {
setState(() {
_answers[_currentIndex] = option;
if (i == 0) {
option1 = option;
}
if (option ==
widget.questions[_currentIndex]
.correctAnswer) {
i = 1;
Fluttertoast.cancel();
Fluttertoast.showToast(
msg: "Righ Answer",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Colors.green,
textColor: Colors.white,
fontSize: 16.0);
} else {
i = 1;
Fluttertoast.cancel();
Fluttertoast.showToast(
msg: "Wrong Answer",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
}
});
},
)),
],
),
),
Expanded(
child: Container(
alignment: Alignment.topCenter,
child: new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
/* const SizedBox(height: 30),*/
/* RaisedButton(
child: Text('Hint'),
onPressed:_giveHint,
color:Colors.yellow, ),*/
const SizedBox(),
ButtonTheme(
minWidth: 200,
height: 50,
child: RaisedButton(
child: Text(_currentIndex ==
(widget.questions.length - 1)
? "Submit"
: "Next"),
onPressed: _nextSubmit,
color: Colors.yellow,
),
),
],
),
),
)
],
),
),
),
),
],
),
),
),
);
}
void _nextSubmit() {
if (_answers[_currentIndex] == null) {
_key.currentState.showSnackBar(SnackBar(
content: Text("You must select an answer to continue."),
));
return;
}
if (_currentIndex < (widget.questions.length - 1)) {
_answers[_currentIndex] = option1;
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Answer is'),
content: Text(widget.questions[_currentIndex].correctAnswer),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
setState(() {
_currentIndex++;
i = 0;
});
},
),
],
);
});
} else {
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (_) => QuizFinishedPage(
questions: widget.questions, answers: _answers)));
}
}
Future<bool> _onWillPop() async {
return showDialog<bool>(
context: context,
builder: (_) {
return AlertDialog(
content: Text(
"Are you sure you want to quit the quiz? All your progress will be lost."),
title: Text("Warning!"),
actions: <Widget>[
FlatButton(
child: Text("Yes"),
onPressed: () {
Navigator.pop(context, true);
},
),
FlatButton(
child: Text("No"),
onPressed: () {
Navigator.pop(context, false);
},
),
],
);
});
}
}
There is an activeColor property in RadioListTile which lets you change color of the tile when it's selected.You can add a condition using ternary operator as follows to do the work for you:
activeColor: (option ==
widget.questions[_currentIndex]
.correctAnswer) ? Colors.green : Colors.red,
Complete Code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mechanicalaptitude/quiz/models/category.dart';
import 'package:mechanicalaptitude/quiz/models/question.dart';
import 'package:mechanicalaptitude/quiz/ui/pages/quiz_finished.dart';
import 'package:html_unescape/html_unescape.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:admob_flutter/admob_flutter.dart';
class QuizPage extends StatefulWidget {
final List<Question> questions;
final Category category;
const QuizPage({Key key, #required this.questions, this.category})
: super(key: key);
#override
_QuizPageState createState() => _QuizPageState();
}
class _QuizPageState extends State<QuizPage> {
final TextStyle _questionStyle = TextStyle(
fontSize: 18.0, //font size of the questions
fontWeight: FontWeight.bold,
color: Colors.red);
int _currentIndex = 0;
int i = 0;
int hint_index = 0;
var option1;
final Map<int, dynamic> _answers = {};
final GlobalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
Question question = widget.questions[_currentIndex];
final List<dynamic> options = question.incorrectAnswers;
if (!options.contains(question.correctAnswer)) {
options.add(question.correctAnswer);
//options.shuffle();
}
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
key: _key,
appBar: AppBar(
title: Text("Question No. - " + "${_currentIndex + 1}"),
backgroundColor: Colors.indigoAccent,
elevation: 10,
),
body: Center(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.all(15.0),
children: <Widget>[
Center(
child: Card(
elevation: 0.0,
child: Container(
//padding: EdgeInsets.all(0.0),
width: double.infinity,
height: 900,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
//SizedBox(width: 10.0),
Expanded(
child: Text(
HtmlUnescape().convert(
widget.questions[_currentIndex].question),
softWrap: true,
textAlign: TextAlign.justify,
style: _questionStyle,
),
),
],
),
Row(
children: <Widget>[
//SizedBox(width: 10.0),
Expanded(
child: Image.network(
HtmlUnescape().convert(
widget.questions[_currentIndex].qimgurl),
// width: 300,
fit: BoxFit.fitWidth,
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes !=
null
? loadingProgress
.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
},
)),
],
),
//SizedBox(height: 0.0),
Card(
//elevation: 10.0,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
...options.map((option) => RadioListTile(
title: Text(
HtmlUnescape().convert("$option"),
style: TextStyle(color: Colors.black),
),
activeColor: (option ==
widget.questions[_currentIndex]
.correctAnswer) ? Colors.green : Colors.red,
groupValue: _answers[_currentIndex],
value: option,
onChanged: (value) {
setState(() {
_answers[_currentIndex] = option;
if (i == 0) {
option1 = option;
}
if (option ==
widget.questions[_currentIndex]
.correctAnswer) {
i = 1;
Fluttertoast.cancel();
Fluttertoast.showToast(
msg: "Righ Answer",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Colors.green,
textColor: Colors.white,
fontSize: 16.0);
} else {
i = 1;
Fluttertoast.cancel();
Fluttertoast.showToast(
msg: "Wrong Answer",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
}
});
},
)),
],
),
),
Expanded(
child: Container(
alignment: Alignment.topCenter,
child: new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
/* const SizedBox(height: 30),*/
/* RaisedButton(
child: Text('Hint'),
onPressed:_giveHint,
color:Colors.yellow, ),*/
const SizedBox(),
ButtonTheme(
minWidth: 200,
height: 50,
child: RaisedButton(
child: Text(_currentIndex ==
(widget.questions.length - 1)
? "Submit"
: "Next"),
onPressed: _nextSubmit,
color: Colors.yellow,
),
),
],
),
),
)
],
),
),
),
),
],
),
),
),
);
}
void _nextSubmit() {
if (_answers[_currentIndex] == null) {
_key.currentState.showSnackBar(SnackBar(
content: Text("You must select an answer to continue."),
));
return;
}
if (_currentIndex < (widget.questions.length - 1)) {
_answers[_currentIndex] = option1;
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Answer is'),
content: Text(widget.questions[_currentIndex].correctAnswer),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
setState(() {
_currentIndex++;
i = 0;
});
},
),
],
);
});
} else {
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (_) => QuizFinishedPage(
questions: widget.questions, answers: _answers)));
}
}
Future<bool> _onWillPop() async {
return showDialog<bool>(
context: context,
builder: (_) {
return AlertDialog(
content: Text(
"Are you sure you want to quit the quiz? All your progress will be lost."),
title: Text("Warning!"),
actions: <Widget>[
FlatButton(
child: Text("Yes"),
onPressed: () {
Navigator.pop(context, true);
},
),
FlatButton(
child: Text("No"),
onPressed: () {
Navigator.pop(context, false);
},
),
],
);
});
}
}