#flutter #dart
#flutter #dart
Вопрос:
Я хочу преобразовать этот API в многоуровневые списки
это должно действовать как изображение ниже
https://i.stack.imgur.com/10Qld.png
Любая помощь будет оценена
Я хочу преобразовать
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
и хотите, чтобы каждый выпадающий список зависел от предыдущего
Пример:
пользователь должен выбрать из categories.name Включить список, чтобы иметь возможность выбирать из 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 **
Ответ №1:
List<T> list = (map['list'] as List).map<T>((e)=>T.fromMap(e));
Попробуйте использовать это, но замените T на Model.
Также у него должна быть fromMap
функция для синтаксического анализа Map<String,dynamic>
в соответствии с вашей моделью.
в противном случае используйте обычные конструкторы
((e)=>T(a:e['a'], b:e['b']);
Вот пример:
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']
);
}
Это модель с fromMap
функцией. Вы можете легко получить эту функцию с помощью плагинов для AndroidStudio или VSCode.
Тот, который я использую для Android Studio, называется DartDataClass
.
Теперь, когда у вас есть json со списками =>
{ list : [
{ "a":"we","b":"try"},
{ "a":"as","b":"dfg"},
]}
Вы можете использовать приведенный выше код для анализа этого JSON, если у вас есть созданная для него модель.
Map<String,dynamic> json = jsonDecode(jsonSource);
List<Model> list = (json['list'] as List).map<Model>((e)=>Model.fromMap(e)).toList();
Комментарии:
1. отредактированный сейчас, я написал это из своей головы, проверил сейчас в IDE
Ответ №2:
Я привел пример, аналогичный вашему примеру, но изменил некоторые имена, чтобы вам было понятнее
Сначала вам нужно создать нужные вам классы следующим образом:
Пример только одного класса ***** то же самое относится и к другим классам *****
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};
myCategory.g.dart
является универсальным файлом с помощью json_serializable,
pubspec.yaml
dependencies:
flutter:
sdk: flutter
json_serializable: ^3.4.1
dev_dependencies:
build_runner: ^1.10.0
Где я генерирую их с помощью следующей команды
flutter pub run build_runner build --delete-conflicting-outputs
Конечно, вы можете использовать другой метод, но я предпочитаю этот метод
Теперь давайте взглянем на самое важное:
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 amp;amp;
_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 amp;amp;
_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')),
),
],
),
),
);
}
}
Я попробовал это сам, и вот результат:
Удачи