Flutter-将动态项目作为键传递 [英] Flutter - Pass a dynamic Item as Key
问题描述
当我在 flutter run
调试模式下运行时,以下代码显示以下错误:
The code below is displaying the following error when I run in flutter run
debug mode:
类型列表"不是值"的字符串"类型的子类型,其中
当我在发布模式下运行 flutter run --release
时,该错误不会出现,并且我可以识别出我选择删除的项目.
When I run in release mode flutter run --release
the error does not appear and I can identify the item I selected to delete.
问题在第39行: key:新的Key(i)
键
仅接受字符串作为值:键(字符串值)→键
The key
only accepts string as value:
Key(String value) → Key
但是我要传递一个看来是动态项目的 List
:动态i
But I'm passing a List
that appears to be a dynamic item:
dynamic i
但是我需要在 Key
上传递一个 List
,以便能够识别被排除的物品.
But I need to pass a List
on the Key
to be able to identify what the excluded item will be.
如何在调试模式下解决此问题?
How could I solve this problem in debug mode?
为什么会发生这种现象,而在发布模式下却没有出现此问题?
And why is this behavior happening and in the release mode the problem does not occur?
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
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> {
List<Widget> tiles;
List foos = [];
@override
void initState() {
this.foos = [[0, 'foo1'], [1, 'foo2'], [2, 'foo3'], [3, 'foo4']];
this.tiles = buildTile(this.foos);
super.initState();
}
//function
List<Widget> buildTile(List list) {
var x = [];
for(var i in list) {
x.add(
new ItemCategory(
key: new Key(i),
category: i[1],
onPressed: () {
setState(() {
list.removeAt(i[0]);
var list2 = [];
for(var x = 0; x < list.length; x++) {
list2.add([ x, list[x][1] ]);
}
this.tiles = buildTile(list2);
});
},
)
);
}
return x;
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Categories'),
),
body: new ListView(
padding: new EdgeInsets.only(top: 8.0, right: 0.0, left: 0.0),
children: this.tiles
)
);
}
}
class ItemCategory extends StatefulWidget {
ItemCategory({ Key key, this.category, this.onPressed}) : super(key: key);
final String category;
final VoidCallback onPressed;
@override
ItemCategoryState createState() => new ItemCategoryState();
}
class ItemCategoryState extends State<ItemCategory> with TickerProviderStateMixin {
ItemCategoryState();
AnimationController _controller;
Animation<double> _animation;
double flingOpening;
bool startFling = true;
void initState() {
super.initState();
_controller = new AnimationController(duration:
const Duration(milliseconds: 246), vsync: this);
_animation = new CurvedAnimation(
parent: _controller,
curve: new Interval(0.0, 1.0, curve: Curves.linear),
);
}
void _move(DragUpdateDetails details) {
final double delta = details.primaryDelta / 304;
_controller.value -= delta;
}
void _settle(DragEndDetails details) {
if(this.startFling) {
_controller.fling(velocity: 1.0);
this.startFling = false;
} else if(!this.startFling){
_controller.fling(velocity: -1.0);
this.startFling = true;
}
}
@override
Widget build(BuildContext context) {
final ui.Size logicalSize = MediaQuery.of(context).size;
final double _width = logicalSize.width;
this.flingOpening = -(48.0/_width);
return new GestureDetector(
onHorizontalDragUpdate: _move,
onHorizontalDragEnd: _settle,
child: new Stack(
children: <Widget>[
new Positioned.fill(
child: new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new Container(
decoration: new BoxDecoration(
color: new Color(0xFFE57373),
),
child: new IconButton(
icon: new Icon(Icons.delete),
color: new Color(0xFFFFFFFF),
onPressed: widget.onPressed
)
),
],
),
),
new SlideTransition(
position: new Tween<Offset>(
begin: Offset.zero,
end: new Offset(this.flingOpening, 0.0),
).animate(_animation),
child: new Container(
decoration: new BoxDecoration(
border: new Border(
top: new BorderSide(style: BorderStyle.solid, color: Colors.black26),
),
color: new Color(0xFFFFFFFF),
),
margin: new EdgeInsets.only(top: 0.0, bottom: 0.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Expanded(
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Container(
margin: new EdgeInsets.only(left: 16.0),
padding: new EdgeInsets.only(right: 40.0, top: 4.5, bottom: 4.5),
child: new Row(
children: <Widget>[
new Container(
margin: new EdgeInsets.only(right: 16.0),
child: new Icon(
Icons.brightness_1,
color: Colors.black,
size: 35.0,
),
),
new Text(widget.category),
],
)
)
],
),
)
],
),
)
),
],
)
);
}
}
推荐答案
您应该知道-release
标志会删除所有 assert
并从应用程序中进行类型检查.这就是为什么您的错误消失的原因.断言/类型检查在这里仅用作更好的开发工具,无需实际运行应用程序即可查看潜在错误.发行版本不需要知道这些.
You should know that --release
flag remove all assert
and type checking from the app. Which is why your error disappear.
Asserts/Type Check are here only as tools for a better development to see potential errors without having to actually run the app. A release build don't need to be aware of these.
在您的情况下,出现问题是因为您没有在 List< Widget>中指定
;默认将 list
的通用"类型.buildTile(列表列表) list
设置为 List< dynamic>
.因此,编译器不知道列表中的元素是什么类型,因此允许您执行 new Key(i)
.因为 i
可能是 String
.
In your case, the problem occurs because you haven't specified the 'generic' type of list
in List<Widget> buildTile(List list)
; which default list
to List<dynamic>
.
Consequence, the compiler don't know what type is an element of your list and therefore allows you to do new Key(i)
. Because i
may be a String
.
将函数原型修改为 List< Widget>buildTile(List< List< String>>列表)
(此处为列表的 real 类型)将允许编译器向您发出潜在错误的警报.该错误是 List< String>不能被分配为在
.新键(i)
上键入String
Modifying your function prototype to List<Widget> buildTile(List<List<String>> list)
(which is the real type of your list here) will allow the compiler to alert you from a potential error.
And that error is List<String> can't be assigned to type String
on new Key(i)
.
要解决该错误,您可以改为执行 new Key(i.toString()
),该键将序列化您的列表(由于是原始对象).
To fix that error, you can instead do new Key(i.toString()
, which will serialize your list (thanks to being primitive objects).
或使用从Key继承的 ObjectKey
,但不是使用 String
作为参数,而是采用了 Object
,例如键:新的ObjectKey(i)
Or use the ObjectKey
that inherit from Key, but instead of using String
as parameter, it takes anObject
such as key: new ObjectKey(i)
这篇关于Flutter-将动态项目作为键传递的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!