Flutter 当类用作值而不是字符串时,颤振下拉菜单失败

Flutter 当类用作值而不是字符串时,颤振下拉菜单失败,flutter,dart,Flutter,Dart,我有以下代码 import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'My App', theme: ThemeData(

我有以下代码

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'My App',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: SimpleScreen());
  }
}

class SimpleScreen extends StatefulWidget {
  @override
  _SimpleScreenState createState() => _SimpleScreenState();
}

class _SimpleScreenState extends State<SimpleScreen> {
  ItemCls currentValue = ItemCls(name: 'one', price: 1);

  List<DropdownMenuItem> _menuItems = <DropdownMenuItem>[
    DropdownMenuItem(
        child: new Container(
          child: new Text("Item#1"),
          width: 200.0,
        ),
        value: ItemCls(name: 'one', price: 1)),
    DropdownMenuItem(
        child: new Container(
          child: new Text("Item#2"),
          width: 200.0,
        ),
        value: ItemCls(name: 'two', price: 2))
  ];

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: Center(
      child: DropdownButton(
        value: currentValue,
        items: _menuItems,
        onChanged: onChanged,
        style: Theme.of(context).textTheme.title,
      ),
    ));
  }

  void onChanged(value) {
    setState(() {
      currentValue = value;
    });
   // print(value);
  }
}

class ItemCls {
  final String name;
  final double price;

  const ItemCls({
    @required this.name,
    @required this.price,
  })  : assert(name != null),
        assert(price != null);
}
导入“包装:颤振/材料.省道”;
void main()=>runApp(MyApp());
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“我的应用程序”,
主题:主题数据(
主样本:颜色。蓝色,
),
主页:SimpleScreen());
}
}
类SimpleScreen扩展StatefulWidget{
@凌驾
_SimpleScreenState createState()=>\u SimpleScreenState();
}
类_SimpleScreenState扩展了状态{
ItemCls currentValue=ItemCls(名称:“一”,价格:1);
列表_菜单项=[
下拉菜单项(
子容器:新容器(
子项:新文本(“第1项”),
宽度:200.0,
),
价值:ItemCls(名称:“一”,价格:1)),
下拉菜单项(
子容器:新容器(
子项:新文本(“第2项”),
宽度:200.0,
),
价值:ItemCls(名称:'2',价格:2))
];
@凌驾
小部件构建(构建上下文){
归还新脚手架(
正文:中(
孩子:下拉按钮(
值:当前值,
项目:\菜单项,
一旦改变:一旦改变,
样式:Theme.of(context).textTheme.title,
),
));
}
更改后无效(值){
设置状态(){
当前值=当前值;
});
//印刷品(价值);
}
}
类项CLS{
最后的字符串名;
最终双倍价格;
常数项({
@需要此名称,
@需要这个价格,
}):assert(name!=null),
断言(价格!=null);
}
这是失败的

在构建SimpleScreen(dirty, 依赖项:[[u LocalizationsScope-[GlobalKey[b1ff3], _InheritedTheme],状态:_SimpleScreenState#d473f):“包:颤振/src/material/dropdown.dart”:失败的断言:行 620位置15:'items==null | | items.isEmpty | | value==null|| items.where((DropdownMenuItem项)=>item.value==value).length ==1”:不正确


每个
下拉菜单项中的
值必须是唯一的。Dart通过两种方式确保唯一性:定义
==
运算符和调用对象上的
hashCode
。您需要将这两个项添加到
ItemCls
类:

class ItemCls{
最后的字符串名;
最终双倍价格;
常数项({
@需要此名称,
@需要这个价格,
}):assert(name!=null),
断言(价格!=null);
布尔运算符==(动态其他){
返回其他is ItemCls&&
this.name==other.name&&
this.price==其他.price;
}
@凌驾
int获取哈希代码{
//源代码的散列码算法https://www.sitepoint.com/how-to-implement-javas-hashcode-correctly/
int hashCode=1;
hashCode=(23*hashCode)+this.name.hashCode;
hashCode=(23*hashCode)+this.price.hashCode;
返回哈希码;
}
}

原因
实例
ItemCls currentValue=ItemCls(名称:“一”,价格:1)不相等
值:ItemCls(名称:'one',价格:1)),

它们有不同的地址并被视为不同的值
因此,下拉按钮认为默认值
ItemCls(名称:'one',价格:1)
在选择列表中不存在

解决方案
使用
List
包含您的选择,并将
currentValue
指向列表的第一个值

ItemCls currentValue;
  static List<ItemCls> itemList = [
    ItemCls(name: 'one', price: 1),
    ItemCls(name: 'two', price: 2)
  ];
  ...
 DropdownMenuItem<ItemCls>(
    child: new Container(
      child: new Text("Item#1"),
      width: 200.0,
    ),
    value: itemList[0]),
...
void initState() {
// TODO: implement initState
currentValue = itemList[0];
}
ItemCls当前值;
静态列表项列表=[
项目CLS(名称:“一”,价格:1),
ItemCls(名称:'2',价格:2)
];
...
下拉菜单项(
子容器:新容器(
子项:新文本(“第1项”),
宽度:200.0,
),
值:itemList[0]),
...
void initState(){
//TODO:实现initState
currentValue=itemList[0];
}
工作演示

完整代码

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'My App',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: SimpleScreen());
  }
}

class SimpleScreen extends StatefulWidget {
  @override
  _SimpleScreenState createState() => _SimpleScreenState();
}

class _SimpleScreenState extends State<SimpleScreen> {
  ItemCls currentValue;
  static List<ItemCls> itemList = [
    ItemCls(name: 'one', price: 1),
    ItemCls(name: 'two', price: 2)
  ];

  List<DropdownMenuItem<ItemCls>> _menuItems = <DropdownMenuItem<ItemCls>>[
    DropdownMenuItem<ItemCls>(
        child: new Container(
          child: new Text("Item#1"),
          width: 200.0,
        ),
        value: itemList[0]),
    DropdownMenuItem<ItemCls>(
        child: new Container(
          child: new Text("Item#2"),
          width: 200.0,
        ),
        value: itemList[1])
  ];

  @override
  void initState() {
    // TODO: implement initState
    currentValue = itemList[0];
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: Center(
      child: DropdownButton<ItemCls>(
        value: currentValue,
        items: _menuItems,
        onChanged: onChanged,
        style: Theme.of(context).textTheme.title,
      ),
    ));
  }

  void onChanged(value) {
    setState(() {
      currentValue = value;
    });
    // print(value);
  }
}

class ItemCls {
  final String name;
  final double price;

  const ItemCls({
    @required this.name,
    @required this.price,
  })  : assert(name != null),
        assert(price != null);
}
导入“包装:颤振/材料.省道”;
void main()=>runApp(MyApp());
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“我的应用程序”,
主题:主题数据(
主样本:颜色。蓝色,
),
主页:SimpleScreen());
}
}
类SimpleScreen扩展StatefulWidget{
@凌驾
_SimpleScreenState createState()=>\u SimpleScreenState();
}
类_SimpleScreenState扩展了状态{
项目CLS当前值;
静态列表项列表=[
项目CLS(名称:“一”,价格:1),
ItemCls(名称:'2',价格:2)
];
列表_菜单项=[
下拉菜单项(
子容器:新容器(
子项:新文本(“第1项”),
宽度:200.0,
),
值:itemList[0]),
下拉菜单项(
子容器:新容器(
子项:新文本(“第2项”),
宽度:200.0,
),
值:itemList[1])
];
@凌驾
void initState(){
//TODO:实现initState
currentValue=itemList[0];
}
@凌驾
小部件构建(构建上下文){
归还新脚手架(
正文:中(
孩子:下拉按钮(
值:当前值,
项目:\菜单项,
一旦改变:一旦改变,
样式:Theme.of(context).textTheme.title,
),
));
}
更改后无效(值){
设置状态(){
当前值=当前值;
});
//印刷品(价值);
}
}
类项CLS{
最后的字符串名;
最终双倍价格;
常数项({
@需要此名称,
@需要这个价格,
}):assert(name!=null),
断言(价格!=null);
}