Flutter: How can use RadioListTile with flutter cubit? - flutter

I am not able to make RadioListTile works. It isn't selected and unselected on click
Can you help me?
Here is me code
edit
...
final ownedController =TextEditingController();
...
RadioListTile<
String>(
value:'not owned',
groupValue:ownedController.text,
toggleable:true,
title: const Text('Owned'),
onChanged:(String) {
cubit.changeOwned(ownedController.text);
}),
...
cubit
...
bool isOwned = false;
String changeOwned(String owned) {
isOwned = !isOwned;
if (isOwned == true) {
owned = 'owned';
} else {
owned = 'not owned';
}
return owned;
}
...

Here is an example based on the enum it is more flexible and easier to add more objects in the future. Enum values can also be converted to the string and represented your user interface in a readable form.
Just copy and paste into DartPad to play with it:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => SomeCubit(),
child: const MaterialApp(
home: SomeView(),
),
);
}
}
class SomeView extends StatelessWidget {
const SomeView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('My App')),
body: BlocBuilder<SomeCubit, SomeStatus>(
builder: (context, state) {
return Column(
children: [
for (var value in SomeStatus.values)
RadioListTile<String>(
title: Text(value.titleByIndex), // <- Title by extension.
value: value.name,
groupValue: state.name,
toggleable: true,
selected: value.name.contains(state.name),
onChanged: context.read<SomeCubit>().onChanged,
),
],
);
},
),
);
}
}
enum SomeStatus { owned, notOwned }
class SomeCubit extends Cubit<SomeStatus> {
SomeCubit() : super(SomeStatus.notOwned);
void onChanged(String? name) {
emit(SomeStatus.values.byName(name ?? state.name));
}
}
extension SomeStatusEx on SomeStatus {
// A useful function for converting value names to UI view.
// List ordering must contain enum values.
String get titleByIndex => ['Owned', 'Not Owned'].elementAt(index);
}
With Dart 2.17 and above:
// Dart 2.17 can convert enum value to any value
// and you do not need to create an extension to put a nicer value name to the view.
enum SomeStatus {
owned('Owned'),
notOwned('Not Owned');
const SomeStatus(this.label);
// View in the user interface "title: Text(value.label)"
final String label;
}

you can avoid using cubit to switch state.
...
final ownedController = TextEditingController();
bool isOwned = false;
String get ownedString => isOwned ? 'owned' : 'not owned';
...
RadioListTile<String>(
value: ownedString,
groupValue: 'owned',
toggleable: true,
title: Text(ownedString),
onChanged: (x) {
setState(() {
isOwned = !isOwned;
ownedController.text = ownedString;
});
},
),
...
you have to fix the toggleGroupe to 'owned' otherwise you'll have wrong display.

Related

GetX UI state not changing on ListTile

I have a list of objects, but I want to change the state of one object to "isLoading" where it will have a different title, etc.
I'm building my list view:
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
body: Obx(() => buildListView(context)));
}
Widget buildListView(BuildContext context) {
return ListView.builder(
itemCount: controller.saveGames.length,
itemBuilder: (context, index) {
final saveGame = controller.saveGames.elementAt(index);
return saveGame.isLoading
? buildListTileIsLoading(context, saveGame)
: buildListTile(context, saveGame);
});
}
ListTile buildListTile(BuildContext context, SaveGame saveGame) {
return ListTile(
onTap: () => controller.process(saveGame)
);
}
The controller:
class SaveGameController extends GetxController {
final RxList<SaveGame> saveGames = <SaveGame>[].obs;
void process(SaveGame saveGame) {
saveGame.working = true;
update();
}
}
Where have I gone wrong here?
edits: Added more code
So despite the fact, I'm only updating one object in the list and not modifying the content of the list (adding/removing objects) I still need to call saveGames.refresh();
An oversight on my end didn't think you'd need to refresh the entire list if you're just changing the property on one of the objects.
Good to know :)
update() is used with GetBuilder()
obs() is used with obx()
you need to make a change on list to update widgets
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get_navigation/get_navigation.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetMaterialApp(
onInit: () {
Get.lazyPut(() => SaveGameController());
},
home: const HomePage(),
);
}
}
class HomePage extends GetView<SaveGameController> {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(), body: Obx(() => buildListView(context)));
}
Widget buildListView(BuildContext context) {
return ListView.builder(
itemCount: controller.saveGames.length,
itemBuilder: (context, index) {
final saveGame = controller.saveGames.elementAt(index);
return buildListTile(context, saveGame);
});
}
ListTile buildListTile(BuildContext context, SaveGame saveGame) {
return ListTile(
tileColor: saveGame.working ? Colors.red : Colors.yellow,
title: Text(saveGame.name),
onTap: () => controller.process(saveGame));
}
}
class SaveGameController extends GetxController {
final RxList<SaveGame> saveGames = <SaveGame>[
SaveGame(id: 0, name: 'a', working: false),
SaveGame(id: 1, name: 'b', working: false),
SaveGame(id: 2, name: 'c', working: false)
].obs;
void process(SaveGame saveGame) {
final index = saveGames.indexWhere((element) => element.id == saveGame.id);
saveGames
.replaceRange(index, index + 1, [saveGame.copyWith(working: true)]);
}
}
class SaveGame {
final int id;
final String name;
final bool working;
SaveGame({required this.id, required this.name, required this.working});
SaveGame copyWith({int? id, String? name, bool? working}) {
return SaveGame(
id: id ?? this.id,
name: name ?? this.name,
working: working ?? this.working);
}
}

Checkbox are not changing their status with MobX

I'm using MobX on Flutter to control states.
Clicking on the FloatingActionButton generates a ListView that contains CheckboxListTile.
However checkboxes are not changing their status
Could you help me fix this problem?
Below is the code and an image:
home_controller.dart
import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart';
import 'package:flutter_modular/flutter_modular.dart';
part 'home_controller.g.dart';
#Injectable()
class HomeController = _HomeControllerBase with _$HomeController;
abstract class _HomeControllerBase with Store {
#observable
ObservableList<CheckBoxModel> mapValues = <CheckBoxModel>[].asObservable();
#observable
ListView listViewCheckbox;
#action
void listViewChekbox(value) {
for (var i in value) {
mapValues.add(CheckBoxModel(key: i));
}
}
}
class CheckBoxModel{
CheckBoxModel({this.key, this.checked = false});
String key;
bool checked;
}
home_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'home_controller.dart';
class HomePage extends StatefulWidget {
final String title;
const HomePage({Key key, this.title = "Home"}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends ModularState<HomePage, HomeController> {
HomeController controller = HomeController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Observer(builder: (_) {
return controller.mapValues == null ? Container() : ListView.builder(
itemCount: controller.mapValues.length,
itemBuilder: (_, int index){
return CheckboxListTile(
title: Text(controller.mapValues[index].key),
value: controller.mapValues[index].checked,
onChanged: (bool value) {
controller.mapValues[index].checked = value;
},
);
},
);
}),
floatingActionButton: FloatingActionButton(
onPressed: () {
List listValues = ['foo', 'bar'];
controller.listViewChekbox(listValues);
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
According to the image, the ListView of CheckboxListTile is created but the checkboxes do not change their status.
You don't have to use setState() or anything else mobX does that for you, you just need to edit you abstract class to tell mobX main variable value changed, like next
abstract class _HomeControllerBase with Store {
#observable
ObservableList<CheckBoxModel> mapValues = <CheckBoxModel>[].asObservable();
#observable
ListView listViewCheckbox;
#action
void listViewChekbox(value) {
for (var i in value) {
mapValues.add(CheckBoxModel(key: i));
}
mapValues = mapValues;
}
}
That's how you can solve it.
the solution found was to insert setState
onChanged: (bool value) {
setState(() {
controller.mapValues[index].checked = value;
});
},

Flutter: How to Disable FlatButton based mysql database

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;
});
},
),
),
],
);
}
}

How to assign i unique ID or key to SwitchListTile and retrieve/get its value in onChanged in flutter mobile app

I am building 9 SwitchListTile using for loop, as now the button contains same code so am having trouble
in its onChanged as my each button will have specific event to perform, how should i achieve it? Is it possible to send the button text/id or anything unique based on which i can perform the specific tasks?
Here _onChanged(value, counter); 'counter' is nothing but you can assume a variable in for loop assigning values 1-9 for each button. So Onchange i should know which button was pressed!.
I tried assigning // key: ValueKey(counter), to SwitchListTile constructor but was unable to retrieve that value in onChanged.
class MySwitchListTilesContainer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[800],
body: ListView(
children: List.generate(20, (i)=>MySwitchListTile(
)),
),
);
}
}
class MySwitchListTile extends StatefulWidget {
#override
_MySwitchListTileState createState() => new _MySwitchListTileState();
}
class _MySwitchListTileState extends State<MySwitchListTile> {
bool _v = false;
#override
Widget build(BuildContext context) {
return SwitchListTile(
value:_v,
onChanged: (value) {
_onChanged(value, counter);
},
);
}
}
void _onChanged(bool _v, int index) {
setState(() {
_v = _v;
if (index == 1) {
print(index);
} else {
print(index +1);
}
});
}
You can copy paste run full code below
You can pass callback to use in onChanged
code snippet
ListView(
children: List.generate(
20,
(i) => MySwitchListTile(
v: false,
callback: () {
print("index is $i");
setState(() {
});
},
)),
)
...
class MySwitchListTile extends StatefulWidget {
final bool v;
final VoidCallback callback;
...
return SwitchListTile(
value: widget.v,
onChanged: (value) {
widget.callback();
},
);
working demo
output of working demo
I/flutter ( 6597): index is 0
I/flutter ( 6597): index is 2
I/flutter ( 6597): index is 6
full code
import 'package:flutter/material.dart';
class MySwitchListTilesContainer extends StatefulWidget {
#override
_MySwitchListTilesContainerState createState() => _MySwitchListTilesContainerState();
}
class _MySwitchListTilesContainerState extends State<MySwitchListTilesContainer> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[800],
body: ListView(
children: List.generate(
20,
(i) => MySwitchListTile(
v: false,
callback: () {
print("index is $i");
setState(() {
});
},
)),
),
);
}
}
class MySwitchListTile extends StatefulWidget {
final bool v;
final VoidCallback callback;
const MySwitchListTile({Key key, this.v, this.callback}) : super(key: key);
#override
_MySwitchListTileState createState() => new _MySwitchListTileState();
}
class _MySwitchListTileState extends State<MySwitchListTile> {
#override
Widget build(BuildContext context) {
return SwitchListTile(
value: widget.v,
onChanged: (value) {
widget.callback();
},
);
}
}
/*void _onChanged(bool _v, int index) {
setState(() {
_v = _v;
if (index == 1) {
print(index);
} else {
print(index + 1);
}
});
}*/
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MySwitchListTilesContainer(),
);
}
}

How to make Multiple Checkbox in flutter dynamically and get their values together

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()));
}