继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Flutter 入门实现 ListView 列表页面以及收藏页面

慕标5832272
关注TA
已关注
手记 1257
粉丝 232
获赞 1003

实现的效果图(官网示例)

webp

官网示例

作为一个 Android 开发者,实现这个功能那肯定是分分钟的事,但是现实是用 flutter 实现,那么需要如何来实现呢?

通过拆分我们可以得到如下要实现的功能:

  • 顶部标题栏

  • 可滑动的列表

  • 可收藏和取消的点击图标

  • 页面跳转

在开始实现效果之前,我们先来了解一下代码结构,入口在lib/main.dart,目前所有的代码都先在里面实现。

在这里使用了一个第三方库,用于提供随机的英文词组,所以需要先添加第三方库,我们在pubspec.yaml文件中添加该库:

dependencies:
  flutter:
    sdk: flutter  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2  # 新添加的英文词组库
  english_words: ^3.1.0

然后在main.dart中导入即可使用:

import 'package:flutter/material.dart';// 导入英文词组库import 'package:english_words/english_words.dart';// 程序入口void main() => runApp(new MyApp());class MyApp extends StatelessWidget {  @override
  Widget build(BuildContext context) {    return new MaterialApp(      // 页面标题
      title: 'Startup Name Generator',      // 显示的页面数据
      home: new RandomWords(),
    );
  }
}

从上面的代码可以看出我们的MyApp是继承自StatelessWidget的,这将会使应用本身也成为一个widget

这里的widget有两种,一种是StatelessWidget,另一种是StatefulWidget.。

前者是无状态的widget也就是不可进行交互,后者是有状态的widget,可进行交互且自己维护自身的状态。(这块本人愚钝还有点说不清楚,待日后再详解,网上也有文章介绍)。

Flutter中,大多数东西都是widget。在上面的代码中RandomWords是我们自定义的一个Widget。它的实现如下:

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

可以看出它继承的是StatefulWidget,也就是继承了有状态的widget

dart中可以通过=>创建一个widget,这里就通过createState() => new RandomWordsState();创建了一个自定义的widget

RandomWordsState的实现如下:

class RandomWordsState extends State<RandomWords> {  // 保存建议的单词对
  final _suggestions = <WordPair>[];  // 集合存储用户喜欢(收藏)的单词对
  final _saved = new Set<WordPair>();  // 增大字体大小
  final _biggerFont = const TextStyle(fontSize: 18.0);  @override
  Widget build(BuildContext context) {    return new Scaffold (
      appBar: new AppBar(
        title: new Text('Startup Name Generator'),
        actions: <Widget>[          new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),
        ],
      ),

      body: _buildSuggestions(),
    );
  }  // listView 列表
  Widget _buildSuggestions() {    return new ListView.builder(
        padding: const EdgeInsets.all(16.0),        // 对于每个建议的单词对都会调用一次itemBuilder,然后将单词对添加到ListTile行中
        // 在偶数行,该函数会为单词对添加一个ListTile row.
        // 在奇数行,该函数会添加一个分割线widget,来分隔相邻的词对。
        // 注意,在小屏幕上,分割线看起来可能比较吃力。
        itemBuilder: (context, i) {          // 在每一列之前,添加一个1像素高的分隔线widget
          if (i.isOdd) return new Divider();          // 语法 "i ~/ 2" 表示i除以2,但返回值是整形(向下取整),比如i为:1, 2, 3, 4, 5
          // 时,结果为0, 1, 1, 2, 2, 这可以计算出ListView中减去分隔线后的实际单词对数量
          final index = i ~/ 2;          // 如果是建议列表中最后一个单词对
          if (index >= _suggestions.length) {            // ...接着再生成10个单词对,然后添加到建议列表
            _suggestions.addAll(generateWordPairs().take(10));
          }          return _buildRow(_suggestions[index]);
        }
    );
  }  // listView 每一行的内容和样式
  Widget _buildRow(WordPair pair) {    // 检查确保单词对还没有添加到收藏夹中
    final alreadySaved = _saved.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) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );
  }  void _pushSaved() {    // 跳转收藏页面的方法
    Navigator.of(context).push(new MaterialPageRoute(
      builder: (context) {        final tiles = _saved.map(
              (pair) {            return new ListTile(
              title: new Text(
                pair.asPascalCase,
                style: _biggerFont,
              ),
            );
          },
        );        // 添加1像素的分割线
        final divided = ListTile.divideTiles(
          context: context,
          tiles: tiles,
        ).toList();        // 收藏页面
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('Saved Suggestions'),
          ),
          body: new ListView(children: divided),
        );
      },
    ),);
  }
}

可以看出自定义一个有状态的widget需要继承自State,默认需要重载 build方法。在build方法中可以看到好几个new出来的widget

而在appBar中就可以设置标题栏的内容。
body:_buildSuggestions()中设置的就是列表显示的内容,在dart中方法名前的_表示私有方法。

_buildSuggestions中创建了ListView widget用于显示列表,而列表中的文字是通过ListTile widget来实现的。

在列表中的收藏和取消收藏的实现 是由final _saved = new Set<WordPair>();来控制的。如果在_saved中存在则移除收藏,不存在则添加收藏。

分页的实现 是通过判断是否是最后一条数据,是的话直接再获取10条数据添加到列表中。

// 如果是建议列表中最后一个单词对if (index >= _suggestions.length) {   // ...接着再生成10个单词对,然后添加到建议列表
    _suggestions.addAll(generateWordPairs().take(10));
}

如果我们觉得蓝色的背景的样式不好看,可以通过在MyApp中添加theme修改:

// 修改主题颜色
 theme: new ThemeData(
 primaryColor: Colors.white,
),

至此,我们的第一个应用就实现到这了,后续学习了新的知识再完善。

参考

官网示例 :https://flutterchina.club/get-started/codelab/

完整代码如下:

import 'package:flutter/material.dart';import 'package:english_words/english_words.dart';void main() => runApp(new MyApp());class MyApp extends StatelessWidget {  @override
  Widget build(BuildContext context) {//    final wordPair = new WordPair.random();
    return new MaterialApp(
      title: 'Startup Name Generator',      // 修改主题颜色
      theme: new ThemeData(
        primaryColor: Colors.white,
      ),
      home: new RandomWords(),
    );
  }
}class RandomWords extends StatefulWidget {  @override
  createState() => new RandomWordsState();
}class RandomWordsState extends State<RandomWords> {  // 保存建议的单词对
  final _suggestions = <WordPair>[];  // 集合存储用户喜欢(收藏)的单词对
  final _saved = new Set<WordPair>();  // 增大字体大小
  final _biggerFont = const TextStyle(fontSize: 18.0);  @override
  Widget build(BuildContext context) {    return new Scaffold (
      appBar: new AppBar(
        title: new Text('Startup Name Generator'),
        actions: <Widget>[          new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),
        ],
      ),

      body: _buildSuggestions(),
    );
  }  // listView 列表
  Widget _buildSuggestions() {    return new ListView.builder(
        padding: const EdgeInsets.all(16.0),        // 对于每个建议的单词对都会调用一次itemBuilder,然后将单词对添加到ListTile行中
        // 在偶数行,该函数会为单词对添加一个ListTile row.
        // 在奇数行,该函数会添加一个分割线widget,来分隔相邻的词对。
        // 注意,在小屏幕上,分割线看起来可能比较吃力。
        itemBuilder: (context, i) {          // 在每一列之前,添加一个1像素高的分隔线widget
          if (i.isOdd) return new Divider();          // 语法 "i ~/ 2" 表示i除以2,但返回值是整形(向下取整),比如i为:1, 2, 3, 4, 5
          // 时,结果为0, 1, 1, 2, 2, 这可以计算出ListView中减去分隔线后的实际单词对数量
          final index = i ~/ 2;          // 如果是建议列表中最后一个单词对
          if (index >= _suggestions.length) {            // ...接着再生成10个单词对,然后添加到建议列表
            _suggestions.addAll(generateWordPairs().take(10));
          }          return _buildRow(_suggestions[index]);
        }
    );
  }  // listView 每一行的内容和样式
  Widget _buildRow(WordPair pair) {    // 检查确保单词对还没有添加到收藏夹中
    final alreadySaved = _saved.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) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );
  }  void _pushSaved() {    // 跳转收藏页面的方法
    Navigator.of(context).push(new MaterialPageRoute(
      builder: (context) {        final tiles = _saved.map(
              (pair) {            return new ListTile(
              title: new Text(
                pair.asPascalCase,
                style: _biggerFont,
              ),
            );
          },
        );        // 添加1像素的分割线
        final divided = ListTile.divideTiles(
          context: context,
          tiles: tiles,
        ).toList();        // 收藏页面
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('Saved Suggestions'),
          ),
          body: new ListView(children: divided),
        );
      },
    ),);
  }

}



作者:_龙衣
链接:https://www.jianshu.com/p/744c3e7cdc71


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP