3.编辑 Flutter 应用

本节内容
    1. Flutter 应用程序的基本结构
    1. 查找和使用第三方库
    1. 使用热重载加快开发周期
    1. 添加一个动态改变状态的控件
    1. 如何创建一个无限滑动的 ListView
    1. 添加交互
    1. 界面跳转
    1. 使用主题更改应用程序的外观

1. 创建起始 Flutter 应用程序

1. 删除 lib / main.dart 中的所有代码并替换为如下代码

它在屏幕的中心显示 "Hello World"

//其实是 dart 语言
import 'package:flutter/material.dart';
void main() => runApp(new MyApp()); //使用 => 表示单行函数或方法的简写
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          child: new Text('Hello World'),
        ),
      ),
    );
  }
}

运行程序,可以看到如下效果:

FlutterHelloWorld.png

Material 是一种视觉设计语言,这里使用 Flutter 创建了一个 Material 应用程序。

2. flutter 程序解析
  1. MyApp 继承了使应用程序本身成为小部件的 StatelessWidget,在Flutter中,几乎所有东西都是一个小部件,包括对齐,填充和布局
  2. StatelessWidget 是 immutable(不变的),即所有属性都不可变,是 final 的
  3. Material library 中的 Scaffold 控件提供了提供了默认的 app bar,其中的 body 属性可以包含主屏幕中的控件树
  4. 一个 Widget 提供一个 build() 方法,其工作就是描述如何显示子控件
  5. MyApp 中包含了一个 Center Widget,而 Center Widget 使其子控件树居中对齐

2. 查找和使用第三方库

开源库仓库:https://pub.dartlang.org/flutter/

1. 添加依赖

在 pubspec.yaml 中添加要依赖的第三方库,例如 english_words 3.1.0:

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.0
  english_words: ^3.1.0
2. 获取新的库 Packages Get
FlutterPackageGet.png

点击后可看到如下日志:

flutter packages get
Running "flutter packages get" in startup_namer...
Process finished with exit code 0
3. 升级第三方库:Packages upgrade
F:\Flutter\flutter\bin\flutter.bat --no-color packages upgrade
Running "flutter packages upgrade" in flutter_app...
Process finished with exit code 0
4. 导入第三方库

在 lib / main.dart 中,添加 import english_words,如下:

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

AS 会自动提示

5. 使用第三方库 english_words

使用英文单词包来生成文本,而不是使用字符串“Hello World”,代码如下:

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: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          //child: new Text('Hello World'), // Replace the highlighted text...
          child: new Text(wordPair.asPascalCase),  // With this highlighted text.
        ),
      ),
    );
  }
}

3. 使用热重载加快开发周期

如果应用程序正在运行,则使用热重新加载按钮(闪电图标)更新正在运行的应用程序。每次单击热重新加载或保存项目时,都会在正在运行的应用程序中随机选择一个不同的单词对。

因为单词对是在 build() 方法中进行的,每次运行 build() 方法都会重新执行

注意:如果应用进程存在但是应用程序不在前台,则|> 运行按钮和 HotLoad 按钮都不会重新启动应用(即点击没反应),需要先手动打开应用才行

4. 添加一个动态改变状态的控件

相对于不变的 Stateless widget,Stateful widgets 是状态可变的
实现 Stateful widgets 需要两个类:StatefulWidget 类和一个 State 类

1. 创建 StatefulWidget 子类

一般将 StatefulWidget 的子类实现放到文件末尾,其内部只创建了一个 State 类

class RandomWords extends StatefulWidget {
  @override
  createState() => new RandomWordsState();
}
2. 创建 State 子类

在 State 子类中保持 RandomWords widget 的状态

class RandomWordsState extends State {
    @override
    Widget build(BuildContext context) {
        final wordPair = new WordPair.random();
        return new Text(wordPair.asPascalCase);
    }
}
3. 修改 MyApp 中的 body 代码

将之前的 new Text(wordPair.asPascalCase) 替换为 new RandomWords()

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //final wordPair = new WordPair.random();  // Delete this line

    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          //child: new Text(wordPair.asPascalCase), // Change the highlighted text to...
          child: new RandomWords(), // ... this highlighted text
        ),
      ),
    );
  }
}
4. 运行 Flutter App

5. 如何创建一个无限滑动的 ListView

1. 准备 ListView 的数据

dart 语言中使用 _ 作为前缀来表示私有变量

class RandomWordsState extends State {
  final _suggestions = [];//使用 _suggestions 来存储 lsitView 数据
  final _biggerFont = const TextStyle(fontSize: 18.0); //使用 _biggerFont 来使字体更大
  ...
}
2. 创建无限滑动的 ListView

在 RandomWordsState 类中添加 _buildSuggestions() 方法来显示 ListView
该方法中的 itemBuilder 使用匿名函数,形参是 context 和 position,position 从 0 开始,一旦用户滑动该匿名方法就会被调用,并且 position 不断增加

class RandomWordsState extends State {
  ...
  Widget _buildSuggestions() {
    return new ListView.builder(
      padding: const EdgeInsets.all(16.0),
      // The itemBuilder callback is called once per suggested word pairing,
      // and places each suggestion into a ListTile row.
      // For even rows, the function adds a ListTile row for the word pairing.
      // For odd rows, the function adds a Divider widget to visually
      // separate the entries. Note that the divider may be difficult
      // to see on smaller devices.
      itemBuilder: (context, i) {
        // Add a one-pixel-high divider widget before each row in theListView.
        if (i.isOdd) return new Divider();

        //  i ~/ 2 表示整除,例如 1, 2, 3, 4, 5 变成 0, 1, 1, 2, 2.
        final index = i ~/ 2;
        // 加载更多
        if (index >= _suggestions.length) {
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_suggestions[index]);
      }
    );
  }
}
3. 创建 item 布局

在 RandomWordsState 中添加 _buildRow() 方法用于创建 item

class RandomWordsState extends State {
  ...

  Widget _buildRow(WordPair pair) {
    return new ListTile(
      title: new Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
    );
  }
}
4. 调用创建 listView 的方法
class RandomWordsState extends State {
  ...
  @override
  Widget build(BuildContext context) {
    // final wordPair = new WordPair.random(); // Delete these two lines.
    // return new Text(wordPair.asPascalCase);
    return new Scaffold (
      appBar: new AppBar(
        title: new Text('Startup Name Generator'),
      ),
      body: _buildSuggestions(),
    );
  }
  ...
}
5. 移除 MyApp 中的无用控件
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Startup Name Generator',
      home: new RandomWords(),
    );
  }
}

6. 添加交互

1. 新建 list 集合保存用户喜欢的 item
class RandomWordsState extends State {
  final _suggestions = [];

  //使用 _saved 集合来保存状态
  final _saved = new Set();

  final _biggerFont = const TextStyle(fontSize: 18.0);
  ...
}
2. 新建成员变量来判断 item 是否添加到了喜欢列表
Widget _buildRow(WordPair pair) {
  final alreadySaved = _saved.contains(pair);
  ...
}
3. 添加喜欢的心型 icon
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,
    ),
  );
}
4. 添加点击事件

在 Flutter 中,调用 setState() 会再次触发 build() 方法,从而更新 UI

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() 方法并传入一个匿名函数
      setState(() {
        if (alreadySaved) {
          _saved.remove(pair);
        } else {
          _saved.add(pair);
        }
      });
    },
  );
}

7. 界面跳转

在 Flutter 中,Navigator 使用栈管理各个界面

1. 添加 Navigation 导航 icon
class RandomWordsState extends State {
  ...
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Startup Name Generator'),
        // 一个属性如果有多个控件,则可以用 [] 来表示
        actions: [
          new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),
        ],
      ),
      body: _buildSuggestions(),
    );
  }

  void _pushSaved() {}
  ...
}
2. 点击导航 icon 时新建界面

使用 MaterialPageRoute 新建界面

void _pushSaved() {
  Navigator.of(context).push(
    new MaterialPageRoute(
      builder: (context) {

        // 创建已选中的 item
        final tiles = _saved.map(
          (pair) {
            return new ListTile(
              title: new Text(
                pair.asPascalCase,
                style: _biggerFont,
              ),
            );
          },
        );

        // divideTiles 为 tiles 添加分割线
        final divided = ListTile
          .divideTiles(
            context: context,
            tiles: tiles,
          )
          .toList();

        //创建 Scaffold 并添加 appBar 和 listView 作为新界面
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('Saved Suggestions'),
          ),
          body: new ListView(children: divided),
        );
      },
    ),
  );
}
3. 运行效果
Navigation运行效果.png

8. 使用主题更改应用程序的外观

1. 使用 ThemeData 类改变主题

改变 MyApp 的主题为白色

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Startup Name Generator',
      theme: new ThemeData(
        primaryColor: Colors.white,
      ),
      home: new RandomWords(),
    );
  }
}
2. 运行效果
FlutterThemeResult.png

你可能感兴趣的:(3.编辑 Flutter 应用)