Compare two lists with String data? - arrays

How I can compare two lists with String data?
I need if values in second list match with first, change icon to red, if not match to green.
isEqual ? Colors.red : Colors.green
First list
List<String> pcAll = ['S01', 'S02', 'S03', 'S04', 'S05'];
Second list
List<String> pcBusy = ['S02', 'S03'];
class ComputerGrid extends StatelessWidget {
const ComputerGrid();
#override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 6 / 3,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
),
itemCount: pcAll.length,
itemBuilder: (BuildContext context, index) {
return GridTile(
child: Container(
color: isEqual() ? Colors.red : Colors.green,
child: Center(
child: Text(
pcAll[index],
),
class _EvrokoStandartScreenState extends State<EvrokoStandartScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
'ЕВРОКО Стандарт',
),
),
body: ComputerGrid(),

#Чак-Джонс you can compare the list as below.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> pcAll = ['S01', 'S02', 'S03', 'S04', 'S05'];
List<String> pcBusy = ['S02', 'S03'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 6 / 3,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
),
itemCount: pcAll.length,
itemBuilder: (BuildContext context, index) {
return GridTile(
child: Container(
color: pcBusy.contains(pcAll[index]) ? Colors.red : Colors.green,
child: Center(
child: Text(pcAll[index]),
),
),
);
},
),
);
}
}

You can compare two lists in flutter using listEquals method, or create a custom method like this.
bool areListsEqual(var list1, var list2) {
// check if both are lists
if(!(list1 is List && list2 is List)
// check if both have same length
|| list1.length!=list2.length) {
return false;
}
// check if elements are equal
for(int i=0;i<list1.length;i++) {
if(list1[i]!=list2[i]) {
return false;
}
}
return true;
}
void main(){
List list1 = [24, 'Hello', 84];
List list2 = [24, 'Hello', 84];
List list3 = [11, 'Hi', 41];
if(areListsEqual(list1, list2)) {
print('list1 and list2 are equal in value.');
} else {
print('list1 and list2 are not equal in value.');
}
if(areListsEqual(list1, list3)) {
print('list1 and list3 are equal in value.');
} else {
print('list1 and list3 are not equal in value.');
}
}

For listEqual
import 'package:flutter/foundation.dart';
...............
bool isEqual = listEquals(pcAll, pcBusy);
For DeepCollectionEquality
import 'package:collection/collection.dart';
.......
Function deepEq = const DeepCollectionEquality().equals;
bool idDeepEqual = deepEq(pcAll, pcBusy);
Normal hardCoded
List<String> pcAll = [
'S01',
'S02',
'S03',
'S04',
'S05',
'S06',
'S07',
'S09',
'S10'
];
List<String> pcBusy = ['S02', 'S03', 'S05', 'S06', 'S07', 'S08'];
List<String> resultSet1 = [];
pcBusy.forEach((pc) {
if (pcAll.contains(pc)) resultSet1.add(pc);
});
print(resultSet1);
print(resultSet1.length > 0 ? "didnot match" : "match");

Related

The argument type 'Object?' can't be assigned to the parameter type 'List<Destination>'

class Destination {
final double lat;
final double lng;
final String name;
final double distance;
const Destination({
required this.lat,
required this.lng,
required this.name,
required this.distance,
});
factory Destination.fromJson(Map<String, dynamic> json) {
return Destination(
lat: json['lat'] as double,
lng: json['lng'] as double,
name: json['name'] as String,
distance: json['distance'] as double,
);
}
}
here is the error
return listViewWidget(List<Destination>.from(snapshot.data));
this my code :
import 'package:flutter/material.dart';
import 'package:flutter_sorting_location/model.dart';
import 'package:geolocator/geolocator.dart';
import 'package:flutter_sorting_location/Utils.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
double? distance;
List<Destination> destinations = [];
Position? _currentPosition;
List<Destination> destinationlist = [];
Future<List<Destination>> getData() async {
var url = 'http://xxxxxxxxxxxxxx/flutter/getlocation.php';
var res =
await http.get(Uri.parse(url), headers: {"Accept": "application/json"});
print(res.body);
if (res.statusCode == 200) {
var data = json.decode(res.body);
var rest = data["articles"] as List;
print(rest);
destinations =
rest.map<Destination>((json) => Destination.fromJson(json)).toList();
}
print("List Size: ${destinations.length}");
return destinations;
}
#override
void initState() {
_getCurrentLocation();
super.initState();
}
Widget listViewWidget(List<Destination> article) {
return Container(
child: ListView.builder(
itemCount: 20,
padding: const EdgeInsets.all(2.0),
itemBuilder: (context, position) {
return Card(
child: ListTile(
title: Text(
'${article[position].name}',
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.bold),
),
leading: Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
child: article[position].name == null
? Image(
image: AssetImage('images/no_image_available.png'),
)
: Image.network('${article[position].name}'),
height: 100.0,
width: 100.0,
),
),
),
);
}),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Location sorting from current location"),
),
body: FutureBuilder(
future: getData(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return listViewWidget(List<Destination>.from(snapshot.data));
} else {
return Center(child: CircularProgressIndicator());
}
}),
);
}
// get Current Location
_getCurrentLocation() {
Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best,
forceAndroidLocationManager: true)
.then((Position position) {
distanceCalculation(position);
setState(() {
_currentPosition = position;
});
}).catchError((e) {
print(e);
});
}
distanceCalculation(Position position) {
for (var d in destinations) {
var km = getDistanceFromLatLonInKm(
position.latitude, position.longitude, d.lat, d.lng);
// var m = Geolocator.distanceBetween(position.latitude,position.longitude, d.lat,d.lng);
// d.distance = m/1000;
//d.distance = km;
destinationlist.add(d);
// print(getDistanceFromLatLonInKm(position.latitude,position.longitude, d.lat,d.lng));
}
setState(() {
destinationlist.sort((a, b) {
// print("a : ${a.distance} b : ${b.distance}");
return a.distance.compareTo(b.distance);
});
});
}
}
this what i found:
getData() is async function. Future<List<Destination>> which is return list of Object not Map or json anymore
so when you call that function here :
body: FutureBuilder(
future: getData(),
builder: (context, snapshot) {
snapshot is List<Destination> , then no need to convert to list anymore.
just like below
return listViewWidget(snapshot);
then on your listViewWidget method , changes this :
title: Text('${article.position.name}',) // no need brackets

Add data instead of overwriting it

When I use pop up AddPlanScreen to add a note to the widget, it overwrites the document instead of adding it. Registering, logging and setting data work properly.
What I've tried to do:
Using FirebaseFirestore.instance.runTransaction but I couldn't use + operator for String as I add data to map.
set(..., SetOptions(merge:true))
update method
Do I have to try to create a new Map and add data there? I am new to programming and will be very grateful for any suggestions.
This is a method I use to set and fetch data
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class MyProvider extends ChangeNotifier {
Map<String, dynamic> _names = {};
String name(String key) => _names[key];
void setName(String key, String newString) {
_names[key] = newString;
var firebaseUser = FirebaseAuth.instance.currentUser;
FirebaseFirestore.instance
.collection('Notes')
.doc(firebaseUser.uid)
.set(_names);
}
void fetchData() {
var firebaseUser = FirebaseAuth.instance.currentUser;
FirebaseFirestore.instance
.collection('Notes')
.doc(firebaseUser.uid)
.get()
.then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
var data = documentSnapshot.data();
_names = data;
} else {
print('The document does not exist on the database');
}
});
}
}
This is Planner Screen where I show all the notes
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:my_planner_app/widgets/my_provider.dart';
import 'file:///C:/Users/krisk/AndroidStudioProjects/planner_app/lib/widgets/weekday_card.dart';
import 'package:provider/provider.dart';
class PlannerScreen extends StatefulWidget {
static const String id = 'planner_screen';
#override
_PlannerScreenState createState() => _PlannerScreenState();
}
class _PlannerScreenState extends State<PlannerScreen> {
Widget build(BuildContext context) {
Provider.of<MyProvider>(context, listen: false)
.fetchData();
var size = MediaQuery.of(context).size;
final double itemHeight = (size.height - 24) / 2;
final double itemWidth = size.width / 2;
return Scaffold(
backgroundColor: Color(0xFFcf9e9f),
body: Container(
child: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: (itemWidth / itemHeight),
),
children: <Widget>[
WeekDayCard(
text: '',
),
WeekDayCard(text: 'Monday' ),
WeekDayCard(text: 'Tuesday'),
WeekDayCard(text: 'Wednesday'),
WeekDayCard(text: 'Thursday'),
WeekDayCard(text: 'Friday'),
WeekDayCard(text: 'Saturday'),
WeekDayCard(text: 'Sunday'),
WeekDayCard(text: 'Notes'),
],
),
),
);
}
}
This is associated WeekDayCard widget
import 'package:flutter/material.dart';
import 'package:my_planner_app/screens/addPlan_screen.dart';
import 'package:provider/provider.dart';
import 'package:my_planner_app/widgets/my_provider.dart';
class WeekDayCard extends StatefulWidget {
WeekDayCard({#required this.text, this.name});
final String name;
final String text;
#override
_WeekDayCardState createState() => _WeekDayCardState();
}
class _WeekDayCardState extends State<WeekDayCard> {
#override
Widget build(BuildContext context) {
return Consumer<MyProvider>(builder: (context, myProvider, child) {
return Card(
color: Color(0xFFFEEFCD),
elevation: 10,
child: Column(
children: [
Text(widget.text),
Text(Provider.of<MyProvider>(context).name(widget.text) ?? ''
),
Expanded(
child: InkWell(
onTap: () {
showModalBottomSheet(
backgroundColor: Color(0xFFFEEFCD),
context: context,
builder: (context) => AddPlanScreen(weekdayName: widget.text),
);
},
),
),
],
),
);
});
}
}
This is associated AddPlanScreen
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:my_planner_app/widgets/my_provider.dart';
class AddPlanScreen extends StatefulWidget {
final String weekdayName;
const AddPlanScreen({Key key, this.weekdayName}) : super(key: key);
#override
_AddPlanScreenState createState() => _AddPlanScreenState();
}
class _AddPlanScreenState extends State<AddPlanScreen> {
String name;
#override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: TextFormField(
onChanged: (text) {
name = text;
},
decoration: InputDecoration(
border: InputBorder.none,
),
minLines: 10,
maxLines: 30,
autocorrect: false,
),
),
FlatButton(
onPressed: () {
Provider.of<MyProvider>(context, listen: false)
.setName(widget.weekdayName, name);
Navigator.pop(context);
},
color: Colors.blue,
),
],
);
}
}
You should use set only when you are creating a document for the first time and you want to give it a designated ID (not randomly generated by firebase). Or, a second use is when you want to deliberately write over your existing data.
When you want to update a document, or a single value\entry in it, you just use: collection('yourCollection').doc('yourDocID').update({"nameOfnewField": "new data"})
This update method will not overwrite your existing document,it will only add a new field called "nameOfnewField", or if that field already exists, it will write over it only.
i.e if nameOfnewField was a value that was false, when you update it, with .update({"nameOfnewField": "true"}), it becomes true but the rest of the document is not changed.

Flutter the values in the array all become the same

Please understand that I am not good at English because I am a foreigner.
There was a problem while I was programming.
I was going to put each object in the array. We succeeded in putting the object in. But there was a problem with all the objects in the array being the same.
I want to solve this problem.
I'd appreciate it if you could help me.
Main.dart :
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'Page/FirstPage.dart';
import 'Page/FourPage.dart';
import 'Page/SecondPage.dart';
import 'Page/ThirdPage.dart';
import 'module/goal.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Index()),
ChangeNotifierProvider(create: (_) => Goal('None')),
ChangeNotifierProvider(create: (_) => GoalList())
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Todo App',
home: MainPage(),
),
);
}
}
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
var currentTab = [FirstPage(), SecondPage(), ThirdPage(), FourPage()];
#override
Widget build(BuildContext context) {
Index currentIndex = Provider.of<Index>(context);
Goal goal = Provider.of<Goal>(context);
return Scaffold(
body: IndexedStack(
index: currentIndex.currentIndex,
children: currentTab,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex.currentIndex,
onTap: (index) {
currentIndex.currentIndex = index;
},
type: BottomNavigationBarType.fixed,
// 하단바 아이콘 고정
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.add_circle), title: Text('Todo Create')),
BottomNavigationBarItem(
icon: Icon(Icons.format_list_bulleted),
title: Text('Todo List')),
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today), title: Text('none')),
BottomNavigationBarItem(
icon: Icon(Icons.settings), title: Text('none')),
],
selectedItemColor: Colors.black87,
// 선택된 index 색깔
unselectedItemColor: Colors.black54,
// 선택안된 index 색깔
),
);
}
}
Goal.dart
import 'package:flutter/cupertino.dart';
// 아이콘 설정 , 제목 , 기간 ,
class Goal with ChangeNotifier {
String _name;
String get getName => _name;
set setName(String name)=> _name = name;
Goal(this._name);
#override String toString() => _name;
}
class Index with ChangeNotifier {
int _currentIndex = 0;
get currentIndex => _currentIndex;
set currentIndex(int index) {
_currentIndex = index;
notifyListeners();
}
}
class GoalList with ChangeNotifier {
List<Goal> goalList = [];
Goal getGoal;
addGoalInList() {
goalList.add(getGoal);
notifyListeners();
}
}
FirstPage.dart
import 'package:flutter/material.dart';
import 'package:goalapp/module/goal.dart';
import 'package:provider/provider.dart';
class FirstPage extends StatefulWidget {
#override
_FirstPageState createState() => _FirstPageState();
}
// 객체를 만들 클래스를 생성
// 생성된 객체를 내부저장소에 저장
class _FirstPageState extends State<FirstPage> {
final _formKey = GlobalKey<FormState>();
TextEditingController _names = TextEditingController();
#override
void dispose() {
_names.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
Index currentIndex = Provider.of<Index>(context);
Goal goal = Provider.of<Goal>(context);
GoalList goalList = Provider.of<GoalList>(context);
return Scaffold(
appBar: AppBar(
title: Text('Todo add'),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
children: <Widget>[
Container(
width: 200,
height: 200,
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
controller: _names,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(10))),
filled: true,
hintText: 'Todo Name'),
),
],
),
),
),
RaisedButton(
onPressed: () {
goal.setName = _names.text;
goalList.getGoal = goal;
goalList.addGoalInList();
currentIndex.currentIndex = 1;
},
child: Text('Create'),
)
],
)
],
),
);
}
}
SecondPage.dart
import 'package:flutter/material.dart';
import 'package:goalapp/module/goal.dart';
import 'package:provider/provider.dart';
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
#override
Widget build(BuildContext context) {
Goal goal = Provider.of<Goal>(context);
GoalList goalList = Provider.of<GoalList>(context);
return Scaffold(
appBar: AppBar(
title: Text('Todo ListView'),
),
body: Column(
children: <Widget>[
Expanded(
child: Consumer<GoalList>(builder: (context, goal, child) {
return ListView.separated(
itemCount: goal.goalList.length,
itemBuilder: (context, index) {
return Container(
child: ListTile(
title: Text(goalList.goalList[index].getName),
subtitle: Text('2020.07.16 ~ 2020.08.16'),
),
);
},
separatorBuilder: (context, index) {
return Divider();
},
);
}),
),
RaisedButton(
onPressed: () {
print(goalList.goalList[0]);
},
child: Text('List[0]'),
),
RaisedButton(
onPressed: () {
print(goalList.goalList[1]);
},
child: Text('List[1]'),
),
],
));
}
}
You can copy paste run full code below
Step 1: Change GoalList's addGoalInList(Goal goal)
class GoalList with ChangeNotifier {
List<Goal> goalList = [];
Goal getGoal;
addGoalInList(Goal goal) {
goalList.add(goal);
notifyListeners();
}
}
Step 2: You do not need Goal goal = Provider.of<Goal>(context);
#override
Widget build(BuildContext context) {
Index currentIndex = Provider.of<Index>(context);
// Goal goal = Provider.of<Goal>(context);
Step 3: Add goal with Goal goal = Goal(_names.text); then goalList.addGoalInList(goal);
RaisedButton(
onPressed: () {
Goal goal = Goal(_names.text);
//goal.setName = _names.text;
//goalList.getGoal = goal;
goalList.addGoalInList(goal);
currentIndex.currentIndex = 1;
},
child: Text('Create'),
)
working demo
full code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter/cupertino.dart';
// 아이콘 설정 , 제목 , 기간 ,
class Goal with ChangeNotifier {
String _name;
String get getName => _name;
set setName(String name)=> _name = name;
Goal(this._name);
#override String toString() => _name;
}
class Index with ChangeNotifier {
int _currentIndex = 0;
get currentIndex => _currentIndex;
set currentIndex(int index) {
_currentIndex = index;
notifyListeners();
}
}
class GoalList with ChangeNotifier {
List<Goal> goalList = [];
Goal getGoal;
addGoalInList(Goal goal) {
goalList.add(goal);
notifyListeners();
}
}
class FirstPage extends StatefulWidget {
#override
_FirstPageState createState() => _FirstPageState();
}
// 객체를 만들 클래스를 생성
// 생성된 객체를 내부저장소에 저장
class _FirstPageState extends State<FirstPage> {
final _formKey = GlobalKey<FormState>();
TextEditingController _names = TextEditingController();
#override
void dispose() {
_names.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
Index currentIndex = Provider.of<Index>(context);
// Goal goal = Provider.of<Goal>(context);
GoalList goalList = Provider.of<GoalList>(context);
return Scaffold(
appBar: AppBar(
title: Text('Todo add'),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
children: <Widget>[
Container(
width: 200,
height: 200,
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
controller: _names,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(10))),
filled: true,
hintText: 'Todo Name'),
),
],
),
),
),
RaisedButton(
onPressed: () {
Goal goal = Goal(_names.text);
//goal.setName = _names.text;
//goalList.getGoal = goal;
goalList.addGoalInList(goal);
currentIndex.currentIndex = 1;
},
child: Text('Create'),
)
],
)
],
),
);
}
}
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
#override
Widget build(BuildContext context) {
Goal goal = Provider.of<Goal>(context);
GoalList goalList = Provider.of<GoalList>(context);
return Scaffold(
appBar: AppBar(
title: Text('Todo ListView'),
),
body: Column(
children: <Widget>[
Expanded(
child: Consumer<GoalList>(builder: (context, goal, child) {
return ListView.separated(
itemCount: goal.goalList.length,
itemBuilder: (context, index) {
return Container(
child: ListTile(
title: Text(goalList.goalList[index].getName),
subtitle: Text('2020.07.16 ~ 2020.08.16'),
),
);
},
separatorBuilder: (context, index) {
return Divider();
},
);
}),
),
RaisedButton(
onPressed: () {
print(goalList.goalList[0]);
},
child: Text('List[0]'),
),
RaisedButton(
onPressed: () {
print(goalList.goalList[1]);
},
child: Text('List[1]'),
),
],
));
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Index()),
ChangeNotifierProvider(create: (_) => Goal('None')),
ChangeNotifierProvider(create: (_) => GoalList())
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Todo App',
home: MainPage(),
),
);
}
}
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
var currentTab = [FirstPage(), SecondPage()];
#override
Widget build(BuildContext context) {
Index currentIndex = Provider.of<Index>(context);
Goal goal = Provider.of<Goal>(context);
return Scaffold(
body: IndexedStack(
index: currentIndex.currentIndex,
children: currentTab,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex.currentIndex,
onTap: (index) {
currentIndex.currentIndex = index;
},
type: BottomNavigationBarType.fixed,
// 하단바 아이콘 고정
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.add_circle), title: Text('Todo Create')),
BottomNavigationBarItem(
icon: Icon(Icons.format_list_bulleted),
title: Text('Todo List')),
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today), title: Text('none')),
BottomNavigationBarItem(
icon: Icon(Icons.settings), title: Text('none')),
],
selectedItemColor: Colors.black87,
// 선택된 index 색깔
unselectedItemColor: Colors.black54,
// 선택안된 index 색깔
),
);
}
}

Flutter Checkbox not working in AlertDialog [duplicate]

I'm trying to create a Radio in a showDialog, however the animation that occurs on Radio does not appear in showDialog.
For example: when tapped in foo2 nothing happens, and when you exit in showDialog and go back to it, foo2 is selected.
Below is the code and a gif showing what is happening:
import "package:flutter/material.dart";
void main() {
runApp(new ControlleApp());
}
class ControlleApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: "My App",
home: new HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
HomePageState createState() => new HomePageState();
}
enum _RadioGroup {
foo1,
foo2
}
class HomePageState extends State<HomePage> {
_RadioGroup _itemType = _RadioGroup.foo1;
void changeItemType(_RadioGroup type) {
setState(() {
_itemType = type;
});
}
void showDemoDialog<T>({ BuildContext context, Widget child }) {
showDialog<T>(
context: context,
child: child,
);
}
#override
Widget build(BuildContext context){
return new Scaffold(
appBar: new AppBar(backgroundColor: new Color(0xFF26C6DA)),
body: new Container(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new InkWell(
onTap: (){
showDemoDialog<String>(
context: context,
child: new SimpleDialog(
title: const Text("show"),
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Radio<_RadioGroup>(
groupValue: _itemType,
value: _RadioGroup.foo1,
onChanged: changeItemType
),
const Text("foo1"),
new Radio<_RadioGroup>(
groupValue: _itemType,
value: _RadioGroup.foo2,
onChanged: changeItemType
),
const Text("foo2"),
],
)
],
)
);
},
child: new Container(
margin: new EdgeInsets.only(top: 16.0, bottom: 8.0),
child: new Text("Show"),
),
)
],
),
)
);
}
}
Remember that components are immutable.
When you call showDialog, the content of that dialog won't change even if HomePage does.
The solution is easy. You need to refactor a bit your code to something like :
showDialog(
context: context,
builder: (context) => MyForm()
)
and instead of changing the state of HomePage, you instead change the state of MyForm.
example :
class Test extends StatelessWidget {
void onSubmit(String result) {
print(result);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
onPressed: () => showDialog(context: context, builder: (context) => MyForm(onSubmit: onSubmit)),
child: Text("dialog"),
),
),
);
}
}
typedef void MyFormCallback(String result);
class MyForm extends StatefulWidget {
final MyFormCallback onSubmit;
MyForm({this.onSubmit});
#override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
String value = "foo";
#override
Widget build(BuildContext context) {
return SimpleDialog(
title: Text("My form"),
children: <Widget>[
Radio(
groupValue: value,
onChanged: (value) => setState(() => this.value = value),
value: "foo",
),
Radio(
groupValue: value,
onChanged: (value) => setState(() => this.value = value),
value: "bar",
),
FlatButton(
onPressed: () {
Navigator.pop(context);
widget.onSubmit(value);
},
child: new Text("submit"),
)
],
);
}
}

Flutter - Dynamic list with data coming from the database

I needed to create the DialogItem widgets using the data that comes from the database. I tried to use for(){} but it did not work.
Could you help me solve this problem?
I put the used code as well as the evidence that works, just does not work the dynamic list of DialogItem with the data of the database.
To work the code below, you need to insert the sqflite and path_provider dependencies into pubspec.yaml, thus:
dependencies:
sqflite: any
path_provider: any
flutter:
sdk: flutter
The DatabaseClient class will create the database with 3 records.
In the gif only foo1 appears the correct one would be to appear all the values of the list that came from the database:
[{name: foo1, color: 0}, {name: foo2, color: 1}, {name: foo3, color: 2}]
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
DatabaseClient _db = new DatabaseClient();
int number;
List listCategory;
List colors = [
const Color(0xFFFFA500),
const Color(0xFF279605),
const Color(0xFF005959)
];
createdb() async {
await _db.create().then(
(data){
_db.countCategory().then((list){
this.number = list[0][0]['COUNT(*)']; //3
this.listCategory = list[1];
//[{name: foo1, color: 0}, {name: foo2, color: 1}, {name: foo3, color: 2}]
});
}
);
}
#override
void initState() {
super.initState();
createdb();
}
void showCategoryDialog<T>({ BuildContext context, Widget child }) {
showDialog<T>(
context: context,
child: child,
)
.then<Null>((T value) {
if (value != null) {
setState(() { print(value); });
}
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(),
body: new Center(
child: new RaisedButton(
onPressed: (){
showCategoryDialog<String>(
context: context,
child: new SimpleDialog(
title: const Text('Categories'),
children: <Widget>[
//for(var i = 0; i < this.number; i++) {
new DialogItem(
icon: Icons.brightness_1,
color: this.colors[
this.listCategory[0]['color']
//the zero should be dynamic going from 0 to 2 with the for(){}
//but o for(){} dont work
],
text: this.listCategory[0]['name'],
onPressed: () {
Navigator.pop(context, this.listCategory[0]['name']);
}
),
//}
]
)
);
},
child: new Text("ListButton"),
)
),
);
}
}
//Creating Database with some data and two queries
class DatabaseClient {
Database db;
Future create() async {
Directory path = await getApplicationDocumentsDirectory();
String dbPath = join(path.path, "database.db");
db = await openDatabase(dbPath, version: 1, onCreate: this._create);
}
Future _create(Database db, int version) async {
await db.execute("""
CREATE TABLE category (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
color INTEGER NOT NULL
)""");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo1', 0)");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo2', 1)");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo3', 2)");
}
Future countCategory() async {
Directory path = await getApplicationDocumentsDirectory();
String dbPath = join(path.path, "database.db");
Database db = await openDatabase(dbPath);
var count = await db.rawQuery("SELECT COUNT(*) FROM category");
List list = await db.rawQuery('SELECT name, color FROM category');
await db.close();
return [count, list];
}
}
//Class of Dialog Item
class DialogItem extends StatelessWidget {
DialogItem({
Key key,
this.icon,
this.size,
this.color,
this.text,
this.onPressed }) : super(key: key);
final IconData icon;
double size = 36.0;
final Color color;
final String text;
final VoidCallback onPressed;
#override
Widget build(BuildContext context) {
return new SimpleDialogOption(
onPressed: onPressed,
child: new Container(
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
child: new Container(
margin: size == 16.0 ? new EdgeInsets.only(left: 7.0) : null,
child: new Icon(icon, size: size, color: color),
)
),
new Padding(
padding: size == 16.0 ?
const EdgeInsets.only(left: 17.0) :
const EdgeInsets.only(left: 16.0),
child: new Text(text),
),
],
),
)
);
}
}
There might be other issues, but as a start, I think this code
for(var i = 0; i < this.number; i++) {
...
}
should be changed to
children: this.number == null ? null :
new List(this.number).map((i) =>
new DialogItem(
icon: Icons.brightness_1,
color: this.colors[
this.listCategory[0]['color']
//the zero should be dynamic going from 0 to 2 with the for(){}
//but o for(){} dont work
],
text: this.listCategory[0]['name'],
onPressed: () {
Navigator.pop(context, this.listCategory[0]['name']);
}
).toList(),
to not throw an exception when this.number is null (response not yet received from the database).
and wrap the code that updates the state with setState(() {...})
createdb() async {
await _db.create().then(
(data){
_db.countCategory().then((list){
setState(() {
this.number = list[0][0]['COUNT(*)']; //3
this.listCategory = list[1];
//[{name: foo1, color: 0}, {name: foo2, color: 1}, {name: foo3, color: 2}]
});
});
}
);
}
I found the solution, according to the Flutter - Build Widgets dynamically and Flutter - Combine dynamically generated elements with hard-coded ones and in this question
As SimpleDialog only accepts a List of type Widget - <Widget>[] I declare a variable tiles of type List<Widget> - List<Widget> tiles; and created a function of type List<Widget> - List<Widget> buildTile(int counter) {... - to be able to return a List<Widget>
Because of Navigator.pop (context, ... I needed to create the buildTile() function inside the Widget build(BuildContext context) {...
In the buildTile() function I added a for() to insert into the Widget type list as many DialogItem Widgets were needed, according to the result that comes from the database
and wrap the code that updates the state with setState(() {...}) as explained by Günter Zöchbauer
setState(() {
this.number = list[0][0]['COUNT(*)']; //3
this.listCategory = list[1];
//[{name: foo1, color: 0}, {name: foo2, color: 1}, {name: foo3, color: 2}]
})
The complete code working as well as the demo are below:
To work the code below, you need to insert the sqflite and path_provider dependencies into pubspec.yaml, thus:
dependencies:
sqflite: any
path_provider: any
flutter:
sdk: flutter
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
DatabaseClient _db = new DatabaseClient();
int number;
List listCategory;
List<Widget> tiles;
List colors = [
const Color(0xFFFFA500),
const Color(0xFF279605),
const Color(0xFF005959)
];
createdb() async {
await _db.create().then(
(data){
_db.countCategory().then((list){
setState(() {
this.number = list[0][0]['COUNT(*)']; //3
this.listCategory = list[1];
//[{name: foo1, color: 0}, {name: foo2, color: 1}, {name: foo3, color: 2}]
});
});
}
);
}
#override
void initState() {
super.initState();
createdb();
}
void showCategoryDialog<T>({ BuildContext context, Widget child }) {
showDialog<T>(
context: context,
child: child,
)
.then<Null>((T value) {
if (value != null) {
setState(() { print(value); });
}
});
}
#override
Widget build(BuildContext context) {
List<Widget> buildTile(int counter) {
this.tiles = [];
for(var i = 0; i < counter; i++) {
this.tiles.add(
new DialogItem(
icon: Icons.brightness_1,
color: this.colors[
this.listCategory[i]['color']
],
text: this.listCategory[i]['name'],
onPressed: () {
Navigator.pop(context, this.listCategory[i]['name']);
}
)
);
}
return this.tiles;
}
return new Scaffold(
appBar: new AppBar(),
body: new Center(
child: new RaisedButton(
onPressed: (){
showCategoryDialog<String>(
context: context,
child: new SimpleDialog(
title: const Text('Categories'),
children: buildTile(this.number)
)
);
},
child: new Text("ListButton"),
)
),
);
}
}
//Creating Database with some data and two queries
class DatabaseClient {
Database db;
Future create() async {
Directory path = await getApplicationDocumentsDirectory();
String dbPath = join(path.path, "database.db");
db = await openDatabase(dbPath, version: 1, onCreate: this._create);
}
Future _create(Database db, int version) async {
await db.execute("""
CREATE TABLE category (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
color INTEGER NOT NULL
)""");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo1', 0)");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo2', 1)");
await db.rawInsert("INSERT INTO category (name, color) VALUES ('foo3', 2)");
}
Future countCategory() async {
Directory path = await getApplicationDocumentsDirectory();
String dbPath = join(path.path, "database.db");
Database db = await openDatabase(dbPath);
var count = await db.rawQuery("SELECT COUNT(*) FROM category");
List list = await db.rawQuery('SELECT name, color FROM category');
await db.close();
return [count, list];
}
}
//Class of Dialog Item
class DialogItem extends StatelessWidget {
DialogItem({
Key key,
this.icon,
this.size,
this.color,
this.text,
this.onPressed }) : super(key: key);
final IconData icon;
double size = 36.0;
final Color color;
final String text;
final VoidCallback onPressed;
#override
Widget build(BuildContext context) {
return new SimpleDialogOption(
onPressed: onPressed,
child: new Container(
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
child: new Container(
margin: size == 16.0 ? new EdgeInsets.only(left: 7.0) : null,
child: new Icon(icon, size: size, color: color),
)
),
new Padding(
padding: size == 16.0 ?
const EdgeInsets.only(left: 17.0) :
const EdgeInsets.only(left: 16.0),
child: new Text(text),
),
],
),
)
);
}
}

Resources