I'm getting an abnormal effect in Flutter and I'm not sure if it's an error in my code or with flutter.
I'm trying to create a FormField object that is a checkbox that can have three values: empty, checked positive, or checked negative. Here is my code so far:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Checkbox Test',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Form(child: MyHomePage(title: 'Checkbox Test')),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> _savedList = [];
#override
Widget build(BuildContext context) {
ThemeData themeData = Theme.of(context);
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new CheckboxFormField(
title: "Option 1",
saved: _savedList,
themeData: themeData,
),
new CheckboxFormField(
title: "Option 2",
saved: _savedList,
themeData: themeData,
),
new CheckboxFormField(
title: "Option 3",
saved: _savedList,
themeData: themeData,
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: () {Form.of(context).reset();},
tooltip: 'Reset',
child: new Icon(Icons.refresh),
),
);
}
}
class CheckboxFormField extends FormField<dynamic> {
CheckboxFormField({
Key key,
bool checkState,
bool initialValue = false,
Color activeColor,
String title,
List<String> saved,
ThemeData themeData,
}) : super(
key: key,
initialValue: initialValue,
builder: (FormFieldState<dynamic> field) {
void onChange() {
if (field.value == false) {
activeColor = Colors.green;
print(activeColor);
checkState = true;
field.didChange(true);
saved.add(title);
print(saved);
} else if (field.value == true) {
activeColor = Colors.red;
print(activeColor);
checkState = null;
field.didChange(null);
saved.remove(title);
saved.add("Not " + title);
print(saved);
} else {
activeColor = themeData.textTheme.subhead.color;
checkState = false;
field.didChange(false);
saved.remove("Not " + title);
print(saved);
}
}
return Checkbox(
tristate: true,
value: field.value,
activeColor: activeColor,
onChanged: (value) => onChange());
});
}
Now this works fine when the app is first started, and does exactly what's expected, with each click cycling through the appropriate color and adding the appropriate value to the list.
The problem arises if the Form is reset: function-wise it remains working normally, but the color changing stops working. The checkbox reverts to the theme's base togglableActiveColor, so despite my function's rotation still being preserved with empty box -> positive check -> negative check -> repeat, the checkbox color becomes togglableActiveColor when it is set to true or null, and unselectedWidgetColor when it is false.
I know the code is still working as the checkbox changes appropriately, and the saved list continues to be appended and removed from appropriately, just the color stops behaving. Is this a glitch in the engine or am I missing something in my code?
Thanks
Bry
EDIT: Continuing to look into it further it seems that on the rebuild by Form.of(context).reset the activeColor property somehow gets lost, while everything else is preserved. Maybe this is by design, any ideas?
Related
I am creating an order application for a cafe and on this I have a list of the cafes items outside of the main class as its own file that I created using maps and in the main dart I have already called to the map class outside of the file and put it into a listview builder however I want there to be dropdowns too within the main page. I want the listviewer and the dropdownbuttons to be connected but I don't know if I can use the maps within the dropdown or do I have to turn them into lists and what not. Also if we can used maps within the dropdownbuttons how do we define it as an "items" if the dropdownbutton.
here is my map file
class Menu {
Menu();
Menu.s(this._sandwichMap);
Menu.b(this._burgerMap);
Menu.o(this._otherItemsMap);
Menu.q(this._sidesMap);
Menu.p(this._pizzaMap);
Map<String, double> _sandwichMap = {
"Veggie Melt": 4.50,
"Crispy Chicken Wrap": 6.95,
"Italian Meatball Sub": 6.99,
"Chicken Parm Grinder": 6.59,
"Grill Cheese": 3.59,
"Grilled Ham & Cheese": 4.59,
"Bacon Bagel Melt": 5.29};
Map<String, double> getSandwichMap() {
return this._sandwichMap;
}
//check burger prices again
Map<String, double> _burgerMap = {
"Veggie Burger": 4.99,
"The Quantum Burger": 7.25,
"Cafe Melt": 6.59,
"The Bull Rider": 5.79,
"Double Cheese Burger": 5.89,
"Hamburger": 3.99};
Map<String, double> getBurgerMap() {
return this._burgerMap;
}
Map<String, double> _otherItemsMap = {
"Chicken Quesadilla": 6.79,
"Cheese Quesadilla": 6.29,
"Chicken Strips": 4.99,
"Popcorn Chicken": 4.59,
"Jalapeno Poppers": 3.49};
Map<String, double> getOtherItemsMap() {
return this._otherItemsMap;
}
Map<String, double> _sidesMap = {
"French Fries": 3.29,
"Onion Rings": 4.79,
"Jalapeno Cheese Curds": 4.99,
"Tater Tots": 3.19,
"Pretzel Bites": 4.59,
"Nachos & Cheese": 3.50};
Map<String, double> getSidesMap() {
return this._sidesMap;
}
Map<String, double> _pizzaMap = {
"7-inch Cheese": 4.59,
"7-inc with topping": 4.99};
Map<String, double> getPizzaMap() {
return this._pizzaMap;
}
}
And here is my main file with the dropdowns
import 'dart:core';
import 'package:flutter/material.dart';
//import 'package:flutter/foundation.dart';
import 'package:flutter/cupertino.dart';
import 'maps.dart';
//var menu = Menu();
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
//Always use Stateless first then use stateful or stateless widgets afterward
#override
Widget build(BuildContext context) {
return MaterialApp(
//only used at the beginning of the program
title: 'The Cafe',
//just a title to the app it does not show for there is nothing telling it to show on the screen
debugShowCheckedModeBanner: false,
//takes out the ribbon at the top right corner of the screen and app
theme: ThemeData(
primarySwatch: Colors.green,
brightness: Brightness.dark,
fontFamily: 'georgia',
textTheme: TextTheme(headline1: TextStyle(fontSize: 100))
//controls the color of the very top part of the application
),
home: StartPage(),
//used to connect the Stateless widget to the Stateful widget below
);
}
}
class StartPage extends StatefulWidget {
#override
_StartPageState createState() => _StartPageState();
}
// do not forget the } prior to this comment if you do it will result in error and the program does not known why either
class _StartPageState extends State<StartPage> {
var menu = Menu();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('The Campus Cafe'),
//where the main title is computed to be shown on the screen
centerTitle: true,
//centers the title
),
body: Center(
//This is Header that is after the main Title
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
//Header Container
Expanded(
child: Image.asset(
'assets/images/campus-cafe-logo-350sidebar.png',)
),
Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.center,
child: Text("Our Menu", style: TextStyle(fontSize: 30),
),
),
Expanded(
child: ListView.builder(
itemCount: 5,
itemBuilder: (context, int index) {
String key = menu.getSandwichMap().keys.elementAt(index);
List<String> key1 = menu.getSandwichMap().keys.toList();
//List<double> key2 = menu.getSandwichMap().values.toList();
return DropdownButton(
value: key[index],
items: key,
onChanged: (value) {
key = value;
setState(() {});
},
hint: Text('Sandwich'),
);
return DropdownButton(items: [],
);
}),
),
]
),
),
);
}
}
If more information is needed on how I want my dropdowns too look I want them too look like the file below with just the listview.builder but I want that information to be within a dropdown if possible
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/cupertino.dart';
import 'maps.dart';
//var menu = Menu();
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
//Always use Stateless first then use stateful or stateless widgets afterward
#override
Widget build(BuildContext context) {
return MaterialApp(
//only used at the beginning of the program
title: 'The Cafe',
//just a title to the app it does not show for there is nothing telling it to show on the screen
debugShowCheckedModeBanner: false,
//takes out the ribbon at the top right corner of the screen and app
theme: ThemeData(
primarySwatch: Colors.green,
brightness: Brightness.dark,
fontFamily: 'georgia',
textTheme: TextTheme(headline1: TextStyle(fontSize: 100))
//controls the color of the very top part of the application
),
home: StartPage(),
//used to connect the Stateless widget to the Stateful widget below
);
}
}
class StartPage extends StatefulWidget {
#override
_StartPageState createState() => _StartPageState();
}
// do not forget the } prior to this comment if you do it will result in error and the program does not known why either
class _StartPageState extends State<StartPage> {
var menu = Menu();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('The Campus Cafe'),
//where the main title is computed to be shown on the screen
centerTitle: true,
//centers the title
),
body: Center(
//This is Header that is after the main Title
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
//Header Container
Expanded(
child: Image.asset(
'assets/images/campus-cafe-logo-350sidebar.png',)
),
Container(
padding: const EdgeInsets.all(8.0),
alignment: Alignment.center,
child: Text("Our Menu", style: TextStyle(fontSize: 30),
),
),
Expanded(
child: ListView.builder(
itemCount: menu.getSandwichMap().length,
itemBuilder: (context, int index) {
String key = menu.getSandwichMap().keys.elementAt(index);
return new Column(
children: <Widget>[
//DropdownButton<String>(
//isExpanded: true;
//items: menu.getSandwichMap();
new ListTile(
title: new Text("$key"),
subtitle: new Text("${menu.getSandwichMap()[key]}"),
),
new Divider(
height: 2.0,
),
// ),
],
);
},
),
)
]
),
),
);
}
}
It is not that difficult to build a dropdown field from your map values.
Basically the idea is you need to get a List<String> first. Then, your life will be much easier. How you want to get there, is up to you.
I have created a DartPad example using your values. Try have a look there.
https://dartpad.dev/93b680c13c57e7a8faff99116793cd3f
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
final List<String> sandwichItems = sandwichMap.keys.toList();
String dropdownValue;
Widget build(BuildContext context) {
return
Container(
child: DropdownButton<String>(
value: dropdownValue ?? sandwichItems[0],
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: sandwichItems.map((e){
return DropdownMenuItem<String>(
value: e,
child: Text(e),
);
}).toList(),
),
);
}
}
Map<String, double> sandwichMap = {
"Veggie Melt": 4.50,
"Crispy Chicken Wrap": 6.95,
"Italian Meatball Sub": 6.99,
"Chicken Parm Grinder": 6.59,
"Grill Cheese": 3.59,
"Grilled Ham & Cheese": 4.59,
"Bacon Bagel Melt": 5.29};
how to make FlatButton disabled based on the values contained in the database?
My app displays 5 questions taken from a database that has 4 answer choices.
my plan is to disabled the button after the user selects an answer.
how to handle it?
My function
_disableButton(BuildContext context, int idSoal, String idUser) async {
final response = await http.post(BaseUrl.cekJawaban, body: {
'id_user': idUser,
'id_soal': "$idSoal",
});
final data = jsonDecode(response.body);
int value = data['value'];
String pesan = data['message'];
if (value == 1) {
print(pesan);
} else {
print(pesan);
}
}
Mysql api
<?php
require "../config/connect.php";
if($_SERVER['REQUEST_METHOD']=="POST"){
$response = array();
$id_user = $_POST['id_user'];
$id_soal = $_POST['id_soal'];
$cek = "SELECT * FROM t_jawab WHERE selesai_jawab ='1' AND id_user='$id_user' AND id_soal='$id_soal'";
$result = mysqli_fetch_array(mysqli_query($conn, $cek));
if (isset($result)){
$response['value']=1;
$response['message']="Question and answer found!";
echo json_encode($response);
mysqli_close($conn);
}else{
$response['value']=0;
$response['message']="Question and answer not found!";
echo json_encode($response);
}
}
?>
Here's my table, id_soal and id_user are foreign key. If data not exist, then button active else button disabled
a way to disable buttons is using a bool value on the onPressed functions as shown below
`RaisedButton(
child: Text("PRESS BUTTON"),
onPressed: booleanCondition
? () => myTapCallback()
: null
)`
from your question if you want to show/ use multiple answer questions you can use Radio<T> class
Used to select between a number of mutually exclusive values. When one radio button in a group is selected, the other radio buttons in the group cease to be selected Enums are commonly used for this purpose.
example
// Flutter code sample for Radio
// Here is an example of Radio widgets wrapped in ListTiles, which is similar
// to what you could get with the RadioListTile widget.
//
// The currently selected character is passed into `groupValue`, which is
// maintained by the example's `State`. In this case, the first `Radio`
// will start off selected because `_character` is initialized to
// `SingingCharacter.lafayette`.
//
// If the second radio button is pressed, the example's state is updated
// with `setState`, updating `_character` to `SingingCharacter.jefferson`.
// This causes the buttons to rebuild with the updated `groupValue`, and
// therefore the selection of the second button.
//
// Requires one of its ancestors to be a [Material] widget.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
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: Center(
child: MyStatefulWidget(),
),
),
);
}
}
enum SingingCharacter { lafayette, jefferson }
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
SingingCharacter _character = SingingCharacter.lafayette;
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ListTile(
title: const Text('Lafayette'),
leading: Radio(
value: SingingCharacter.lafayette,
groupValue: _character,
onChanged: (SingingCharacter value) {
setState(() {
_character = value;
});
},
),
),
ListTile(
title: const Text('Thomas Jefferson'),
leading: Radio(
value: SingingCharacter.jefferson,
groupValue: _character,
onChanged: (SingingCharacter value) {
setState(() {
_character = value;
});
},
),
),
],
);
}
}
I'm a beginner and only recently started learning Flutter.
After searching the web for a long time I finally managed to find a tutorial that explains how to add a dynamic theme changer.
Now this works perfectly - however I still don't get where & how I'm supposed to add my custom colors like
primaryColor: Colors.white, accentColor: Colors.green,
in ThemeData.
I will post my code below, please help me.
main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ThemeChanger>(
create: (_) => ThemeChanger(ThemeData.light()),
child: MaterialAppWithTheme(),
);
}
}
class MaterialAppWithTheme extends StatelessWidget {
#override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeChanger>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: theme.getTheme(),
home: MdLayout(),
);
}
}
theme.dart
class ThemeChanger with ChangeNotifier{
ThemeData _themeData;
ThemeChanger(this._themeData);
getTheme() => _themeData;
setTheme(ThemeData theme) {
_themeData = theme;
notifyListeners();
}
}
theme_switch_state.dart
class ThemeSwitchState extends State {
bool switchControl = false;
#override
Widget build(BuildContext context) {
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Transform.scale(
scale: 1.5,
child: Switch(
onChanged: toggleSwitch,
value: switchControl,
activeColor: Colors.blue,
activeTrackColor: Colors.grey,
inactiveThumbColor: Colors.green,
inactiveTrackColor: Colors.white,
)),
]);
}
void toggleSwitch(bool value) {
ThemeChanger _themeChanger = Provider.of<ThemeChanger>(context, listen: false);
if (switchControl == false) {
setState(() {
switchControl = true;
});
print('Theme is Dark');
// Put your code here which you want to execute on Switch ON event.
_themeChanger.setTheme(ThemeData.dark());
} else {
setState(() {
switchControl = false;
});
print('Theme is Light');
// Put your code here which you want to execute on Switch OFF event.
_themeChanger.setTheme(ThemeData.light());
}
}
}
If you construct normal ThemeData class, there are so many properties you can put value into. For instance, ThemeData(primaryColor: Colors.red), but if you use the named constructor like ThemeData.light(), Flutter put all the default values for a standard light theme, the same goes with ThemeData.dark(). So what you can do is to use copyWith() method to some sort overwritten the default values, ThemeData.light().copyWith(primaryColor: Colors.white, accentColor: Colors.green,).
I have written a Flutter application that makes use of package:flutter/material.dart. Running the app on the iOS Simulator looks as follows. As you can see, there is no padding between components in one row, and the components reach to top, bottom, left and right without padding/margin/border. My question is:
What is the recommended way to apply Material-compliant padding, for example for the label-component-gap between Convert to and the dropdown button. Would I pack my components in a Container and apply padding there?
Thank you very much in advance.
This is the application code:
import 'package:flutter/material.dart';
import 'converter.dart';
import 'model.dart';
const _appName = 'Temperature Converter';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: _appName,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: _appName),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final Model model = new Model();
var _currentInput = const InputValue();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(config.title),
),
body: new Column(children: <Widget>[
new Row(children: <Widget>[
new Expanded(
child: new Input(
hintText: 'Temperature',
value: _currentInput,
onChanged: (input) => _currentInput = input)),
new DropdownButton(
items: createUnit(),
onChanged: (temperatureUnit newValue) {
setState(() {
model.inUnit = newValue;
});
},
value: model.inUnit)
]),
new Row(children: <Widget>[
new Text("Convert to"),
new DropdownButton(
items: createUnit(),
onChanged: (temperatureUnit newValue) {
setState(() {
model.outUnit = newValue;
});
},
value: model.outUnit),
]),
new FlatButton(
child: new Text('Calculate'),
onPressed: () {
setState(() {
double inTemp = stringToDouble(_currentInput.text);
model.inTemperature = inTemp;
model.calculateOutTemperature();
});
}),
new Text(model.outTemperatureAsString)
]), // This trailing comma tells the Dart formatter to use
// a style that looks nicer for build methods.
);
}
List<DropdownMenuItem> createUnit() {
var l = new List<DropdownMenuItem<temperatureUnit>>();
// degrees Celsius
l.add(new DropdownMenuItem<temperatureUnit>(
value: temperatureUnit.degreesCelsius,
child: new Text(unitDegreesCelsius)));
// degrees Fahrenheit
l.add(new DropdownMenuItem<temperatureUnit>(
value: temperatureUnit.degreesFahrenheit,
child: new Text(unitDegreesFahrenheit)));
// Kelvin
l.add(new DropdownMenuItem<temperatureUnit>(
value: temperatureUnit.kelvin, child: new Text(unitKelvin)));
return l;
}
}
The question is by no means implying that Flutter is missing something. I merely want to do it right. ;-)
Generally I would recommend using a Block as the child of the Scaffold. It has a padding value that you can set.
You can also just use a Padding widget.
I only know ButtonTheme that have a padding value
ButtonTheme.of(context).padding
So I think the best solution for now is to have constant value and use a Container to apply your padding.
Maybe I am wrong but I don't know any Widget that automatically apply any Material padding.
I made a simple example with an input text, but on my phone (nokia edge 6) neither on an older tablet (samsung) don't work.... 2 problem:
1) if I tap on the input, the string inserted (as soon as I write some text) doesn't appear in the input
2) if use an initial value for the input, if I tap in it, I cannot write text and I cannot position the cursor where I want (it goes only before other text inside the input)
how can I do? thanks very much!
Here is my code:
import 'package:flutter/material.dart';
void main() {
runApp(
new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue
),
home: new FlutterDemo()
)
);
}
class FlutterDemo extends StatefulWidget {
FlutterDemo({ Key key }) : super(key: key);
#override
_FlutterDemoState createState() => new _FlutterDemoState();
}
class _FlutterDemoState extends State<FlutterDemo> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Input Demo')
),
body: new Center(
child:
new Input(
value: new InputValue(text: 'via Dei Giacinti n° 8'),
labelText: 'INDIRIZZO'
)
)
);
}
}
As far as I understand the problem is that every time the user edits the text (or changes the position of the cursor) the state of the widget changes such that it is rebuilt. When the widget is built you specify the text of the Input, thus it never changes.
The following should work:
class _FlutterDemoState extends State<FlutterDemo> {
InputValue inputValue = new InputValue(text: 'via Dei Giacinti n° 8');
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text('Input Demo')),
body: new Center(child: new Input(
value: inputValue,
labelText: 'INDIRIZZO',
onChanged: (InputValue newInputValue) {
setState(() {
inputValue = newInputValue;
});
})));
}
}
I had the same problem in flutter web but then I noticed that if I add maxlines: 2 it did work .
TextFotmField() and TextField()