【问题标题】:flutter delete item from listview从列表视图中颤动删除项目
【发布时间】:2019-08-04 04:41:07
【问题描述】:

我试过了

编写您的第一个 Flutter 应用,第 2 部分 flutter app page 5

我现在对此应用程序有疑问。我想从该 List onLongPress 中删除一个条目,如下所示:

 onLongPress: () {
              setState(() {
                _saved.remove(pair);
              });
            },

这将从列表中删除该项目,但不会更新屏幕。返回家中并重新打开此路线后,新项目没有被删除。但是如何在没有用户重新打开页面的情况下触发此页面上的更新。

 import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Startup Name Generator',
      home: RandomWords(),
      theme: new ThemeData(
        primaryColor: Colors.orange,
      ),
    );
  }
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

class RandomWordsState extends State<RandomWords> {
  final List<WordPair> _suggestions = <WordPair>[];
  final TextStyle _biggerFont = const TextStyle(fontSize: 18);
  final Set<WordPair> _saved = new Set<WordPair>();

  _buildSuggestions() {
    return ListView.builder(
      padding: const EdgeInsets.all(16),
      itemBuilder: (context, i) {
        if (i.isOdd) return Divider();

        final index = i ~/ 2;
        if (index >= _suggestions.length) {
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_suggestions[index]);
      },
    );
  }

  Widget _buildRow(WordPair pair) {
    final bool alreadySaved = _saved.contains(pair);

    return ListTile(
      title: Text(pair.asPascalCase, style: _biggerFont),
      trailing: new Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      onTap: () {
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Startup Name Generator"),
        actions: <Widget>[
          new IconButton(icon: const Icon(Icons.list), onPressed: _pushSaved),
        ],
      ),
      body: _buildSuggestions(),
    );
  }

  void _pushSaved() {
    Navigator.of(context).push(
      new MaterialPageRoute(
        builder: (BuildContext context) {
          final Iterable<ListTile> tiles = _saved.map(
            (WordPair pair) {
              return new ListTile(
//this is the delete operation
                onLongPress: () {
                  setState(() {
                    _saved.remove(pair);
                  });
                },
                title: new Text(
                  pair.asPascalCase,
                  style: _biggerFont,
                ),
              );
            },
          );

          final List<Widget> divided = ListTile.divideTiles(
            context: context,
            tiles: tiles,
          ).toList();

          return new Scaffold(
            appBar: new AppBar(
              title: const Text('Saved Suggestions'),
            ),
            body: new ListView(children: divided),
          );
        },
      ),
    );
  }
}

【问题讨论】:

    标签: listview flutter


    【解决方案1】:

    2019-11月最新方式

    更多信息https://www.youtube.com/watch?v=iEMgjrfuc58

                     ListView.builder/GridView.builder(
                       itemBuilder: (BuildContext context, int index){
                          return Dismissible(
                          key: Key(selectServiceLocations[index].toString()),
                          onDismissed: (direction) {
                            setState(() {
                             selectServiceLocations.removeAt(index);
                            });
                          },
                         child: Container(...)
    }
    )
    

    【讨论】:

    【解决方案2】:

    那是因为您正在创建一个新的 MaterialPageRoute。

    试试这个:

    onLongPress: () {
      _saved.remove(pair);
      Navigator.of(context).pop();
      _pushSaved();
    },
    


    使用此解决方案,您仍然会看到视图发生变化。如果你想防止这种情况发生,你需要一个新的有状态页面,并进行一些重构:

    • 使您的 _saved 项目全局化(仅适用于本示例)
    • 删除_pushSaved方法
    • 更新用于调用_pushSaved函数的onPressed函数
    • 添加有状态的DetailPage 而不是_pushSaved 方法

    像这样:

    import 'package:flutter/material.dart';
    import 'package:english_words/english_words.dart';
    
    void main() => runApp(new MyApp());
    
    // create a global saved set
    Set<WordPair> savedGlobal = new Set<WordPair>();
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Startup Name Generator',
          home: new RandomWords(),
        );
      }
    }
    
    class RandomWords extends StatefulWidget {
      @override
      RandomWordsState createState() => new RandomWordsState();
    }
    
    class RandomWordsState extends State<RandomWords> {
      final List<WordPair> _suggestions = <WordPair>[];
      final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: const Text('Startup Name Generator'),
            actions: <Widget>[
              // change the onPressed function
              new IconButton(icon: const Icon(Icons.list), onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => DetailPage()
                  )
                );
              }),
            ],
          ),
          body: _buildSuggestions(),
        );
      }
    
      Widget _buildSuggestions() {
        return new ListView.builder(
          padding: const EdgeInsets.all(16.0),
          itemBuilder: (BuildContext _context, int i) {
            if (i.isOdd) {
              return const Divider();
            }
            final int index = i ~/ 2;
            if (index >= _suggestions.length) {
              _suggestions.addAll(generateWordPairs().take(10));
            }
            return _buildRow(_suggestions[index]);
          });
      }
    
      Widget _buildRow(WordPair pair) {
        final bool alreadySaved = savedGlobal.contains(pair);
    
        return new ListTile(
          title: new Text(
            pair.asPascalCase,
            style: _biggerFont,
          ),
          trailing: new Icon(
            alreadySaved ? Icons.favorite : Icons.favorite_border,
            color: alreadySaved ? Colors.red : null,
          ),
          onTap: () {
            setState(() {
              if (alreadySaved) {
                savedGlobal.remove(pair);
              } else {
                savedGlobal.add(pair);
              }
            });
          },
        );
      }
    }
    
    // add a new stateful page
    class DetailPage extends StatefulWidget {
      @override
      _DetailPageState createState() => _DetailPageState();
    }
    
    class _DetailPageState extends State<DetailPage> {
      final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);
    
      @override
      Widget build(BuildContext context) {
    
        Iterable<ListTile> tiles = savedGlobal.map((WordPair pair) {
          return new ListTile(
            onLongPress: () {
              setState(() {
                savedGlobal.remove(pair);
              });
            },
            title: new Text(
              pair.asPascalCase,
              style: _biggerFont,
            ),
          );
        });
    
        final List<Widget> divided = ListTile.divideTiles(
          context: context,
          tiles: tiles,
        ).toList();
    
        return new Scaffold(
          appBar: new AppBar(
            title: const Text('Saved Suggestions'),
          ),
          body: new ListView(children: divided),
        );
      }
    }
    

    【讨论】:

    • 这可行,但您会看到主页并切换到新路线。
    • 你是对的。我将提供一个解决方案来防止这种情况(尽管解决方案不会像以前那么简单)
    • 总结一下。如果我想编辑页面的内容,我应该创建一个新页面并将该页面推送到导航器。要在同一页面上显示不更新的内容,我可以创建页面 throws Navigator.of(context).push( new MaterialPageRoute(
    • 是和否,在您已经创建第二个页面但无法更新它的状态之前。现在我们“准备”了一个有状态的第二页,并告诉第一页显示它而不是动态创建一个。
    • 这个state 概念可能看起来有点抽象。 This page on the Flutter site 可以澄清一下!
    【解决方案3】:

    聚会有点晚了,但我发现如果您想操作 ListView 或 GridView,最重要的是为 List/GridView 的每个子 Widget 分配一个 Key

    简而言之,Flutter 仅按类型而不是状态来比较小部件。因此,当 List/GridView 中表示的 List 的状态发生更改时,Flutter 不知道应该删除哪些子项,因为它们的 Types 仍然相同并签出。 Flutter 发现的唯一问题是项目的数量,这就是为什么它只删除 List/GridView 中的最后一个小部件。

    因此,如果您想在 Flutter 中操作列表,请为每个子组件的顶级小部件分配一个 Key。 this article 有更详细的解释。

    这可以通过添加来实现

       return GridView.count(
      shrinkWrap: true,
      crossAxisCount: 2,
      crossAxisSpacing: 5.0,
      mainAxisSpacing: 5.0,
      children: List.generate(urls.length, (index) {
        //generating tiles with from list
        return   GestureDetector(
            key: UniqueKey(), //This made all the difference for me
            onTap: () => {
              setState(() {
                currentUrls.removeAt(index);
              }) 
    
            },
            child: FadeInImage( // A custom widget I made to display an Image from 
                image:  NetworkImage(urls[index]),
                placeholder: AssetImage('assets/error_loading.png') 
                ),
    
        );
      }),
    
    );
    

    【讨论】:

      【解决方案4】:

      第 1 步:查找特定对象(元素)VIA 的索引

      List_Name.indexOf(List_Name[index]);
      
      ex:_userTransactions.indexOf(_userTransactions[index]) 
      

      第 2 步:删除特定索引处的对象

      LIST_Name.removeAt(index);
      
      ex: _userTransactions.removeAt(index);
      

      【讨论】:

        猜你喜欢
        • 2021-08-27
        • 1970-01-01
        • 2019-10-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-03
        • 2021-09-15
        相关资源
        最近更新 更多