【Toki从零学Flutter】编写一个列表应用

目录

  1. 配置环境
  2. 运行官方演示项目
  3. 编写一个列表应用
  4. 混合开发 iOS版

前言

Flutter应用一切正常,下面开始写代码,找到官方教程按步骤敲就好了。
其实这些代码我昨天就敲过了,不过有些地方没看明白,写这篇教程的时候也顺便复习一下。


第一步:替换演示代码

替换工程目录下 lib/main.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'),
        ),
      ),
    );
  }
}

简要分析
  • material.dart是视觉设计相关的包(by: 官方教程)
  • MyApp继承自StatelessWidget,说明它的属性变化不会重新渲染页面
  • Scaffold类似iOS的ViewController,里面提供了默认的导航栏appBar和内容容器body

第二步: 使用外部包(package)

这一步很多框架都会用到,作为程序员都不会陌生
找到pubspec.yaml文件,在dependencies:下方添加我们要引用的包english_words: ^3.1.0,这个包在本章中仅用来示范引用包文件。

...
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
...

在VS Code中,如果安装了Flutter插件,在保存pubspec.yaml文件时,会自动下载并安装对应的包,无需手动执行,随后可以在代码中引用对应的包。

【Toki从零学Flutter】编写一个列表应用_第1张图片

输入关键字后会有联想内容提示。
不过,不知道是VS Code还是Dart插件的问题,这个联想不是很智能,一旦输入过程出现中断,联想就不会再出现了。

第三步:创建一个可以滚动的列表

从这里开始就和官方教程不一样了,后面是偷懒的简化版本

首先,建立在模块化编程的思维基础上,我们应该新建一个文件TextListScaffoldWidget.dart用来编写列表代码。

import 'package:flutter/material.dart';

class TextListScaffoldState extends State {
  final _textTiles = List(10);
  
  @override
  Widget build(BuildContext context) {
    //生成列表卡片
    for (var i = 0; i < _textTiles.length; i++) {
      final text = new Text(i.toString());
      final tile = new ListTile(title: text,);
      _textTiles[i] = tile;
    }
    //生成主要页面
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Text List'),
      ),
      //生成列表
      body: new ListView(children: _textTiles),
    );
  }
}

class TextListScaffoldWidget extends StatefulWidget {
  @override
  State createState() {
    return TextListScaffoldState();
  }
}

之后,我们需要在main.dart中引用该文件,并将TextListScaffoldWidget设置为主页

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new TextListScaffoldWidget()
    );
  }
}

保存代码之后可以在连接的设备上看到热重载之后的界面


【Toki从零学Flutter】编写一个列表应用_第2张图片
简要分析
  • 代码主要内容是先生成一个长度为10的数组,向内填充ListTile,随后用他们来创建ListView,最后把他们塞到Scaffoldbody里面
  • ListTile类似iOS中的Cell, ListView类似iOS中的TableView
  • 我习惯的文件命名规范是业务+功能+类型对应的是TextList+Scaffold+Widget
  • TextListScaffoldWidget继承自StatefulWidget,与StatelessWidget不同,它的属性State变化会重新渲染页面

第四步:添加点击功能

这一步主要是展示StatefulWidgetState变化的响应,内容很简单,点击Tile的时候,在title后面添加后缀“_s”
首先,在tile初始化时添加onTap点击事件,点击事件中使用setState来通知页面状态改变,需要重新渲染
然后,由于ListView的构造方法不响应State,所以要把ListView的初始化方式换成ListView.builder()

...
class TextListScaffoldState extends State {
  final _textTiles = List(10);
  var _selectedIndex = -1;
  
  @override
  Widget build(BuildContext context) {
    for (var i = 0; i < _textTiles.length; i++) {
      final isSelected = _selectedIndex == i;
      final suffix = isSelected ? '_s' : '';
      final text = new Text(i.toString() + suffix);
      //添加点击事件
      final tile = new ListTile(
        title: text,
        onTap: () {
          setState(() {
            _selectedIndex = i;
          });
        },
      );
      _textTiles[i] = tile;
    }
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Text List'),
      ),
      //更换初始化方式
      body: new ListView.builder(
        itemBuilder: (context, i) {
          if (i < _textTiles.length) {
            return _textTiles[i];
          }
          return null;
        },
      ),
    );
  }
}
...

保存代码,之后列表变为可点击模式,点击时会有Flutter默认的波纹效果,被点击的卡片会显示“_s”后缀


【Toki从零学Flutter】编写一个列表应用_第3张图片
简要分析
  • setState和属性的修改没有直接关联,完全可以先修改属性,然后执行该方法,效果相同。代码如下
onTap: () {
 _selectedIndex = i;
 setState(() {
 });
},

第四步:添加跳转功能

为了省事,我选择套娃。点击卡片的时候跳转一个新的TextListScaffold
替换tile初始化方法里的onTap的实现内容就可以了

...
      final tile = new ListTile(
        title: text,
        onTap: () {
          Navigator.of(context).push(
            new MaterialPageRoute(
              builder: (context) {
                return new TextListScaffoldWidget();
              }
            )
          );
        },
      );
      _textTiles[i] = tile;
    }
...

保存代码,开始套娃!


【Toki从零学Flutter】编写一个列表应用_第4张图片
简要分析
  • Navigator.of(context)是导航管理器,应该是个单例,他会显示最顶层的路由内容。用MaterialPageRoute创建一个新页面的路由,把路由推入导航管理器的栈中,就会显示新页面。
  • 看了下Flutter的接口,好像没有类似iOS中present行为的控制器展示,尝试了一下用导航管理器做模态视图,感觉有些麻烦。(参考Flutter Ui 实验室(一)模态弹窗)

参考文章: statelessWidget和statefulWidget简介


后记

简单的跟着教程写了两遍,对基础框架稍微熟悉了一点。感觉Flutter上手还是很快的,如果是做小规模独立开发或者简单的应用原型的话,应该是个非常合适的UI框架。

你可能感兴趣的:(【Toki从零学Flutter】编写一个列表应用)