从零开始写第一个Flutter app(十)——最终代码

目录

前言

在贴出最终代码前,我们再对上一节的代码做下重构,使代码更清晰点。

在上节跳转新页面时,我们是在MaterialPageRoute的builder中写一个方法直接返回一个ListView,这一节我们重构下代码,新建一个StateLessWidget表示新的reoute,在里面返回ListView。这样结构会比较清晰一点。

重构前代码

先看下重构前跳转新页面的代码

void _pushSaved() {
  // push方法往堆栈里添加一个新的Route对象
  Navigator.of(context).push(
    // MaterialPageRoute是Matetial风格的Route
    MaterialPageRoute<void>(
      // builder属性是一个方法,返回一个Widget
      builder: (BuildContext context) {
        // map操作符,将List<WordPair>转成Iterable<ListTile>
        final Iterable<ListTile> tiles = _saved.map((WordPair pair) {
          return ListTile(
            title: Text(
              pair.asPascalCase,
              style: _biggerFont,
            ),
          );
        },
        );

        // 通过ListTile.divideTiles方法将每一个ListTile下面添加一条分割线
        final List<Widget> divided = ListTile.divideTiles(
          context: context,
          tiles: tiles,
        )
            .toList();

        // 通过Scaffold构造一个新的页面,这个就是新的Route页面的内容
        return Scaffold(         // Add 6 lines from here...
          appBar: AppBar(
            title: Text('Saved Suggestions'),
          ),
          body: ListView(children: divided),
        );                       // ... to here.
      },
    ),
  );
}

重构1

新建SavedRoute 表示新的页面route,由于该页面单纯显示,不需要管理状态,所以继承StateLessWidget

将原先在_pushSaved()方法中构建ListView的代码转移到SavedRoute类的build()方法下

class SavedRoute extends StatelessWidget {
  // 构造函数,选中的数据saved由上个页面传过来
  SavedRoute({Key key, this.saved}): super(key: key);
  final List<WordPair> saved;
  final _biggerFont = const TextStyle(fontSize: 18.0);

  @override
  Widget build(BuildContext context) {
    // map操作符,将List<WordPair>转成Iterable<ListTile>
    final Iterable<ListTile> tiles = saved.map((WordPair pair) {
      return ListTile(
        title: Text(
          pair.asPascalCase,
          style: _biggerFont,
        ),
      );
    });

    // 通过ListTile.divideTiles方法将每一个ListTile下面添加一条分割线
    final List<Widget> divided = ListTile.divideTiles(
      context: context,
      tiles: tiles,
    ).toList();

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

 修改_pushSaved()方法

void _pushSaved() {
  // push方法往堆栈里添加一个新的Route对象
  Navigator.of(context).push(
    // MaterialPageRoute是Matetial风格的Route
    MaterialPageRoute<void>(
      // builder属性是一个方法,返回一个Widget
      builder: (context) => SavedRoute(saved: _saved.toList())
    ),
  );
}

重构2

这里再提供另一种重构的方案,在方案一中ListView的构建是一次性生成所有item,这种方法适用于item数量少的情况,多的话会影响性能,如果item数量多建议使用ListView.builder来构建

class SavedRoute2 extends StatelessWidget {
  // 构造函数,选中的数据saved由上个页面传过来
  SavedRoute2({Key key, this.saved}): super(key: key);
  final List<WordPair> saved;
  final _biggerFont = const TextStyle(fontSize: 18.0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Saved Suggestions'),
      ),
      body: ListView.builder(
          padding: const EdgeInsets.all(16.0),
          // item数量
          itemCount: saved.length,
          itemBuilder: (context, i) {
            // 先创建一个ListTile,此时还未有分割线
            ListTile listTile = ListTile(
              title: Text(
                saved[i].asPascalCase,
                style: _biggerFont,
              ),
            );

            // 添加分割线
            DecoratedBox box = DecoratedBox(
              position: DecorationPosition.foreground,
              decoration: BoxDecoration(
                border: Border(
                  bottom: Divider.createBorderSide(context),
                ),
              ),
              child: listTile,
            );

            return box;
          }),
    );
  }
}
void _pushSaved() {
  // push方法往堆栈里添加一个新的Route对象
  Navigator.of(context).push(
    // MaterialPageRoute是Matetial风格的Route
    MaterialPageRoute<void>(
      // builder属性是一个方法,返回一个Widget
      builder: (context) => SavedRoute2(saved: _saved.toList())
    ),
  );
}

最终代码

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',
      theme: ThemeData(          // Add the 3 lines from here...
        primaryColor: Colors.white,
      ),
      home: RandomWords(),
    );
  }
}

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

class RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[]; // ListView用的数据源
  final _biggerFont = const TextStyle(fontSize: 18.0); // 字体大小
  final Set<WordPair> _saved = Set<WordPair>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Startup Name Generator'),
        actions: <Widget>[      // Add 3 lines from here...
          IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
        ],
      ),
      body: _buildSuggestions(), // body为一个ListView
    );
  }

  Widget _buildSuggestions() {
    return ListView.builder(
        padding: const EdgeInsets.all(16.0), // 设置padding
        itemBuilder: (context, i) {
          if (i.isOdd) return Divider(); // 如果为基数,返回分割线

          final index = i ~/ 2; // 由于divider也占一个位置,所以需除以2计算实际的index
          // 若数据源不够,则一次性生成10条数据,这样就可以实现ListView无限滑动的效果
          if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10));
          }
          // 生成每一条item布局
          return _buildRow(_suggestions[index]);
        });
  }

  // 创建ListView的Item
  Widget _buildRow(WordPair pair) {
    final bool alreadySaved = _saved.contains(pair);
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont, // 设置样式字体大小
      ),
      trailing: Icon(   // Add the lines from here...
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      onTap: () {      // Add 9 lines from here...
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
            toast("选择:" + pair.asPascalCase);
          } else {
            _saved.add(pair);
            toast("取消:" + pair.asPascalCase);
          }
        });
      },
    );
  }

  void toast(String txt) {
    Fluttertoast.showToast(
        msg: txt, // 显示的内容
        toastLength: Toast.LENGTH_SHORT, // 显示时长,与原生Toast一样可设置LENGTH_SHORT或者LENGTH_LONG
        gravity: ToastGravity.BOTTOM, // 显示位置,支持TOP, BOTTOM, CENTER三种位置
        timeInSecForIos: 1,
        backgroundColor: Colors.black, // 背景颜色
        fontSize: 16, // 字体大小
        textColor: Colors.white // 字体颜色
    );
  }

  void _pushSaved() {
    // push方法往堆栈里添加一个新的Route对象
    Navigator.of(context).push(
      // MaterialPageRoute是Matetial风格的Route
      MaterialPageRoute<void>(
        // builder属性是一个方法,返回一个Widget
        builder: (context) => SavedRoute(saved: _saved.toList())
//          builder: (context) => SavedRoute2(saved: _saved.toList())
      ),
    );
  }
}

class SavedRoute extends StatelessWidget {
  // 构造函数,选中的数据saved由上个页面传过来
  SavedRoute({Key key, this.saved}): super(key: key);
  final List<WordPair> saved;
  final _biggerFont = const TextStyle(fontSize: 18.0);

  @override
  Widget build(BuildContext context) {
    // map操作符,将List<WordPair>转成Iterable<ListTile>
    final Iterable<ListTile> tiles = saved.map((WordPair pair) {
      return ListTile(
        title: Text(
          pair.asPascalCase,
          style: _biggerFont,
        ),
      );
    });

    // 通过ListTile.divideTiles方法将每一个ListTile下面添加一条分割线
    final List<Widget> divided = ListTile.divideTiles(
      context: context,
      tiles: tiles,
    ).toList();

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

class SavedRoute2 extends StatelessWidget {
  // 构造函数,选中的数据saved由上个页面传过来
  SavedRoute2({Key key, this.saved}): super(key: key);
  final List<WordPair> saved;
  final _biggerFont = const TextStyle(fontSize: 18.0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Saved Suggestions'),
      ),
      body: ListView.builder(
          padding: const EdgeInsets.all(16.0),
          // item数量
          itemCount: saved.length,
          itemBuilder: (context, i) {
            // 先创建一个ListTile,此时还未有分割线
            ListTile listTile = ListTile(
              title: Text(
                saved[i].asPascalCase,
                style: _biggerFont,
              ),
            );

            // 添加分割线
            DecoratedBox box = DecoratedBox(
              position: DecorationPosition.foreground,
              decoration: BoxDecoration(
                border: Border(
                  bottom: Divider.createBorderSide(context),
                ),
              ),
              child: listTile,
            );

            return box;
          }),
    );
  }
}


 

posted @ 2019-07-30 17:16  野猿新一  阅读(42)  评论(0编辑  收藏  举报