我目前正在开发电子商务移动应用。
现在我正在处理我的导航。有一堆类别可以有子类别,而子类别可以有自己的子类别。我通过 app init 上的 API 检索所有类别的列表,然后将其存储。
这是我的数据集示例:
{
"id":"41490",
"name":"Electrical Equipment",
"subCategories":[
{
"id":"41492",
"name":"Breakers",
"subCategories":[
{
"id":"167542",
"name":"1 Pole",
"subCategories":[
{
"id":"167577",
"name":"15 Amp",
"subCategories":null
},
{
"id":"167585",
"name":"20 Amp",
"subCategories":null
},
{
"id":"167600",
"name":"30 Amp",
"subCategories":null
},
{
"id":"167606",
"name":"40 Amp",
"subCategories":null
}
]
},
我正在使用列表视图和列表视图构建器来制作我的类别列表。 列表视图构建器还调用递归函数来创建子类别。 我设法让所有内容都动态生成,这意味着如果我们在网站上添加一堆类别,那么应用程序将通过 API 自动更新。
我现在的问题是,当我单击类别时,navDrawer 不会重绘。我必须关闭类别并重新打开它们以使其重绘。我需要一些新概念,在这个概念上摸索了一段时间。
我认为我的代码结构可能有问题,因为我在状态之外初始化了类别。
这是我的 navDrawer 类:
class navDrawer extends StatefulWidget {
bool _expandCategories = false;
bool _expandAccount = false;
List _categories;
var _categoryList;
List _tempSubCats;
void flickCategories(){
//_expandCategories = !_expandCategories;
//sleep(const Duration(microseconds: 100));
//_expandCategories = !_expandCategories;
}
void setCategories(List categories){
_categories = categories;
int catCount = categories.length;
_categoryList = new ListView.builder(
//shrinkWrap: true,
//physics: ClampingScrollPhysics(),
padding:EdgeInsets.all(0.0),
itemCount: catCount,
itemBuilder: (BuildContext context, int index) => buildCategories(context, index),
);
}
Widget buildCategories(BuildContext context, int index){
if(_categories[index]['subCategories']!=null){
if(idHandler.isIdOpen(_categories[index]['id'])){
_tempSubCats = [];
buildSubCategories(_categories[index],2);
ListView subCategories = new ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: _tempSubCats.length,
itemBuilder: (BuildContext ct, int i){
return _tempSubCats[i];
}
);
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 30.0,
child: ListTile(
title: Row(
children: [
Text(" " + _categories[index]['name']),
Transform.rotate(
angle: -math.pi/2,
child:
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
)
]
),
onTap: () {
flickCategories();
idHandler.toggleId(_categories[index]['id']);
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
),
MediaQuery.removePadding(
removeTop: true,
removeBottom: true,
removeLeft: true,
removeRight: true,
context: context,
child: subCategories
)
]
);
} else {
return Container(
height: 30.0,
child: ListTile(
title: Row(
children: [
Text(" " + _categories[index]['name']),
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
]
),
onTap: () {
flickCategories();
idHandler.toggleId(_categories[index]['id']);
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
);
}
} else {
return Container(
height: 30.0,
child: ListTile(
title: Text(" "+_categories[index]['name']),
onTap: () {
//TODO: implement category navigation
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
);
}
}
void buildSubCategories(var parent, int depth){
if(parent['subCategories']!=null){
List subCategoryList = parent['subCategories'];
int subCategoryCount = subCategoryList.length;
//Column subCats = new Column();
if(idHandler.isIdOpen(parent['id'])) {
for (var i = 0; i < subCategoryCount; i++) {
String formattedCategory = indentCategory(parent['subCategories'][i]['name'], depth);
_tempSubCats.add(
parent['subCategories'][i]['subCategories']!=null ?
Container(
height:20.0,
child:
ListTile(
title: idHandler.isIdOpen(parent['subCategories'][i]['id']) ?
Row(
children:[
Text(formattedCategory),
Transform.rotate(
angle:-math.pi/2,
child:
Transform.scale(
scale:0.75,
child:
Icon(Icons.arrow_back)
)
)
]
)
:
Row(
children: [
Text(formattedCategory),
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
]
),
onTap: (){
flickCategories();
idHandler.toggleId(parent['subCategories'][i]['id']);
}
)
)
:
Container(
height:20.0,
child:
ListTile(
title: Text(formattedCategory),
onTap: (){
//TODO: implement category navigation
}
)
)
);
buildSubCategories(parent['subCategories'][i], depth+1);
}
}
}
}
String indentCategory(String input, int amount){
String output='';
for(var i=0; i<amount; i++){
output += ' ';
}
output+=input;
return output;
}
@override
_navDrawerState createState() => _navDrawerState();
}
class _navDrawerState extends State<navDrawer>{
@override
Widget build(BuildContext Context){
return Drawer(
child:
Container(
padding:EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 5),
child:
Column(
children:[
Container(
height:80.0,
width:double.infinity,
child:
DrawerHeader(
child: Text('Menu'),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[
Colors.grey,
Colors.red
])
)
),
margin:EdgeInsets.all(0.0),
padding:EdgeInsets.all(0.0)
),
Expanded(
child:
ListView(
padding:EdgeInsets.zero,
children: <Widget>[
widget._expandCategories?
Column(
children:[
Container(
height:40.0,
child: ListTile(
title: Row(
children: [
Text('Categories'),
Transform.rotate(
angle: -math.pi/2,
child:
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
)
]
),
onTap:() {
_expandCat();
}
)
),
MediaQuery.removePadding(
removeTop:true,
context: context,
child:
SizedBox(
height:300.0,
child: widget._categoryList,
)
)
]
)
:Container(
height:40.0,
child:
ListTile(
title: Row(
children: [
Text('Categories'),
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
]
),
onTap:(){
_expandCat();
//Update state of the app
}
),
margin:EdgeInsets.all(0.0),
padding:EdgeInsets.all(0.0)
),
Container(
height:40.0,
child:
ListTile(
title:Text('Your quotes'),
onTap:(){
//Update state of the app
}
),
margin:EdgeInsets.all(0.0),
padding:EdgeInsets.all(0.0)
),
widget._expandAccount?
Column(
children:[
Container(
height:40.0,
child:
ListTile(
title: Row(
children:[
Text('Your account'),
Transform.rotate(
angle:-math.pi/2,
child:
Transform.scale(
scale:0.75,
child:
Icon(Icons.arrow_back)
)
)
]
),
onTap:(){
_expandAcc();
}
),
margin:EdgeInsets.all(0.0),
padding:EdgeInsets.all(0.0)
),
Container(
height:30.0,
child:
ListTile(
title:Text(' Your Information'),
onTap:(){
}
)
),
Container(
height:30.0,
child:
ListTile(
title:Text(' Your Address'),
onTap:(){
}
)
),
Container(
height:30.0,
child:
ListTile(
title:Text(' Listed Equipment'),
onTap:(){
}
)
),
Container(
height:30.0,
child:
ListTile(
title:Text(' Add Equipment'),
onTap:(){
}
)
),
]
)
:Container(
height:40.0,
child:
ListTile(
title: Row(
children:[
Text('Your account'),
Transform.scale(
scale:0.75,
child:
Icon(Icons.arrow_back)
)
]
),
onTap:(){
_expandAcc();
}
),
margin:EdgeInsets.all(0.0),
padding:EdgeInsets.all(0.0)
)
]
),
)
]
)
)
);
}
void _expandCat(){
setState((){
widget._expandCategories=!widget._expandCategories;
});
}
void _expandAcc(){
setState((){
widget._expandAccount=!widget._expandAccount;
});
}
}
注意:idHandler 是 main.dart 的公共成员。
注2:flickCategories() 是我更新状态的尝试之一。
如果我单击“电气设备”,则必须单击“类别”两次才能使其重绘,并且必须滚动回列表中的位置。
那么,当我的某个类别被点击时,我该如何更新状态?
我需要像有状态类别小部件之类的东西吗?
我正在尝试使用箭头和缩进等使其看起来响应。
答案 0 :(得分:0)
这是我自己想出来的。
我需要制作一个 productCategory 有状态小部件并从小部件内部更新其状态。
每个 productCategory 小部件都有一个代表子类别的列表。在我的递归过程中,我添加到每个 productCategory 的 subCategories。
productCategory 小部件正确重绘自身,因为我调用了 setState(),它具有将滚动位置保持在原来位置的额外好处。
这是我的 productCategory 小部件:
class productCategory extends StatefulWidget{
String _id = '';
String _name = '';
List<productCategory> _subCategories = [];
productCategory(String id, String name){
_id = id;
_name = name;
}
void addAllSubCategories(List<productCategory> subCats){
_subCategories.addAll(subCats);
}
void addSubCategory(productCategory cat){
_subCategories.add(cat);
}
void setName(String name){
_name = name;
}
void setId(String id){
_id = id;
}
@override
_productCategoryState createState() => _productCategoryState();
}
class _productCategoryState extends State<productCategory>{
@override
Widget build(BuildContext context) {
if(widget._subCategories.isNotEmpty){
if(idHandler.isIdOpen(widget._id)){
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 30.0,
child: ListTile(
title: Row(
children: [
Text(widget._name),
Transform.rotate(
angle: -math.pi/2,
child:
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
)
]
),
onTap: () {
setState((){
idHandler.toggleId(widget._id);
});
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
),
MediaQuery.removePadding(
removeTop: true,
removeBottom: true,
removeLeft: true,
removeRight: true,
context: context,
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.all(0.0),
itemCount: widget._subCategories.length,
itemBuilder: (BuildContext context, int index){
return widget._subCategories[index];
}
)
)
]
);
} else {
return Container(
height: 30.0,
child: ListTile(
title: Row(
children: [
Text(widget._name),
Transform.scale(
scale: 0.75,
child:
Icon(Icons.arrow_back)
)
]
),
onTap: () {
setState((){
idHandler.toggleId(widget._id);
});
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
);
}
} else {
return Container(
height: 30.0,
child: ListTile(
title: Text(widget._name),
onTap: () {
//TODO: implement category navigation
}
),
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(0.0)
);
}
}
}