I have a simple Switch in my Drawer:
SwitchListTile(
title: Text("Dark Theme"),
value: darkThemeEnabled,
onChanged: (darkThemeEnabled) {
if (darkThemeEnabled) {
_themeChanger.setTheme(ThemeData.dark());
} else {
_themeChanger.setTheme(AppTheme.light);
}
)
When I enable my Switch it changes to my dark theme, but how can I change it back? How can I run something on disabling?
I know it must be pretty simple, but I'm currently stuck.
SwitchListTile widget itself doesn't manage state. You can create a StatefulWidget and call setState to update the UI.
class OnOff extends StatefulWidget {
#override
_OnOffState createState() => _OnOffState();
}
class _OnOffState extends State<OnOff> {
bool flag = false;
#override
Widget build(BuildContext context) {
return SwitchListTile(
title: const Text('Change Me'),
value: flag,
onChanged: (bool value) {
setState(() {
flag = value;
});
},
);
}
}
SwitchListTile(
title: Text("Dark Theme"),
value: darkThemeEnabled,
onChanged: (){
if(darkThemeEnabled)
doSometing();
}
)
Related
I am using CheckboxListTile to show some todo item in flutter(v3.0.4). This is the code looks like:
CheckboxListTile(
controlAffinity: ListTileControlAffinity.leading,
title: Text(element.name,style:element.isCompleted == 1? TextStyle(color: Colors.grey):TextStyle(color: Colors.black)),
value: element.isCompleted == 1?true:false,
checkColor: Colors.green,
selected: element.isCompleted == 1?true:false,
onChanged: (bool? value) {
if(value!){
element.isCompleted = 1;
}else{
element.isCompleted = 0;
}
TodoProvider.updateTodo(element).then((value) => {
TodoProvider.getTodos().then((todos) => {
buildTodoItems(todos)
})
});
},
))
when the user tap the CheckboxListTile item text, I want to show the todo detail information, when the user tap the checkbox, I want to make the todo task changed to complete. Now I am facing a problem is that I could not detect which part the user tap, all the way will trigger onchange event. I have already read the CheckboxListTile source code, seems no api to do this. Am I misssing something? what should I do to detect which part the user select?
You can wrap your title in a GestureDetector(). Now when the title is tapped, only the gesture detector will be run, and not the onChanged().
In this example, if you tap on the text "Checkbox" then you can see the actual checkbox value is not being updated but the GestureDetector is being called, and if you look at the console "tapped" is being printed.
Here is a complete example. I hope you understand:
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: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
const MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
var _value = false;
#override
Widget build(BuildContext context) {
return CheckboxListTile(
title: GestureDetector(
child: Text('Checkbox'),
onTap: () {
print('tapped');
// you can change the value here too
// setState(() {
// _value = !_value;
// });
},
),
value: _value,
onChanged: (bool? value) {
setState(() {
_value = value!;
});
},
);
;
}
}
I have this widget:
DropdownButton<String>(
value: rentPeriod,
items: rentPeriods.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(translate("expense.$value")),
);
}).toList(),
onChanged: (value) async {
setState(() {
rentPeriod = value;
});
},
),
How can I disable, let's say, the first option of the list?
i dont think there is any straight forward way of disabling a DropdownMenuItem
but you can have a list of the DropdownMenuItems you want to disable and then when you run setState you can check if that DropdownMenuItem is contained in that list and if it is then do nothing, also check by the DropdownMenuItem text if its contained in that list and if it is then change the color to be greyed out.
Like this
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
var rentPeriods = <String>['one', 'two'];
final disabledItems = ['one'];
var rentPeriod;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: rentPeriod,
items: rentPeriods.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
translate("expense.$value"),
style: TextStyle(
color: disabledItems.contains(value) ? Colors.grey : null,
),
),
);
}).toList(),
onChanged: (value) async {
if (!disabledItems.contains(value)) {
setState(() {
rentPeriod = value;
});
}
},
);
}
}
You can create your own disable customization, changing the color and the callback of onChangedfunction in the DropdownButton, like this example:
https://dartpad.dev/587b44d2f1b06e056197fcf705021699?null_safety=true
I want to send data from widget to another widget, in my example i want to send some filter data from FilterScreen.dart to ShopScreen.dart
it works fine but i dont know is what i'm doing is correct?
in filter model file:
class FilterData with ChangeNotifier {
bool isFreeShipping;
bool isSomeThingElse;
FilterData({this.isFreeShipping = false, this.isSomeThingElse = false});
void setFreeShippingValue(bool newval) {
isFreeShipping = newval;
notifyListeners();
}
void setSomeThingElseValue(bool newval) {
isSomeThingElse = newval;
notifyListeners();
}
}
in main.dart:
return ChangeNotifierProvider(
create: (context) => FilterData(),
child: MaterialApp(
.........
)
);
in tabs screen:
class TabsScreen extends StatefulWidget {
#override
_TabsScreenState createState() => _TabsScreenState();
}
class _TabsScreenState extends State<TabsScreen> {
List<Map<String, Object>> _pages;
int _selectedPageIndex = 0;
#override
void initState() {
_pages = [
{
'page': ShopScreen(),
'title': 'shop',
},
{
'page': FilterScreen(),
'title': 'filter',
},
];
super.initState();
}
void _selectPage(int index) {
setState(() {
_selectedPageIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_pages[_selectedPageIndex]['title']),
),
drawer: DrawerApp(),
body: _pages[_selectedPageIndex]['page'],
bottomNavigationBar: BottomNavigationBar(
onTap: _selectPage,
backgroundColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.white,
selectedItemColor: Theme.of(context).accentColor,
currentIndex: _selectedPageIndex,
// type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.shop),
title: Text('Shop'),
),
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.search),
title: Text('Filter'),
),
],
),
);
}
}
in FilterScreen.dart:
class FilterScreen extends StatefulWidget {
#override
_FilterScreenState createState() => _FilterScreenState();
}
class _FilterScreenState extends State<FilterScreen> {
#override
Widget build(BuildContext context) {
final data = Provider.of<FilterData>(context);
return Container(
child: Center(
child: Expanded(
child: ListView(
children: <Widget>[
SwitchListTile(
title: Text('Free Shipping'),
value: data.isFreeShipping,
subtitle: Text('get free shipping products'),
onChanged: (newValue) {
data.setFreeShippingValue(newValue);
}),
SwitchListTile(
title: Text('Some thing else'),
value: data.isSomeThingElse,
subtitle: Text('get filtred products'),
onChanged: (newValue) {
data.setSomeThingElseValue(newValue);
}),
],
),
),
),
);
}
}
in ShopScreen.dart:
class ShopScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
final data = Provider.of<FilterData>(context);
return Container(
child: Center(
child: Text(
data.isFreeShipping ? 'get favorite Products' : 'get all products'),
),
);
}
}
enter image description here
Your question indeed is a pain for most of the developers, which is like I don't know how it works!
So, if you are not able to understand. there are two reasons to that:
You just blindly followed the tutorial or documentation, cos of the time constraints
You did not understand how Flutter Provider State Management works. So, for that, do read upon these:
List of state managements in flutter
Flutter provider package, of course you have used that in your project. But read how he is using.
So, now let us jump to the code. How your code works?
There are multiple things which are responsible for this:
1. Provider Wrap: If you closely look into the main.dart code, you have done this
return ChangeNotifierProvider(
create: (context) => FilterData(), // here you define the ChangeNotifier class
child: MaterialApp(
.........
)
);
Now looking at the above code, you see, whenever you wrap the app with the ChangeNotifierProvider(), it always rebuilds whenever there is a state change in the class which you have provided inside that, in this case FilterData(). Any changes happens will reflect in the whole app, cos, ChangeNotifierProvider(), is keep rebuilding the state of the immediate child, in this case your, MaterialApp(), which is wrapped.
2. NotifyChanges from the ChangeNotifier class: If you look at your FilterData, it is the one which is responsible for the rebuilding of the app, which is wrapped by the ChangeNotifierProvider().
Let us see how:
void setFreeShippingValue(bool newval) {
isFreeShipping = newval;
notifyListeners();
}
void setSomeThingElseValue(bool newval) {
isSomeThingElse = newval;
notifyListeners();
}
If you closely take a look at the methods, which I mentioned in the above code from your FilterData class only, they have notifyListeners(). These are the ones, which is responsible, whenever your two methods called, it notifies the ChangeNotifierListener to rebuild the widget, and hence you see the updated data every time, you use any of the two methods
3. Using NotifyListeneres method from the FilterData in FilterScreen: So, again if we look closely at the thing which we have mentioned in the point 2, we see that, the method method should be called to make changes in the App which is the immediate child of ChangeNotifierProvider()
SwitchListTile(
title: Text('Free Shipping'),
value: data.isFreeShipping,
subtitle: Text('get free shipping products'),
onChanged: (newValue) {
data.setFreeShippingValue(newValue);
}),
SwitchListTile(
title: Text('Some thing else'),
value: data.isSomeThingElse,
subtitle: Text('get filtred products'),
onChanged: (newValue) {
data.setSomeThingElseValue(newValue);
}),
So, when you call any of the methods in your onChanged, it straight away notifies the Provider that, the value has been changed, and the app rebuilds, and when you switch to the other tab, you see updated result like magic.
MOST IMPORTANT: Your final data = Provider.of<FilterData>(context);, is an instance of the Provider class, which trigger the method to help notify the ChangeNotifierProvider() to make changes in the app
So the mapping is like that:
Listens to the change
FilterData {setFreeShippingValue, setSomeThingElseValue} <----------------------> ChangeNotifierProvider() REBUILDS MATERIALAPP()
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 am new in flutter I am facing a problem in creating a CheckBox with multiple items then the user can also select multiple items from the checkbox list. please help me, guys.
you can try this widget CheckboxListTile :
import 'package:flutter/material.dart';
class DemoCheck extends StatefulWidget {
#override
DemoCheckState createState() => new DemoCheckState();
}
class DemoCheckState extends State<Demo> {
Map<String, bool> values = {
'foo': true,
'bar': false,
};
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: Text('Demo')),
body: ListView(
children: values.keys.map((String key) {
return new CheckboxListTile(
title: Text(key),
value: values[key],
onChanged: (bool value) {
setState(() {
values[key] = value;
});
},
);
}).toList(),
),
);
}
}
void main() {
runApp( MaterialApp(home: DemoCheck()));
}