【问题标题】:I want to check if any Widget exist in a List?我想检查列表中是否存在任何小部件?
【发布时间】:2019-08-31 10:26:42
【问题描述】:

我想从列表加载页面,当用户点击抽屉中的项目时,他可以转到该页面(如果它已经打开),否则小部件将加载到所选页面中。 但我找不到该小部件是否已存在于列表中 if(myList.contains(Widget1())) => print('it exist'); 一个人告诉我覆盖 hashCodeoperator==

class Widget6 extends StatelessWidget {
  final String title = 'Widget6';

  final Icon icon = Icon(Icons.assessment); 



      @override
  Widget build(BuildContext context) {
    return Center(
      child: icon,
    );
  }

 @override
      bool operator ==(dynamic other) {
        final Widget6 typedOther = other;
        return title == typedOther.title && icon == typedOther.icon;
      }

      @override
          int get hashCode => hashValues(title, icon);
}

如果我这样做,我就不能对这些小部件使用任何子小部件。获取异常,例如:type 'Center' is not a subtype of type 'Widget6'。我从颤振画廊复制了这个我没有找到好的文档/指南。对不起,我是初学者。

下面的完整代码

class _MyHomePageState extends State<MyHomePage> {
  List pageList = [
    Widget1(),
    Widget2(),
    Widget3(),
    Widget4(),
  ];

  PageController _pageController;

  int _selectedIndex = 0;

  @override
  void initState() {
    _pageController = PageController(
      initialPage: _selectedIndex,
    );
    super.initState();
  }

  void navigatePage(Widget widget) {
// problem is here
    if (pageList.contains(widget)) {
      _pageController.animateToPage(pageList.indexOf(widget, 0),
          duration: Duration(milliseconds: 300), curve: Curves.ease);
    }

    else {
      setState(() {
        pageList.removeAt(_pageController.page.toInt());
        pageList.insert(_pageController.page.toInt(), widget);
      });
      _pageController.animateToPage(_pageController.page.toInt(),
          duration: Duration(milliseconds: 300), curve: Curves.ease);
    }
    Navigator.pop(context);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: Drawer(
        child: ListView(
          children: <Widget>[
            ListTile(
              title: Text('Widget1'),
              onTap: () => navigatePage(
                Widget1(),
              ),
            ),
            ListTile(
              title: Text('Widget2'),
              onTap: () => navigatePage(
                Widget2(),
              ),
            ),
            ListTile(
              title: Text('Widget3'),
              onTap: () => navigatePage(
                Widget3(),
              ),
            ),
            ListTile(
              title: Text('Widget4'),
              onTap: () => navigatePage(
                Widget4(),
              ),
            ),
            ListTile(
              title: Text('Widget5'),
              onTap: () => navigatePage(
                Widget5(),
              ),
            ),
            ListTile(
              title: Text('Widget6'),
              onTap: () => navigatePage(
                Widget6(),
              ),
            ),
          ],
        ),
      ),
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: PageView.builder(
        onPageChanged: (newPage) {
          setState(() {
            this._selectedIndex = newPage;
          });
        },
        controller: _pageController,
        itemBuilder: (context, index) {
          return Container(
            child: pageList[index],
          );
        },
        itemCount: pageList.length,
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _selectedIndex,
        onTap: (index) => setState(() {
          _selectedIndex = index;
          _pageController.animateToPage(index,
              duration: Duration(milliseconds: 300), curve: Curves.ease);
        }),
        items: pageList.map((page) {
          return BottomNavigationBarItem(
              backgroundColor: Colors.deepOrangeAccent,
              icon: page.icon,
              title: Text(page.title));
        }).toList(),
      ),
    );
  }
}

这里的虚拟小部件列表

class Widget1 extends StatelessWidget {
  final String title = 'Widget1';

  final Icon icon = Icon(Icons.school);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: icon,
    );
  }
}

class Widget2 extends StatelessWidget {
  // only title and icon are changed
}

class Widget3 extends StatelessWidget {
  // only title and icon are changed
}

class Widget4 extends StatelessWidget {
  // only title and icon are changed
}

class Widget5 extends StatelessWidget {
 // only title and icon are changed
}
class Widget6 extends StatelessWidget {
 // only title and icon are changed
}

【问题讨论】:

  • 一种解决方案是在您的小部件中使用一个键,然后使用 removeWhere 等方法来查找/删除...特定的小部件。
  • 对不起,如果我不明白。为什么要使用 if(page List.contains(widget)? Widget 不在 List pageList=[Widget1(),...] 中创建?
  • @NorbertoMartínAfonso 要检查页面是否已打开,基于此我导航到该页面或打开所选页面。
  • 您是否想过使用 SharedPreferences 并保存访问过的页面,例如:widgetonevisited=true 并在 initstate 时检查 SharedPreferences?
  • @NorbertoMartínAfonso 如果我在那些虚拟小部件中使用operator ==,现在一切正常。但我得到了一个例外,@ 987654329@。更具体地说,我不能使用任何子小部件。

标签: flutter


【解决方案1】:

好的,我找到了解决方案。它与operator== 覆盖有关 我错过了这条线if (runtimeType != other.runtimeType) return false; 整个代码保持不变。

@override
  // ignore: hash_and_equals
  bool operator ==(dynamic other) {
    if (runtimeType != other.runtimeType) return false;
    final Widget6 typedOther = other;
    return title == typedOther.title;
  }

【讨论】:

    【解决方案2】:

    @Ahmed 抱歉回复晚了,我决定将其放在答案而不是评论中。

    一个解决方案是你的,覆盖==,但我正在考虑使用Key,而不是使用contains方法,使用类似的东西:

    if(myList.indexWhere((Widget widget)=> widget.key==_key) != -1)...
    

    建议

    您可以将图标和标题存储为地图或模块,而不是制作 6 个不同的 Widget。

    你可以创建另一个文件,像这样说module.dart

    class Module {
      final String title;
      final Icon icon;
    
      Module(this.title, this.icon);
    
      @override
      int get hashCode => hashValues(title.hashCode, icon.hashCode);
    
      @override
      bool operator ==(other) {
        if (!identical(this, other)) {
          return false;
        }
        return other is Module &&
            this.title.compareTo(other.title) == 0 &&
            this.icon == other.icon;
      }
    }
    
    

    然后创建另一个构建页面的文件,说mywidget.dart,如下所示:

    class MyWidget extends StatelessWidget {
      final Module module;
      MyWidget({Key key,@required this.module}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: module.icon,
        );
      }
    }
    

    然后在每个 ListTile 的 onTap 上,像这样导航:

    ...
    ListTile(
        title: Text('Widget1'),
        onTap: () => navigatePage(
         MyWidget(module: Module('Widget1', Icon(Icons.school)),)
        ),
      ),
    ...
    

    因此,您无需存储小部件,而是存储您声明的类型(此处模块)。

    您还可以使用列表的map 为每个模块构建ListView 中的每个ListTile,而不是一个一个地构建。 (如果抽屉上的每件物品都相似),像这样:

     List<Module> myTabs = [
          Module('Widget1', Icon(Icons.school)),
          Module('Widget2', Icon(Icons.home)),
        ];
    ...
        Drawer(
          child: ListView(
            children:myTabs.map((Module module)=> ListTile(
              title:Text( module.title),
              onTap: navigatePage(MyWidget(module: module,)),
            )).toList(),
          ) ,
        );
    ...
    

    【讨论】:

    • 一点也不晚,感谢您的回答。我一定会试试这个,让你知道。你能告诉我有什么充分的理由不将Widget 存储在列表中可能是性能问题吗?
    • @Ahmed 希望对您有所帮助,对于您的问题,我将您推荐给this answer,我之所以喜欢它的原因是,我想比较模块实例而不是小部件是一个更好的选择,而且如果您想要稍微改变一下小部件(比如在图标旁边添加标题),你只需要做一次而不是 6 次等等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-02
    • 1970-01-01
    • 2018-02-02
    相关资源
    最近更新 更多