颤振从列表视图中删除项目

ste*_*eph 9 listview flutter

我试着做

编写您的第一个 Flutter 应用程序,第 2 部分 Flutter 应用程序第 5 页

我现在有一个关于这个应用程序的问题。我想从该列表 onLongPress 中删除一个条目,如下所示:

 onLongPress: () {
              setState(() {
                _saved.remove(pair);
              });
            },
Run Code Online (Sandbox Code Playgroud)

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

 onLongPress: () {
              setState(() {
                _saved.remove(pair);
              });
            },
Run Code Online (Sandbox Code Playgroud)

Sve*_*ven 9

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

尝试这个:

onLongPress: () {
  _saved.remove(pair);
  Navigator.of(context).pop();
  _pushSaved();
},
Run Code Online (Sandbox Code Playgroud)


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

  • 使您的_saved项目成为全球性的(仅针对此示例)
  • 删除_pushSaved方法
  • 更新onPressed用于调用该_pushSaved函数的函数
  • 添加有状态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),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Blo*_*oss 8

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(...)
}
)
Run Code Online (Sandbox Code Playgroud)

  • 伟大的!这是“Dismissible”用法的一个友好的官方示例:https://flutter.dev/docs/cookbook/gestures/dismissible (2认同)

小智 6

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

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

因此,如果您想在 Flutter 中操作列表,请为每个子组件的顶级组件分配一个 Key。本文提供了更详细的解释。

这可以通过添加来实现

   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') 
            ),

    );
  }),

);
Run Code Online (Sandbox Code Playgroud)