Flutter 学习:从main.dart文件说起

Categories: flutter

这个是我学习Flutter的一个系列文章:

  1. Flutter 学习1:开发环境、开发工具、初始化一个项目
  2. Flutter 学习2:从main.dart文件说起
  3. Flutter 学习3:转场、导航
  4. Flutter 学习4:集成到原有的项目中

flutter的命令

上次那篇文章写了环境安装,开发工具插件安装然后用插件生成一个flutter项目。生成一个新的项目非常简单,点一下插件的New Project就行了。其实点击这个New Project就是执行了一个命令:

$ flutter create appName
# 这个appName就是你要生成的项目名

这个时候生成的项目里面,android项目用的是默认的java语言,IOS项目用的是Object-C。如果你比较新潮用了kotlin、swift语言。那只需要在那个命令后面加个参数就行了。

$ flutter create -i swift -a kotlin appName

热更新

Flutter提供了热更新功能来提升开发者的效率,还是用那个生成的项目来测试下。我把中间的那串英文改成了中文,然后保存一下这个main.dart文件: 再看模拟器,文字已经改了。非常方便!

理解main.dart的内容

刚才看模拟器上显示的文字,在main.dart里面找到了对应的地方,然后修改文字就行了。对于整个文件和模拟器上显示的UI界面是怎么对应的还不太清楚。 我把代码折叠看了一下: 首先第一行是:

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

这个main函数是一个入口。启动了这个MyApp,这个MyApp继承自StatelessWidget。下面还有一个是MyHomePage继承自StatefulWidget_MyHomePageState继承自State 。这些都是啥意思呢? 其实,Flutter的思路就是来自于Facebook的React,它的整个UI界面就是由这些Widget组合起来的。它就像一棵树,最顶部是这个MyApp,里面有子元素MyHomePageMyHomePage还有子元素AppBarFloatingActionButtonText,一层层往下展开。

Widget主要有两种:StatelessWidgetStatefulWidget

class MyHomePage extends StatefulWidget {
    @override
    _MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
    ...
}

State的生命周期比Widget长,Widget是临时的,Statebuild()生成需要显示的StatefulWidget,当状态参数变化的时候执行setState() 它会再次调用build()生成新的StatefulWidget,所以我们在界面上就看到了变化!

MaterialApp

main.dart里面还有一个比较有意思的就是MyApp,它其实就是一个MaterialApp,这个Widget是Flutter提供的按照Material Design设计的一个主题框架。这个开发Android的应该都很熟悉。Android有很多这种Material Design组件。这个组件提供了主题功能,所以切换主题就变的分分钟的事情了. 这是默认生成的代码,它的主题色是蓝色:

new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );

修改成紫色:

new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.purple,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );

还有暗黑模式:

new MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.dark(),      
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );

制作一个列表页面

引入外部包

我把main.dart修改一下,把它做成一个列表,列表在移动端是很常见的东西,看看Flutter怎么实现。 首先看下我们的项目根目录下有个文件pubspec.yaml,这个是项目的配置文件,配置了项目名称,flutter依赖的包,环境版本等等信息。这个配置文件信息量很大,我现在只了解了依赖包的使用。 添加依赖包就在dependencies节点下面,关于依赖包可以去官方的开源包网站查找更多:

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.2
  # 新增一个单词包,列表展现用的
  english_words: ^3.1.0

添加了包之后,需要到Terminal上去执行一下命令:

$ flutter packages get

然后就可以在我们的main.dart头部引入这个包了:

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

修改main.dart代码:

class MyApp extends StatelessWidget {
  final wordPair = WordPair.random();
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.dark(),
      home: Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          child: Text(wordPair.asPascalCase),
        ),

      ),
    );
  }
}

这样就能在我们的屏幕中间显示一个随机的英文单词。

定义一个StatefulWidget

我们把中间这个Text改成一个前面说的StatefulWidget

class RandomWordsState extends State<RandomWords> {
  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random();
    return Text(wordPair.asPascalCase);
  }
}

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

ListView

现在列表的元素已经有了,那我们可以引入列表了ListView,生成一个无限滚动的列表。 修改下RandomWordsState

Widget  _buildSuggestions() {
    return ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemBuilder: (context, i){
        //分隔符
        if (i.isOdd) return Divider();
        final index = i ~/ 2;
        if (index >= _suggestions.length) {
          // 每次获取10个单词加入数组,让它有无限长。。。
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildItem(_suggestions[index]);
      },
    );
  }

ListTile

这个_buildSuggestions生成一个ListView,这个ListView是Flutter的提供的组件,里面有很多参数可以调整。itemBuilder是生成列表子项的build方法,每次显示一个子项就会来调用这个itemBuilder。 列表子项的生成:

Widget _buildItem(WordPair pair) {
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont,
        ),
    );
  }

它是一个ListTileListView的一个子项,就是一般列表的一行。我们这里就显示一个单词,所以就定义了它的title用Text显示,ListTile还可以定义leading,subtitle等。 这样列表和列表的行都有了,我们把RandomWordsState的build方法修改下用这个列表替换:

@override
Widget build(BuildContext context) {
    return _buildSuggestions();
}

保存后列表就出现了,可以一直往下滚动: