I need a nested TreeView where going through a list and build nodes based on parent child realationship. When tapping on a node it expands and shows its children with indentation. Also changing textstyle color of selectedt node..and 2d scrollable if the list is very long and has many nodes with children themselves having many children. How? please help.
You can copy paste run full code below
You can use package https://pub.dev/packages/flutter_treeview
It has some features you can customize, you can see working demo below
For parent child relation, you can see initState() in full code
#override
void initState() {
_nodes = [
Node(
label: 'documents',
key: 'docs',
expanded: docsOpen,
icon: NodeIcon(
codePoint:
docsOpen ? Icons.folder_open.codePoint : Icons.folder.codePoint,
color: "blue",
),
children: [
Node(
label: 'personal',
key: 'd3',
code snippet
TreeView(
controller: _treeViewController,
allowParentSelect: _allowParentSelect,
supportParentDoubleTap: _supportParentDoubleTap,
onExpansionChanged: (key, expanded) =>
_expandNode(key, expanded),
onNodeTap: (key) {
debugPrint('Selected: $key');
setState(() {
_selectedNode = key;
_treeViewController =
_treeViewController.copyWith(selectedKey: key);
});
},
theme: _treeViewTheme,
)
working demo
full code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_treeview/tree_view.dart';
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'TreeView Example',
home: MyHomePage(title: 'TreeView Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _selectedNode;
List<Node> _nodes;
TreeViewController _treeViewController;
bool docsOpen = true;
final Map<ExpanderPosition, Widget> expansionPositionOptions = const {
ExpanderPosition.start: Text('Start'),
ExpanderPosition.end: Text('End'),
};
final Map<ExpanderType, Widget> expansionTypeOptions = const {
ExpanderType.caret: Icon(
Icons.arrow_drop_down,
size: 28,
),
ExpanderType.arrow: Icon(Icons.arrow_downward),
ExpanderType.chevron: Icon(Icons.expand_more),
ExpanderType.plusMinus: Icon(Icons.add),
};
final Map<ExpanderModifier, Widget> expansionModifierOptions = const {
ExpanderModifier.none: ModContainer(ExpanderModifier.none),
ExpanderModifier.circleFilled: ModContainer(ExpanderModifier.circleFilled),
ExpanderModifier.circleOutlined:
ModContainer(ExpanderModifier.circleOutlined),
ExpanderModifier.squareFilled: ModContainer(ExpanderModifier.squareFilled),
ExpanderModifier.squareOutlined:
ModContainer(ExpanderModifier.squareOutlined),
};
ExpanderPosition _expanderPosition = ExpanderPosition.start;
ExpanderType _expanderType = ExpanderType.caret;
ExpanderModifier _expanderModifier = ExpanderModifier.none;
bool _allowParentSelect = false;
bool _supportParentDoubleTap = false;
#override
void initState() {
_nodes = [
Node(
label: 'documents',
key: 'docs',
expanded: docsOpen,
icon: NodeIcon(
codePoint:
docsOpen ? Icons.folder_open.codePoint : Icons.folder.codePoint,
color: "blue",
),
children: [
Node(
label: 'personal',
key: 'd3',
icon: NodeIcon.fromIconData(Icons.input),
children: [
Node(
label: 'Resume.docx',
key: 'pd1',
icon: NodeIcon.fromIconData(Icons.insert_drive_file)),
Node(
label: 'Cover Letter.docx',
key: 'pd2',
icon: NodeIcon.fromIconData(Icons.insert_drive_file)),
]),
Node(
label: 'Inspection.docx',
key: 'd1',
// icon: NodeIcon.fromIconData(Icons.insert_drive_file),
),
Node(
label: 'Invoice.docx',
key: 'd2',
icon: NodeIcon.fromIconData(Icons.insert_drive_file)),
],
),
Node(
label: 'MeetingReport.xls',
key: 'mrxls',
icon: NodeIcon.fromIconData(Icons.insert_drive_file)),
Node(
label: 'MeetingReport.pdf',
key: 'mrpdf',
icon: NodeIcon.fromIconData(Icons.insert_drive_file)),
Node(
label: 'Demo.zip',
key: 'demo',
icon: NodeIcon.fromIconData(Icons.archive)),
];
_treeViewController = TreeViewController(
children: _nodes,
selectedKey: _selectedNode,
);
super.initState();
}
ListTile _makeExpanderPosition() {
return ListTile(
title: Text('Expander Position'),
dense: true,
trailing: CupertinoSlidingSegmentedControl(
children: expansionPositionOptions,
groupValue: _expanderPosition,
onValueChanged: (ExpanderPosition newValue) {
setState(() {
_expanderPosition = newValue;
});
},
),
);
}
SwitchListTile _makeAllowParentSelect() {
return SwitchListTile.adaptive(
title: Text('Allow Parent Select'),
dense: true,
value: _allowParentSelect,
onChanged: (v) {
setState(() {
_allowParentSelect = v;
});
},
);
}
SwitchListTile _makeSupportParentDoubleTap() {
return SwitchListTile.adaptive(
title: Text('Support Parent Double Tap'),
dense: true,
value: _supportParentDoubleTap,
onChanged: (v) {
setState(() {
_supportParentDoubleTap = v;
});
},
);
}
ListTile _makeExpanderType() {
return ListTile(
title: Text('Expander Style'),
dense: true,
trailing: CupertinoSlidingSegmentedControl(
children: expansionTypeOptions,
groupValue: _expanderType,
onValueChanged: (ExpanderType newValue) {
setState(() {
_expanderType = newValue;
});
},
),
);
}
ListTile _makeExpanderModifier() {
return ListTile(
title: Text('Expander Modifier'),
dense: true,
trailing: CupertinoSlidingSegmentedControl(
children: expansionModifierOptions,
groupValue: _expanderModifier,
onValueChanged: (ExpanderModifier newValue) {
setState(() {
_expanderModifier = newValue;
});
},
),
);
}
#override
Widget build(BuildContext context) {
TreeViewTheme _treeViewTheme = TreeViewTheme(
expanderTheme: ExpanderThemeData(
type: _expanderType,
modifier: _expanderModifier,
position: _expanderPosition,
color: Colors.grey.shade800,
size: 20,
),
labelStyle: TextStyle(
fontSize: 16,
letterSpacing: 0.3,
),
parentLabelStyle: TextStyle(
fontSize: 16,
letterSpacing: 0.1,
fontWeight: FontWeight.w800,
color: Colors.blue.shade700,
),
iconTheme: IconThemeData(
size: 18,
color: Colors.grey.shade800,
),
colorScheme: Theme.of(context).brightness == Brightness.light
? ColorScheme.light(
primary: Colors.blue.shade50,
onPrimary: Colors.grey.shade900,
background: Colors.transparent,
onBackground: Colors.black,
)
: ColorScheme.dark(
primary: Colors.black26,
onPrimary: Colors.white,
background: Colors.transparent,
onBackground: Colors.white70,
),
);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
elevation: 0,
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
color: Colors.grey.shade200,
padding: EdgeInsets.all(20),
height: double.infinity,
child: Column(
children: <Widget>[
Container(
height: 300,
child: Column(
children: <Widget>[
_makeExpanderPosition(),
_makeExpanderType(),
_makeExpanderModifier(),
_makeAllowParentSelect(),
_makeSupportParentDoubleTap(),
],
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
padding: EdgeInsets.all(10),
child: TreeView(
controller: _treeViewController,
allowParentSelect: _allowParentSelect,
supportParentDoubleTap: _supportParentDoubleTap,
onExpansionChanged: (key, expanded) =>
_expandNode(key, expanded),
onNodeTap: (key) {
debugPrint('Selected: $key');
setState(() {
_selectedNode = key;
_treeViewController =
_treeViewController.copyWith(selectedKey: key);
});
},
theme: _treeViewTheme,
),
),
),
GestureDetector(
onTap: () {
debugPrint('Close Keyboard');
FocusScope.of(context).unfocus();
},
child: Container(
padding: EdgeInsets.only(top: 20),
alignment: Alignment.center,
child: Text(_treeViewController.getNode(_selectedNode) == null
? ''
: _treeViewController.getNode(_selectedNode).label),
),
)
],
),
),
),
bottomNavigationBar: SafeArea(
top: false,
child: ButtonBar(
alignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
CupertinoButton(
child: Text('Node'),
onPressed: () {
setState(() {
_treeViewController = _treeViewController.copyWith(
children: _nodes,
);
});
},
),
CupertinoButton(
child: Text('JSON'),
onPressed: () {
setState(() {
_treeViewController =
_treeViewController.loadJSON(json: US_STATES_JSON);
});
},
),
CupertinoButton(
child: Text('Toggle'),
onPressed: _treeViewController.selectedNode != null &&
_treeViewController.selectedNode.isParent
? () {
setState(() {
_treeViewController = _treeViewController
.withToggleNode(_treeViewController.selectedKey);
});
}
: null,
),
CupertinoButton(
child: Text('Edit'),
onPressed: () {
TextEditingController editingController = TextEditingController(
text: _treeViewController.selectedNode.label);
showCupertinoDialog(
context: context,
builder: (context) {
return CupertinoAlertDialog(
title: Text('Edit Label'),
content: Container(
height: 80,
alignment: Alignment.center,
padding: EdgeInsets.all(10),
child: CupertinoTextField(
controller: editingController,
autofocus: true,
),
),
actions: <Widget>[
CupertinoDialogAction(
child: Text('Cancel'),
isDestructiveAction: true,
onPressed: () => Navigator.of(context).pop(),
),
CupertinoDialogAction(
child: Text('Update'),
isDefaultAction: true,
onPressed: () {
if (editingController.text.isNotEmpty) {
setState(() {
Node _node = _treeViewController.selectedNode;
_treeViewController =
_treeViewController.withUpdateNode(
_treeViewController.selectedKey,
_node.copyWith(
label: editingController.text));
});
debugPrint(editingController.text);
}
Navigator.of(context).pop();
},
),
],
);
});
},
),
],
),
),
);
}
_expandNode(String key, bool expanded) {
String msg = '${expanded ? "Expanded" : "Collapsed"}: $key';
debugPrint(msg);
Node node = _treeViewController.getNode(key);
if (node != null) {
List<Node> updated;
if (key == 'docs') {
updated = _treeViewController.updateNode(
key,
node.copyWith(
expanded: expanded,
icon: NodeIcon(
codePoint: expanded
? Icons.folder_open.codePoint
: Icons.folder.codePoint,
color: expanded ? "blue600" : "grey700",
)),
);
} else {
updated = _treeViewController.updateNode(
key, node.copyWith(expanded: expanded));
}
setState(() {
if (key == 'docs') docsOpen = expanded;
_treeViewController = _treeViewController.copyWith(children: updated);
});
}
}
}
class ModContainer extends StatelessWidget {
final ExpanderModifier modifier;
const ModContainer(this.modifier, {Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
double _borderWidth = 0;
BoxShape _shapeBorder = BoxShape.rectangle;
Color _backColor = Colors.transparent;
Color _backAltColor = Colors.grey.shade700;
switch (modifier) {
case ExpanderModifier.none:
break;
case ExpanderModifier.circleFilled:
_shapeBorder = BoxShape.circle;
_backColor = _backAltColor;
break;
case ExpanderModifier.circleOutlined:
_borderWidth = 1;
_shapeBorder = BoxShape.circle;
break;
case ExpanderModifier.squareFilled:
_backColor = _backAltColor;
break;
case ExpanderModifier.squareOutlined:
_borderWidth = 1;
break;
}
return Container(
decoration: BoxDecoration(
shape: _shapeBorder,
border: _borderWidth == 0
? null
: Border.all(
width: _borderWidth,
color: _backAltColor,
),
color: _backColor,
),
width: 15,
height: 15,
);
}
}
const List<Map<String, dynamic>> US_STATES = [
{
"label": "A",
"children": [
{"label": "Alabama", "key": "AL"},
{"label": "Alaska", "key": "AK"},
{"label": "American Samoa", "key": "AS"},
{"label": "Arizona", "key": "AZ"},
{"label": "Arkansas", "key": "AR"}
]
},
{
"label": "C",
"children": [
{"label": "California", "key": "CA"},
{"label": "Colorado", "key": "CO"},
{"label": "Connecticut", "key": "CT"},
]
},
{
"label": "D",
"children": [
{"label": "Delaware", "key": "DE"},
{"label": "District Of Columbia", "key": "DC"},
]
},
{
"label": "F",
"children": [
{"label": "Federated States Of Micronesia", "key": "FM"},
{"label": "Florida", "key": "FL"},
]
},
{
"label": "G",
"children": [
{"label": "Georgia", "key": "GA"},
{"label": "Guam", "key": "GU"},
]
},
{
"label": "H",
"children": [
{"label": "Hawaii", "key": "HI"},
]
},
{
"label": "I",
"children": [
{"label": "Idaho", "key": "ID"},
{"label": "Illinois", "key": "IL"},
{"label": "Indiana", "key": "IN"},
{"label": "Iowa", "key": "IA"},
]
},
{
"label": "K",
"children": [
{"label": "Kansas", "key": "KS"},
{"label": "Kentucky", "key": "KY"},
]
},
{
"label": "L",
"children": [
{"label": "Louisiana", "key": "LA"},
]
},
{
"label": "M",
"children": [
{"label": "Maine", "key": "ME"},
{"label": "Marshall Islands", "key": "MH"},
{"label": "Maryland", "key": "MD"},
{"label": "Massachusetts", "key": "MA"},
{"label": "Michigan", "key": "MI"},
{"label": "Minnesota", "key": "MN"},
{"label": "Mississippi", "key": "MS"},
{"label": "Missouri", "key": "MO"},
{"label": "Montana", "key": "MT"},
]
},
{
"label": "N",
"children": [
{"label": "Nebraska", "key": "NE"},
{"label": "Nevada", "key": "NV"},
{"label": "New Hampshire", "key": "NH"},
{"label": "New Jersey", "key": "NJ"},
{"label": "New Mexico", "key": "NM"},
{"label": "New York", "key": "NY"},
{"label": "North Carolina", "key": "NC"},
{"label": "North Dakota", "key": "ND"},
{"label": "Northern Mariana Islands", "key": "MP"},
]
},
{
"label": "O",
"children": [
{"label": "Ohio", "key": "OH"},
{"label": "Oklahoma", "key": "OK"},
{"label": "Oregon", "key": "OR"},
]
},
{
"label": "P",
"children": [
{"label": "Palau", "key": "PW"},
{"label": "Pennsylvania", "key": "PA"},
{"label": "Puerto Rico", "key": "PR"},
]
},
{
"label": "R",
"children": [
{"label": "Rhode Island", "key": "RI"},
]
},
{
"label": "S",
"children": [
{"label": "South Carolina", "key": "SC"},
{"label": "South Dakota", "key": "SD"},
]
},
{
"label": "T",
"children": [
{"label": "Tennessee", "key": "TN"},
{"label": "Texas", "key": "TX"},
]
},
{
"label": "U",
"children": [
{"label": "Utah", "key": "UT"},
]
},
{
"label": "V",
"children": [
{"label": "Vermont", "key": "VT"},
{"label": "Virgin Islands", "key": "VI"},
{"label": "Virginia", "key": "VA"},
]
},
{
"label": "W",
"children": [
{"label": "Washington", "key": "WA"},
{"label": "West Virginia", "key": "WV"},
{"label": "Wisconsin", "key": "WI"},
{"label": "Wyoming", "key": "WY"}
]
},
];
String US_STATES_JSON = jsonEncode(US_STATES);
Related
suppose you a List of String List which will come from API.
now you want to show that list inside DropdownButton.
Let's say your list is like
homepage_categories": [
{
"id": 1,
"name": "Electronics",
"slug": "electronics",
"icon": "fas fa-anchor",
"image": "uploads/custom-images/electronics-2022-11-19-02-48-28-5548.png"
},
{
"id": 2,
"name": "Game",
"slug": "game",
"icon": "fas fa-gamepad",
"image": "uploads/custom-images/game-2022-11-19-02-48-48-6382.png"
},
{
"id": 3,
"name": "Mobile",
"slug": "mobile",
"icon": "fas fa-mobile-alt",
"image": "uploads/custom-images/mobile-2022-11-19-02-49-20-2538.png"
},
{
"id": 4,
"name": "Lifestyle",
"slug": "lifestyle",
"icon": "fas fa-home",
"image": "uploads/custom-images/lifestyle-2022-11-19-02-49-38-3139.png"
},
]
From this API you can easily fetch.
So the Question is How can i assign a default/initial value like Select Category or something else into that list
I have tried this...
late List<CategoryModel> category;
late String value;
#override
void initState() {
category = context.read<CategoryBrandCubit>().categoryBrandModel.category;
value = category.first.id.toString();
super.initState();
}
DropdownButton<String>(
hint: const Text('Select Status'),
isExpanded: true,
icon: const Icon(Icons.keyboard_arrow_down_rounded),
underline: const SizedBox(),
value: value,
onChanged: (String? val) {
value = val!;
bloc.add(StoreProductEventCategory(value));
print('catVal: $value');
},
items: category
.map(
(e) => DropdownMenuItem<String>(
value: e.id.toString(),
child: Text(e.name),
),
)
.toList(),
),
try this:
DropdownButton<String>(
hint: const Text('Select Status'),
isExpanded: true,
icon: const Icon(
Icons.keyboard_arrow_down_rounded),
underline: const SizedBox(),
value: "default",
onChanged: (String? val) {},
items: [
const DropdownMenuItem(
alignment: Alignment.center,
value: "default",
enabled: false,
child: Text("Select Your role"),
),
...category
.map(
(e) => DropdownMenuItem<String>(
value: e.id.toString(),
child: Text(e.name),
),
)
.toList()
],
),
The DropdownButton default value is corrosponding to the value field. If we take a look at your code we see that you assign value but it is empty:
late String value; // this is empty
DropdownButton<String>(
hint: const Text('Select Status'),
isExpanded: true,
icon: const Icon(Icons.keyboard_arrow_down_rounded),
underline: const SizedBox(),
value: value, // always the current value
onChanged: (String? val) {
value = val!;
bloc.add(StoreProductEventCategory(value));
print('catVal: $value');
},
What you have to do is asigning an initial value to value. You could do something like: value = homepage_categories[0].name
If you take a look at the official flutter documentation you can also see that the value field is described as the following:
value → T?: The value of the currently selected DropdownMenuItem.
You can read more about it here and see the full example.
fetch Two different pages api with same uniq id
I want the user_uniq_id of the API of the button and the user_uniq_id of the API of the team_list to match and show the data of its user after the match.
this code is for first File
This code is of the button that is coming from the api
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:practice/left_team.dart';
import 'package:http/http.dart' as http;
class Button extends StatefulWidget {
#override
_ButtonState createState() => _ButtonState();
}
class _ButtonState extends State<Button> {
var api = Uri.parse('http://192.***.***.***/flutter/teamApi.php');
var response;
var teamApi;
#override
void initState() {
super.initState();
fetchData();
}
fetchData() async {
response = await http.get(api);
print(response.body);
teamApi = jsonDecode(response.body);
setState(() {});
}
#override
Widget build(BuildContext context) {
var color = 0xff453658;
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xff392850),
title: Row(
children: [
InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back)),
SizedBox(
width: 10.0,
),
Text(
"Income",
style: TextStyle(fontStyle: FontStyle.italic),
),
],
),
actions: [
IconButton(
icon: Icon(Icons.person),
onPressed: () => print("open cart"),
),
],
),
body: Column(
children: [
Container(
margin: const EdgeInsets.all(20.0),
padding: const EdgeInsets.all(10.0),
decoration: BoxDecoration(
border: Border.all(width: 2, color: Color(color))),
child: Row(
children: [
Text(
"Total Income:",
style: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic),
),
SizedBox(
width: 10.0,
),
Text(
"Rs.2000",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic),
),
],
),
),
SizedBox(
height: 20.0,
),
Flexible(
child: Container(
child: GridView.count(
childAspectRatio: 1.0,
padding: EdgeInsets.only(left: 16, right: 16),
crossAxisCount: 3,
crossAxisSpacing: 18,
mainAxisSpacing: 18,
children: List.generate(
teamApi.length,
(index) => GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
LeftTeam(teamData: teamApi[index])),
);
},
child: Container(
decoration: BoxDecoration(
color: Color(0xff00ffff),
borderRadius: BorderRadius.circular(10)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Text(teamApi[index]["teamType"],
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600)),
),
],
),
),
),
),
),
),
),
],
),
);
}
}
This is API data of button
[{"teamType":"direct team","team_name":"platinum","team_number":"234","team_uniq_id":"1","team_last_update":"10-may-2021"},{"teamType":"left team","team_name":"gold","team_number":"356","team_uniq_id":"2","team_last_update":"10-may-2021"},{"teamType":"right team","team_name":"silver","team_number":"876","team_uniq_id":"3","team_last_update":"10-may-2021"}]
this is code for second file.
this is model part.
class MyData {
List<Results> user = [];
MyData.fromJson(Map<String, dynamic> json) {
// previous = json['previous'];
// next = json['next'];
if (json['results'] != null) {
user = <Results>[];
json['results'].forEach((v) {
user.add(new Results.fromJson(v));
});
}
}
}
class Results {
String user_name = "";
String user_mother_name = "";
String user_address = "";
String user_mobile = "";
String user_sponsor_id = "";
String sponsor_id = "";
String email = "";
String city = "";
String state = "";
String dob = "";
Results.fromJson(Map<String, dynamic> json) {
user_name = json['user_name'];
user_mother_name = json['user_mother_name'];
user_address = json['user_address'];
user_mobile = json['user_mobile'];
user_sponsor_id = json['user_sponsor_id'];
email = json['email'];
city = json['city'];
state = json['state'];
dob = json['dob'];
}
}
this provider of api link.
import 'dart:convert';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'package:practice/LeftTeamFile/model/myData.dart';
class MyHomePageProvider extends ChangeNotifier {
MyData? data;
Future getData(context) async {
var url = Uri.parse(
var url = Uri.parse('http://192.***.***.***/flutter/team_list.php');
var response = await http.get(url);
print("res${response.body}");
var mJson = json.decode(response.body);
this.data = MyData.fromJson(mJson);
this.notifyListeners();
this is teamList part .
import 'package:flutter/material.dart';
import 'package:practice/LeftTeamFile/provider/myHomePageProvider.dart';
import 'package:provider/provider.dart';
class TeamList extends StatefulWidget {
final teamData;
const TeamList({Key? key, this.teamData}) : super(key: key);
#override
_TeamListState createState() => _TeamListState();
}
class _TeamListState extends State<TeamList> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
Container(
padding: EdgeInsets.all(10.0),
height: 100.0,
color: Color(0xffedbf6b),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(
Icons.list_alt,
color: Colors.white,
),
Text(
widget.teamData['team_uniq_id'],
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
],
),
]),
),
SizedBox(
height: 10.0,
),
Stack(
children: [
ChangeNotifierProvider<MyHomePageProvider>(
create: (context) => MyHomePageProvider(),
child: Consumer<MyHomePageProvider>(
builder: (context, provider, child) {
if (provider.data!.team_uniq_id ==
widget.teamData['team_uniq_id']) {
print("prov $provider.data");
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
// Data table widget in not scrollable so we have to wrap it in a scroll view when we have a large data set..
child: SingleChildScrollView(
child: DataTable(
columns: [
DataColumn(
label: Text('Name'),
tooltip: 'represents if user is verified.'),
DataColumn(
label: Text('Mother_name'),
tooltip: 'represents first S no of the user'),
DataColumn(
label: Text('address'),
tooltip: 'represents Sponsor ID of the user'),
DataColumn(
label: Text('mobile'),
tooltip: 'represents User ID of the user'),
DataColumn(
label: Text('User_s_id'),
tooltip: 'represents Name of the user'),
DataColumn(
label: Text('sponsor_id'),
tooltip: 'represents Mobile of the user'),
DataColumn(
label: Text('email'),
tooltip: 'represents Date of the user'),
DataColumn(
label: Text('city'),
tooltip: 'represents Date of the user'),
DataColumn(
label: Text('state'),
tooltip: 'represents Date of the user'),
DataColumn(
label: Text('dob'),
tooltip: 'represents Date of the user'),
],
rows: provider.data!.user
.map((data) =>
// we return a DataRow every time
DataRow(
// List<DataCell> cells is required in every row
cells: [
red when unverified
DataCell(Text(data.user_name)),
DataCell(Text(data.user_mother_name)),
DataCell(Text(data.user_address)),
DataCell(Text(data.user_mobile)),
DataCell(Text(data.user_sponsor_id)),
DataCell(Text(data.sponsor_id)),
DataCell(Text(data.email)),
DataCell(Text(data.city)),
DataCell(Text(data.state)),
DataCell(Text(data.dob)),
]))
.toList(),
),
),
);
}, provider.getData(context);
return Center(child: CircularProgressIndicator());
),
),
],
),
],
),
);
}
}
this is teamlist api
[
{
"teamType": "direct Team",
"team_uniq_id": "1",
"user": [
{
"user_name": "deepak",
"user_mother_name": "Accomodation",
"user_address": "varanasi",
"user_mobile": "5678989",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
},
{
"user_name": "deepak",
"user_mother_name": "Accomodation",
"user_address": "varanasi",
"user_mobile": "5678989",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
},
{
"user_name": "deepak",
"user_mother_name": "Accomodation",
"user_address": "varanasi",
"user_mobile": "5678989",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
}
]
},
{
"teamType": "left Team",
"team_uniq_id": "2",
"user": [
{
"user_name": "Ashu",
"user_mother_name": "manju",
"user_address": "Mirzapur",
"user_mobile": "222222",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
},
{
"user_name": "Ashutodh",
"user_mother_name": "manju1",
"user_address": "Mirzapur1",
"user_mobile": "2222221",
"user_sponsor_id": "1234561",
"sponsor_id": "34561",
"email": "abc#gmai.com1",
"city": "varanasi1",
"state": "India1",
"dob": "12-5-19961"
}
]
},
{
"teamType": "Right Team",
"team_uniq_id": "3",
"user": [
{
"user_name": "tosh",
"user_mother_name": "snju",
"user_address": "Allahabad",
"user_mobile": "44444444",
"user_sponsor_id": "333456",
"sponsor_id": "6666666",
"email": "jkl#gmai.com",
"city": "lucknow",
"state": "India",
"dob": "15-3-1956"
}
]
},
{
"teamType": "Total Team",
"team_uniq_id": "4",
"user": [
{
"user_name": "tosh",
"user_mother_name": "snju",
"user_address": "Allahabad",
"user_mobile": "44444444",
"user_sponsor_id": "333456",
"sponsor_id": "6666666",
"email": "jkl#gmai.com",
"city": "lucknow",
"state": "India",
"dob": "15-3-1956"
},
{
"user_name": "deepak",
"user_mother_name": "Accomodation",
"user_address": "varanasi",
"user_mobile": "5678989",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
},
{
"user_name": "deepak",
"user_mother_name": "Accomodation",
"user_address": "varanasi",
"user_mobile": "5678989",
"user_sponsor_id": "123456",
"sponsor_id": "3456",
"email": "abc#gmai.com",
"city": "varanasi",
"state": "India",
"dob": "12-5-1996"
},
{
"user_name": "tosh",
"user_mother_name": "snju",
"user_address": "Allahabad",
"user_mobile": "44444444",
"user_sponsor_id": "333456",
"sponsor_id": "6666666",
"email": "jkl#gmai.com",
"city": "lucknow",
"state": "India",
"dob": "15-3-1956"
}
]
}
]
I feel some error is coming.
You can try to make sure you convert the object you are getting from the server to list, to be able to pass in the list into the widget
I need to create a checkbox with select all functionality , here is my sample json
[
{
"id": 1,
"name": "categories 1",
"child": [
{
"id": 29,
"name": "sub 1"
},
{
"id": 30,
"name": "sub 2"
},
{
"id": 31,
"name": "sub 3 "
}
]
},
{
"id": 2,
"name": "categories 2",
"child": [
{
"id": 23,
"name": "sub 1"
},
{
"id": 24,
"name": "sub 1"
},
{
"id": 25,
"name": "sub 1"
}
]
},
{
"id": 3,
"name": "categories 3",
"child": [
{
"id": 222,
"name": "sub 1"
},
{
"id": 229,
"name": "sub 1"
},
{
"id": 229,
"name": "sub 1"
}
]
}
]
How i need is
If I check categories 1 all under categories should be selected/unselected and if I select category 2 all under that should be selected and also individual item also need to be selected
Select all should select all checkbox in all categories
Try something like this.
Container(
child: ListView.builder(
itemCount: 50,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Wrap(
children: [
Container(
child: Icon(
Icons.check_box,
)
),
Container(
child: Text(
'Category ${index+1}'
),
),
],
),
Container(
margin: EdgeInsets.only(left: 16),
child: ListView.builder(
itemCount: 3,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index2) {
return Wrap(
children: [
Container(
child: Icon(
Icons.check_box,
)
),
Container(
child: Text(
'Subcategory ${index2+1}'
),
),
],
);
}
)
)
]
)
);
}
)
)
Then you have to put your own logic according to your requirement.
I think using this is more flexible, tree_view:
var treeView = TreeView(
parentList: [
Parent(
parent: Text('Desktop'),
childList: ChildList(
children: <Widget>[
Parent(
parent: Text('documents'),
childList: ChildList(
children: <Widget>[
Text('Resume.docx'),
Text('Billing-Info.docx'),
],
),
),
Text('MeetingReport.xls'),
Text('MeetingReport.pdf'),
Text('Demo.zip'),
],
),
),
],
);
I want to convert this API to multiable lists
it should act like the image below
https://i.stack.imgur.com/10Qld.png
Any help will be appreciated
I want to convert
1-categories.name toList
2-categories.children.name toList
3-categories.children.children_lv.name toList
4-categories.children.name.children_lv.children.name toList
and want to make every dropdown dependant to the previous one
Example:
the user should select from categories.name toList to be able to choose from 2-categories.children.name toList
API
"categories": [
{
"category_id": "1841",
"name": "Cars",
"children": [
{
"name": "Car1",
"category_id": "1845",
"children_lv": [
{
"name": "",
"category_id": "",
"children_lv": "",
"href": ""
}
],
"column": "1",
{
"name": "Car2",
"category_id": "1846",
"children_lv": [
{
"name": "Car2_1",
"category_id": "1847",
"children_lv": [
{
"name": "",
"category_id": "",
"children_lv": "",
"href": ""
}
],
},
{
"name": "Car2_2",
"category_id": "1848",
"children_lv": [
{
"name": "",
"category_id": "",
"children_lv": "",
"href": ""
}
],
}
],
}
],
},
{
"category_id": "1842",
"name": "Properties",
"children": [
{
"name": "",
"category_id": "",
"children_lv": "",
"href": ""
}
],
"column": "1",
},
{
"category_id": "1843",
"name": "Machines",
"children": [
{
"name": "",
"category_id": "",
"children_lv": "",
}
],
"column": "1",
},
{
"category_id": "1844",
"name": "Electronics",
"children": [
{
"name": "",
"category_id": "",
"children_lv": "",
"href": ""
}
],
"column": "1",
}
]
}```
the lists that should be converted are category, children and the other children_lv
**Model has been made with app.quicktype.io and it works **
List<T> list = (map['list'] as List).map<T>((e)=>T.fromMap(e));
Try with this, but replace T with Model.
Also it should have fromMap function, to parse Map<String,dynamic> to your model.
else use normal constructors
((e)=>T(a:e['a'], b:e['b']);
Here is an example:
class Model {
final String a;
final String b;
Model({this.a,this.b});
factory Model.fromMap(Map<String,dynamic> map) =>
Model(
a: map['a'],
b: map['b']
);
}
This is a model with fromMap function. You can get that function easy with plugins for AndroidStudio or VSCode.
The one I use for android studio is called DartDataClass.
Now when you have json with lists =>
{ list : [
{ "a":"we","b":"try"},
{ "a":"as","b":"dfg"},
]}
You can use code above to parse that JSON if you have create the model for it.
Map<String,dynamic> json = jsonDecode(jsonSource);
List<Model> list = (json['list'] as List).map<Model>((e)=>Model.fromMap(e)).toList();
I did an example, the same as your example, but changed some names to make it clear to you
First, you need to create the Classes that you need like this:
Example of only one class ***** the same thing applies to the other classes *****
myCategory.dart
import 'package:flutterapp/myCategory1.dart';
import 'package:json_annotation/json_annotation.dart';
part 'myCategory.g.dart';
#JsonSerializable()
class MyCategory {
String name;
List<MyCategory1> children1;
MyCategory({this.name,this.children1});
factory MyCategory.fromJson(Map<String, dynamic> json) =>
_$MyCategoryFromJson(json);
Map<String, dynamic> toJson() => _$MyCategoryToJson(this);
}
myCategory.g.dart
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'myCategory.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
MyCategory _$MyCategoryFromJson(Map<String, dynamic> json) {
return MyCategory(
name: json['name'] as String,
children1: (json['children1'] as List)
?.map((e) => e == null
? null
: MyCategory1.fromJson(e as Map<String, dynamic>))
?.toList());
}
Map<String, dynamic> _$MyCategoryToJson(MyCategory instance) =>
<String, dynamic>{'name': instance.name, 'children1': instance.children1};
the myCategory.g.dart is generic file by json_serializable,
pubspec.yaml
dependencies:
flutter:
sdk: flutter
json_serializable: ^3.4.1
dev_dependencies:
build_runner: ^1.10.0
Where I generate it with the following command
flutter pub run build_runner build --delete-conflicting-outputs
Of course, you can use another method, but I prefer this method
Now let's take a look at the most important thing:
class CategoriesWidget extends StatefulWidget {
#override
_CategoriesWidgetState createState() => new _CategoriesWidgetState();
}
class _CategoriesWidgetState extends State<CategoriesWidget> {
List<MyCategory> myNestedList;
MyCategory _selectedMyCategory;
MyCategory1 _selectedMyCategory1;
MyCategory2 _selectedMyCategory2;
#override
void initState() {
super.initState();
myNestedList =
(map['categories'] as List).map((e) => MyCategory.fromJson(e)).toList();
}
Map<String, dynamic> map = {
'categories': [
{
"name": '1',
"children1": [
{"name": '1-1'},
{
"name": '1-2',
'children2': [
{'name': '1-2-1'},
{'name': '1-2-2'}
]
}
]
},
{
"name": '2',
"children1": [
{"name": '2-1'},
{
"name": '2-2',
'children2': [
{'name': '2-2-1'},
{'name': '2-2-2'}
]
}
]
}
]
};
#override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
appBar: AppBar(
title: Text("Dropdown Categories"),
centerTitle: true,
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.grey, width: 0.5)),
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
margin: EdgeInsets.all(8),
child: DropdownButton(
isDense: true,
isExpanded: true,
hint: Text('My categories'),
underline: Container(),
items: myNestedList.map((item) {
return DropdownMenuItem(
value: item,
child: Text(item.name),
);
}).toList(),
value: _selectedMyCategory,
onChanged: (value) {
setState(() {
_selectedMyCategory = value;
if (_selectedMyCategory1 != null) {
_selectedMyCategory1 = _selectedMyCategory.children1
.firstWhere(
(element) => element == _selectedMyCategory1,
orElse: () => null);
}
});
},
),
),
_selectedMyCategory?.children1 != null &&
_selectedMyCategory.children1.length > 0
? Container(
height: 45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.grey, width: 0.5)),
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
margin: EdgeInsets.all(8),
child: DropdownButton(
isDense: true,
isExpanded: true,
hint: Text('My categories 1'),
underline: Container(),
value: _selectedMyCategory1,
items: _selectedMyCategory.children1.map((item) {
return DropdownMenuItem(
value: item,
child: Text(item.name),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedMyCategory1 = value;
if (_selectedMyCategory2 != null) {
_selectedMyCategory2 =
_selectedMyCategory1.children2.firstWhere(
(element) =>
element == _selectedMyCategory2,
orElse: () => null);
}
});
},
),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text('My categories 1')),
),
_selectedMyCategory1?.children2 != null &&
_selectedMyCategory1.children2.length > 0
? Container(
height: 45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.grey, width: 0.5)),
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
margin: EdgeInsets.all(8),
child: DropdownButton(
isDense: true,
isExpanded: true,
hint: Text('My categories 2'),
underline: Container(),
items: _selectedMyCategory1.children2.map((item) {
return DropdownMenuItem(
value: item,
child: Text(item.name),
);
}).toList(),
value: _selectedMyCategory2,
onChanged: (value) {
setState(() {
_selectedMyCategory2 = value;
});
},
),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text('My categories 2')),
),
],
),
),
);
}
}
I tried it myself, and here is the result:
Good luck
i have grid view shows all data in list and i have drop down with values like price from low to high and when user select any value then i will re-sort the list at this point all is work correctly and list updated but grid view stell with old list.
i cannot update grid view
class ProductsListState extends State<ProductsList> {
double width;
String _title;
String _selectedSort;
String _language;
ProductsListState(this._title);
List productsList;
int filter;
#override
Widget build(BuildContext context) {
MediaQueryData deviceInfo = MediaQuery.of(context);
width = deviceInfo.size.width;
_language = _language ?? AppLocalizations.of(context).tr('lang');
filter = filter ?? 1;
_selectedSort ??= getSortFilter(_language)[0];
productsList = (productsList ?? getProductsList(filter));
print(productsList);
print(filter);
var size = MediaQuery.of(context).size;
var data = EasyLocalizationProvider.of(context).data;
return EasyLocalizationProvider(
data: data,
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Color.fromRGBO(205, 14, 64, 1),
appBar:
MarketinoAppBar(title: _title, width: width, appContext: context),
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
blurRadius: 13.0,
color: Colors.black.withOpacity(.5),
offset: Offset(6.0, 7.0),
),
],
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20)),
),
),
Column(
children: <Widget>[
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 20, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text('SORT BY: '),
DropdownButton<String>(
value: _selectedSort,
onChanged: (value) {
setState(() {
productsList.sort(
(a, b) => a['price'].compareTo(b['price']));
_selectedSort = value;
filter = 2;
});
},
items: getSortFilter(_language).map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
],
),
),
Container(
child: filter == 1
? Grid(productsList, width, size)
: Grid(getProductsList(2), width, size),
)
],
)
],
),
),
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
EasylocaLizationDelegate(locale: data.locale, path: "assets/language")
],
supportedLocales: [Locale('en', 'US'), Locale('ar', 'SA')],
locale: data.savedLocale,
),
);
}
//replace by json
List getProductsList(int filter) {
List list = [];
list.add({
"id": "1",
"name": "sssss",
"imageUrl": "assets/images/Frozen Food.jpg",
"description": "qwerfghjhgfdsaasdfghnjmhgfdsa",
"price": "110",
"quantity": "1",
"isLiked": "false",
"max": "5"
});
list.add({
"id": "2",
"name": "sssss",
"imageUrl": "assets/images/Frozen Food.jpg",
"description": "qwerfghjhgfdsaasdfghnjmhgfdsa",
"price": "112",
"quantity": "1",
"isLiked": "true",
"max": "5"
});
list.add({
"id": "3",
"name": "sssss",
"imageUrl": "assets/images/Frozen Food.jpg",
"description": "qwerfghjhgfdsaasdfghnjmhgfdsa",
"price": "114",
"quantity": "1",
"isLiked": "true",
"max": "10"
});
list.add({
"id": "4",
"name": "sssssssssssssssssssssssssssssssssssssssssssssssssssssssszzzzz",
"imageUrl": "assets/images/Frozen Food.jpg",
"description": "qwerfghjhgfdsaasdfghnjmhgfdsa",
"price": "11",
"quantity": "1",
"isLiked": "false",
"max": "1"
});
list.add({
"id": "5",
"name": "sssss",
"imageUrl": "assets/images/Frozen Food.jpg",
"description": "qwerfghjhgfdsaasdfghnjmhgfdsa",
"price": "110",
"quantity": "1",
"isLiked": "false",
"max": "15"
});
switch (filter) {
case 1:
list.sort((a, b) => a['id'].compareTo(b['id']));
break;
case 2:
list.sort((a, b) => a['price'].compareTo(b['price']));
break;
}
return list;
}
List<String> getSortFilter(String language) {
if (language == 'english')
return [
"الأكثر رواجا",
"السعر من الأقل للأعلى",
"السعر من الأعلى للأقل",
"التخفيضات",
];
else
return [
"Popularty",
"Price: Low to High",
"Price: High to Low",
"Discount",
];
}
}
class Grid extends StatefulWidget {
List productsList;
var _width;
var _size;
Grid(this.productsList, this._width, this._size);
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return GridState(productsList, _width, _size);
}
}
class GridState extends State<Grid> {
List productsList;
var _width;
var _size;
GridState(this.productsList, this._width, this._size);
#override
Widget build(BuildContext context) {
// TODO: implement build
return Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new GridView.builder(
itemCount: productsList.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: _width > 600 ? 3 : 2,
childAspectRatio: _width > 600 ? 0.6 : _width > 400 ? .725 : .685,
// childAspectRatio: (_itemWidth / _itemHeight),
),
itemBuilder: (BuildContext context, int index) {
return ProductGridTile(
price: double.parse(productsList[index]['price']),
width: _size.width,
image: productsList[index]['imageUrl'],
title: productsList[index]['name'],
likeStatus: productsList[index]['isLiked'] == 'true',
max: double.parse(productsList[index]['max']),
id: int.parse(productsList[index]['id']));
}),
),
);
}
}
gridview updated after re-sort list
You are doing some operations inside the build() method, when you call setState() these operations would be called again. Check that part and also try to update the list this way:
productsList = List.from(productsList)..sort(
(a, b) => a['price'].compareTo(b['price']));