100行写一个无限懒加载ListView,Flutter中文教程

作者:计算机网络

图片 1Flutter

图片 2

在 上一篇文章 中,我们讲解了 Flutter 开发环境搭建 , 以及运行了官方demo简单体验了下 Flutter app .

在如今的 Fultter 大潮下,本系列是让你看完会安心的文章。本系列将完整讲述:如何快速从0开发一个完整的 Flutter APP,配套高完成度 Flutter 开源项目 GSYGithubAppFlutter。同时也会提供一些 Flutter 的开发细节技巧,并针对开发过程中可能遇到的问题进行填坑。

本文是Flutter系列的第二篇教程,内容来自Flutter中文网,该网站翻译目前来说是最全的,只不过刚刚上线,搜索排名还比较靠后,建议您保存为书签,或者百度搜索“Flutter中文网”,在2、3页左右的样子找到 ,点击进入,这样也可以帮刷一下排名,让优质资源能脱颖而出(当然,我觉得你没这么好)。

Flutter

此篇我们将开始对一些 Flutter app 中的一些概念做一些讲解 , 一些基本的操作做一些示例 , 主要是参考官网的教程 Write Your First Flutter App

系列文章分为三篇,第一部分是基础篇(针对 Dart 语言和 Flutter 基础),第二部分是App快速开发实战篇,第三部分是细节填坑篇。

Flutter中文网的Cookbook中包含了在编写Flutter应用程序时常见问题及示例。每个主题都是独立的,可以当做作参考文档来帮助您构建应用程序,下面是一个列表,您可以直接点击访问。

以下内容基本翻译自Write Your First Flutter App,翻译的并不完全!作为自己学习的笔记,加入了自己的理解,可能有疏漏错误,欢迎指正!

若你对面向对象编程熟悉,以及对基本编程概念如变量、循环、条件了解 , 则适合阅读本篇教程 . 不必需要拥有 Dart 或移动编程经验.

本篇主要涉及:环境搭建、Dart 语言、Flutter 的基础。

  • 使用主题共享颜色和字体样式

步骤

1.创建一个Flutter app
2.使用扩展包(external package)
3.添加一个Stateful组件
4.创建一个无限滚动的(且懒加载的)ListView
5.添加interactivity
6.引导(Navigate)至一个新的界面(Screen)
7.使用主题(Themes)改变界面(UI)

为了更好的阅读体验 , 请点击 阅读原文 :)

1、环境搭建

Flutter 的环境搭建十分省心,特别对应 Android 开发者而言,只是在 Android Stuido上安装插件,并下载flutter Sdk到本地,配置在环境变量即可。其实中文网的搭建Futter开发环境 已经很贴心详细,从平台指引开始安装基本都不会遇到问题。

这里主要是需要注意,因为某些不可抗力的原因,国内的用户需要配置 Flutter 的代理,并且国内用户在搜索 Flutter 第三方包时,也是在 内查找,下方是需要配置到环境变量的地址。(ps Android Studio下运行 iOS 也是蛮有意思的

///win直接配置到环境编辑即可,mac 配置到 bash_profileexport PUB_HOSTED_URL=https://pub.flutter-io.cn //国内用户需要设置export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn //国内用户需要设置

要创建的App目标

如下图:
1)创建一个列表ListView,无限懒加载一些英文名称
2)用户可以选择或取消选择,保存自己的最爱
3)代码每次创建10个条目,随着滑动,创建新的一批条目
4)点击右上角按钮,进入一个新的界面,ListView中只包含自己的最爱(lists only the favorited names)

图片 3

startup-namer-app.gif

  • 步骤 1 : 创建及启动 Flutter app
  • 步骤 2 : 使用一个外部的程序包
  • 步骤 3 : 增加一个 Stateful Widget
  • 步骤 4 : 创建一个无限滚动的 ListView
  • 步骤 5 : 增加交互
  • 步骤 6 : 跳转到新页面
  • 步骤 7 : 通过主题改变UI
  • 完成!

2、Dart语言下的Flutter

在跨平台开领域被 JS 一统天下的今天,Dart 语言的出现无疑是一股清流。作为后来者,Dart语言有着不少Java、kotlin 和 JS 的影子,所以对于 Android 原生开发者、前端开发者而言无疑是非常友好的。

官方也提供了包括 iOS开发者,React Native 等开发者迁移到 Flutter 上的文档,所以请不要担心,Dart语言不会是你掌握 Flutter 的门槛。甚至作为开发者,就算你不懂 Dart 也可以看着代码摸索。

Come on,下面主要通过对比,简单讲述下 Dart 的一些特性,主要涉及的是 Flutter 下使用。

基本类型

var 可以定义变量,如 var tag = "666" ,这和 JS 、 Kotlin 等语言类似,同时 Dart 属于动态类型语言,支持闭包。

Dart 中 number 类型分为 int 和 double ,其中 java 中的 long 对应的也是 Dart 中的 int 类型。Dart 中没有 float 类型。

Dart 下只有 bool 型可以用于 if 等判断,不同于 JS 这种使用方式是不合法的 var g = "null"; if{} 。

DART中,switch 支持 String 类型。

变量

Dart 不需要给变量设置 setter getter 方法, 这和 kotlin 等类似。Dart 中所有的基础类型、类等都继承 Object ,默认值是 NULL, 自带 getter 和 setter ,而如果是 final 或者 const 的话,那么它只有一个 getter 方法。

Dart 中 final 和 const 表示常量,比如 final name = 'GSY'; const value= 1000000; 同时 static const 组合代表了静态常量。其中 const 的值在编译期确定,final 的值要到编译时才确定。(ps Flutter 在 Release 下是 AOT 模式。)

Dart 下的数值,在作为字符串使用时,是需要显式指定的。比如:int i = 0; print("aaaa" i); 这样并不支持,需要 print("aaaa" i.toString; 这样使用。这和 Java 与 JS 存在差异。所以在使用动态类型时,需要注意不要把 number 类型当做 String 使用。

DART 中数组等于列表,所以 var list = []; 和 List list = new List() 可以简单看做一样。

方法

Dart 下 ?? 、??= 属于操作符,如: AA ?? "999" 表示如果 AA 为空,返回999;AA ??= "999" 表示如果 AA 为空,给 AA 设置成 999。

Dart 方法可以设置 参数默认值 和 指定名称 。比如: getDetail(Sting userName, reposName, {branch = "master"}){} 方法,这里 branch 不设置的话,默认是 “master” 。参数类型 可以指定或者不指定。调用效果: getRepositoryDetailDao(“aaa", "bbbb", branch: "dev");

Dart 不像 Java ,没有关键词 public 、private 等修饰符,_下横向直接代表 private ,但是有 @protected 注解。

Dart 中多构造函数,可以通过如下代码实现的。默认构造方法只能有一个,而通过Model.empty() 方法可以创建一个空参数的类,其实方法名称随你喜欢。而变量初始化值时,只需要通过 this.name 在构造方法中指定即可:

class ModelA { String name; String tag; //默认构造方法,赋值给name和tag ModelA(this.name, this.tag); //返回一个空的ModelA ModelA.empty(); //返回一个设置了name的ModelA ModelA.forName(this.name);}

Flutter

Flutter 中支持 async/await 。这一点和 ES7 很像,如下代码所示,只是定义的位置不同。同时异步操作也和 ES6 中的Promise 很像,只是 Flutter 中返回的是 Future 对象,通过 then 可以执行下一步。如果返回的还是 Future 便可以 then 的流式操作了 。

 ///模拟等待两秒,返回OK request() async { await Future.delayed(Duration(seconds: 1)); return "ok!"; } ///得到"ok!"后,将"ok!"修改为"ok from request" doSomeThing() async { String data = await request(); data = "ok from request"; return data; } ///打印结果 renderSome() { doSomeThing().then { print; ///输出ok from request }); }

Flutter 中 setState 很有 React Native 的既视感,Flutter 中也是通过 state 跨帧实现管理数据状态的,这个后面会详细讲到。

Flutter 中一切皆 Widget 呈现,通过 build方法返回 Widget,这也是和 React Native 中,通过 render 函数返回需要渲染的 component 一样的模式。

  • 显示来自网上的图片
  • 用占位符淡入图片
  • 使用缓存图

学习目标(U CAN LEARN)

1.熟悉Flutter App基本构造(structure)
2.寻找和使用扩展包扩展功能
3.使用热重载(reload),以实现更快的开发周期(development cycle)
4.如何实现Stateful组件
5.如何实现无限懒加载的ListView
6.创建并引导至(Navigate)一个新的界面(Screen)
7.如何使用主题改变app的外观

我们将创建什么

我们将实现一个简单的移动应用 , 它会生成创业公司的名称 . 用户可以选择和反选名称 , 保存最好的那些 . 代码一次生成 10 个名称 . 当用户滑动时 , 新一批的名称就会生成 . 用户可以点击导航栏右上的按钮进入一个只展示喜好的名称的列表新页面.

图片 4

image

我们将学到:

  • Flutter app 的基本结构
  • 使用额外的包去拓展功能
  • 使用热部署来快速开发
  • 如何去实现一个stateful 小部件
  • 如何创建一个无线滑动,懒加载的列表
  • 如何跳转去下一个界面
  • 如果通过主题去修改app外观

3、Flutter Widget

在 Flutter 中,一切的显示都是 Widget 。Widget 是一切的基础,作为响应式的渲染,属于 MVVM 的实现机制。我们可以通过修改数据,再用setState 设置数据,Flutter 会自动通过绑定的数据更新 Widget 。 所以你需要做的就是实现 Widget 界面,并且和数据绑定起来。

Widget 分为 有状态 和 无状态 两种,在 Flutter 中每个页面都是一帧。无状态就是保持在那一帧。而有状态的 Widget 当数据更新时,其实是绘制了新的 Widget,只是 State 实现了跨帧的数据同步保存。

这里有个小 Tip ,当代码框里输入 stl 的时候,可以自动弹出创建无状态控件的模板选项,而输入 stf 的时,就会弹出创建有状态 Widget 的模板选项。

代码格式化的时候,括号内外的逗号都会影响格式化时换行的位置。

如果觉得默认换行的线太短,可以在设置-Editor-Code Style-Dart-Wrapping and Braces-Hard wrap at 设置你接受的数值。3.1、无状态StatelessWidget

直接进入主题,下方代码是无状态 Widget 的简单实现。

继承 StatelessWidget,通过 build 方法返回一个布局好的控件。可能现在你还对 Flutter 的内置控件不熟悉,but Don't worry , take is easy ,后面我们就会详细介绍。这里你只需要知道,一个无状态的 Widget 就是这么简单。

Widget 和 Widget 之间通过 child: 进行嵌套。其中有的 Widget 只能有一个 child,比如下方的 Container ;有的 Widget 可以多个 child ,也就是children:,比如` Colum 布局。下方代码便是 Container Widget 嵌套了 Text Widget。

import 'package:flutter/material.dart';class DEMOWidget extends StatelessWidget { final String text; //数据可以通过构造方法传递进来 DEMOWidget(this.text); @override Widget build(BuildContext context) { //这里返回你需要的控件 //这里末尾有没有的逗号,对于格式化代码而已是不一样的。 return Container( //白色背景 color: Colors.white, //Dart语法中,?? 表示如果text为空,就返回尾号后的内容。 child: Text(text ?? "这就是无状态DMEO"), ); }}

3.2、有状态StatefulWidget

继续直插主题,如下代码,是有状态的widget的简单实现。

你需要创建管理的是主要是 State , 通过 State 的 build 方法去构建控件。在 State 中,你可以动态改变数据,这类似 MVVM 实现,在 setState 之后,改变的数据会触发 Widget 重新构建刷新。而下方代码中,是通过延两秒之后,让文本显示为 "这就变了数值"。

如下代码还可以看出,State 中主要的声明周期有 :

initState :初始化,理论上只有初始化一次,第二篇中会说特殊情况下。didChangeDependencies:在 initState 之后调用,此时可以获取其他 State 。dispose :销毁,只会调用一次。看到没,Flutter 其实就是这么简单!你的关注点只要在:创建你的 StatelessWidget 或者 StatefulWidget 而已。你需要的就是在 build 中堆积你的布局,然后把数据添加到 Widget 中,最后通过 setState 改变数据,从而实现画面变化。

import 'dart:async';import 'package:flutter/material.dart';class DemoStateWidget extends StatefulWidget { final String text; ////通过构造方法传值 DemoStateWidget(this.text); ///主要是负责创建state @override _DemoStateWidgetState createState() => _DemoStateWidgetState;}class _DemoStateWidgetState extends State<DemoStateWidget> { String text; _DemoStateWidgetState(this.text); @override void initState() { ///初始化,这个函数在生命周期中只调用一次 super.initState(); ///定时2秒 new Future.delayed(const Duration(seconds: 1), () { setState { text = "这就变了数值"; }); }); } @override void dispose() { ///销毁 super.dispose(); } @override void didChangeDependencies() { ///在initState之后调 Called when a dependency of this [State] object changes. super.didChangeDependencies(); } @override Widget build(BuildContext context) { return Container( child: Text(text ?? "这就是有状态DMEO"), ); }}

工具

Flutter SDK,Android Studio IDE,Flutter and Dart plugins for Android Studio IDE
参考Hello Flutter

步骤 1 : 创建及启动 Flutter app

这里创建一个简单的 flutter app

flutter create flutter_first_app
cd flutter_first_app
flutter run

如有疑问 , 可参考 前一篇文章 指引

简单地 , 我们先将 lib/main.dart中的代码全部删除 , 替换为以下代码 , 其主要就是在屏幕中间展示 'Hello World'

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'),
        ),
      ),
    );
  }
}

重新运行得到结果

图片 5

image

4、Flutter 布局

Flutter 中拥有需要将近30种内置的 布局Widget,其中常用有 Container、Padding、Center、Flex、Stack、Row、Colum、ListView 等,下面简单讲解它们的特性和使用。

图片 6Flutter布局.png

  • Container :最常用的默认布局!只能包含一个child:,支持配置 padding,margin,color,宽高,decoration(一般配置边框和阴影)等配置,在 Flutter 中,不是所有的控件都有 宽高、padding、margin、color 等属性,所以才会有 Padding、Center 等 Widget 的存在。
 new Container( ///四周10大小的maring margin: EdgeInsets.all, height: 120.0, width: 500.0, ///透明黑色遮罩 decoration: new BoxDecoration( ///弧度为4.0 borderRadius: BorderRadius.all(Radius.circular, ///设置了decoration的color,就不能设置Container的color。 color: Colors.black, ///边框 border: new Border.all(color: Color(GSYColors.subTextColor), width: 0.3)), child:new Text);

Colum、Row 绝对是必备布局, 横竖布局也是日常中最常见的场景。如下方所示,它们常用的有这些属性配置:主轴方向是 start 或 center 等;副轴方向方向是 start 或 center 等;mainAxisSize 是充满最大尺寸,或者只根据子 Widget 显示最小尺寸。

//主轴方向,Colum的竖向、Row我的横向mainAxisAlignment: MainAxisAlignment.start, //默认是最大充满、还是根据child显示最小大小mainAxisSize: MainAxisSize.max,//副轴方向,Colum的横向、Row我的竖向crossAxisAlignment :CrossAxisAlignment.center,

Expanded 在 Colum 和 Row 中代表着平均充满,当有两个存在的时候默认均分充满。同时页可以设置 flex 属性决定比例。

 new Column( ///主轴居中,即是竖直向居中 mainAxisAlignment: MainAxisAlignment.center, ///大小按照最小显示 mainAxisSize : MainAxisSize.min, ///横向也居中 crossAxisAlignment : CrossAxisAlignment.center, children: <Widget>[ ///flex默认为1 new Expanded(child: new Text, flex: 2,), new Expanded(child: new Text, ], );

接下来我们来写一个复杂一些的控件。首先我们创建一个私有方法_getBottomItem,返回一个 Expanded Widget,因为后面我们需要将这个方法返回的 Widget 在 Row 下平均充满。

如代码中注释,布局内主要是现实一个居中的Icon图标和文本,中间间隔5.0的 padding:

 ///返回一个居中带图标和文本的Item _getBottomItem(IconData icon, String text) { ///充满 Row 横向的布局 return new Expanded( flex: 1, ///居中显示 child: new Center( ///横向布局 child: new Row( ///主轴居中,即是横向居中 mainAxisAlignment: MainAxisAlignment.center, ///大小按照最大充满 mainAxisSize : MainAxisSize.max, ///竖向也居中 crossAxisAlignment : CrossAxisAlignment.center, children: <Widget>[ ///一个图标,大小16.0,灰色 new Icon( icon, size: 16.0, color: Colors.grey, ), ///间隔 new Padding(padding: new EdgeInsets.only), ///显示文本 new Text( text, //设置字体样式:颜色灰色,字体大小14.0 style: new TextStyle(color: Colors.grey, fontSize: 14.0), //超过的省略为...显示 overflow: TextOverflow.ellipsis, //最长一行 maxLines: 1, ), ], ), ), ); }

接着我们把上方的方法,放到新的布局里。如下流程和代码:

首先是 Container包含了Card,用于快速简单的实现圆角和阴影。然后接下来包含了FlatButton实现了点击,通过Padding实现了边距。接着通过Column垂直包含了两个子Widget,一个是Container、一个是Row。Row 内使用的就是_getBottomItem方法返回的 Widget ,效果如下图。

 @override Widget build(BuildContext context) { return new Container( ///卡片包装 child: new Card( ///增加点击效果 child: new FlatButton( onPressed: (){print;}, child: new Padding( padding: new EdgeInsets.only(left: 0.0, top: 10.0, right: 10.0, bottom: 10.0), child: new Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ ///文本描述 new Container( child: new Text( "这是一点描述", style: TextStyle( color: Color(GSYColors.subTextColor), fontSize: 14.0, ), ///最长三行,超过 ... 显示 maxLines: 3, overflow: TextOverflow.ellipsis, ), margin: new EdgeInsets.only(top: 6.0, bottom: 2.0), alignment: Alignment.topLeft), new Padding(padding: EdgeInsets.all, ///三个平均分配的横向图标文字 new Row( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ _getBottomItem(Icons.star, "1000"), _getBottomItem(Icons.link, "1000"), _getBottomItem(Icons.subject, "1000"), ], ), ], ), ))), ); }

Flutter 中,你的布局很多时候就是这么一层一层嵌套出来的,当然还有其他更高级的布局方式,这里就先不展开了。

5、Flutter 页面

Flutter 中除了布局的 Widget,还有交互显示的 Widget 和完整页面呈现的Widget。其中常见的有 MaterialApp、Scaffold、Appbar、Text、Image、FlatButton等。下面简单介绍这些 Wdiget,并完成一个页面。

图片 7Flutter页面.png

那么再次直插主题实现一个简单完整的页面试试。如下方代码:

首先我们创建一个StatefulWidget:DemoPage。然后在 _DemoPageState中,通过build创建了一个Scaffold。Scaffold内包含了一个AppBar和一个ListView。AppBar类似标题了区域,其中设置了 title为 Text Widget。body是ListView,返回了20个之前我们创建过的 DemoItem Widget。

import 'package:flutter/material.dart';import 'package:gsy_github_app_flutter/test/DemoItem.dart';class DemoPage extends StatefulWidget { @override _DemoPageState createState() => _DemoPageState();}class _DemoPageState extends State<DemoPage> { @override Widget build(BuildContext context) { ///一个页面的开始 ///如果是新页面,会自带返回按键 return new Scaffold( ///背景样式 backgroundColor: Colors.blue, ///标题栏,当然不仅仅是标题栏 appBar: new AppBar( ///这个title是一个Widget title: new Text, ), ///正式的页面开始 ///一个ListView,20个Item body: new ListView.builder( itemBuilder: (context, index) { return new DemoItem(); }, itemCount: 20, ), ); }}

最后我们创建一个StatelessWidget作为入口文件,实现一个MaterialApp将上方的DemoPage设置为home页面,通过main入口执行页面

import 'package:flutter/material.dart';import 'package:gsy_github_app_flutter/test/DemoPage.dart';void main() { runApp(new DemoApp;}class DemoApp extends StatelessWidget { DemoApp({Key key}) : super; @override Widget build(BuildContext context) { return new MaterialApp(home: DemoPage; }}

好吧,第一部分终于完了,这里主要讲解都是一些简单基础的东西,适合安利入坑,后续还有两篇主要实战,敬请期待哟!ゞ

  • 创建一个基本list
  • 创建一个水平list
  • 使用长列表
  • 创建不同类型子项的List
  • 创建一个 grid List

第一步 创建App

创建过程很简单就省略了,可以参考Hello Flutter和官网
1.替换lib/main.dart,
lib/main.dart的位置:如果不是Project切换

图片 8

文件结构.png

我们要编辑的就是蓝色框里的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'),
        ),
      ),
    );
  }
}

2.运行效果

图片 9

运行效果

小结

  • 这个例子创建了一个MaterialApp。 Material 是一种手机和网页的视觉设计(visual design)语言标准。Flutter提供了丰富的Material组件。
  • main方法指定了用于一行函数或方法的肥箭头=>(fat arrow)标记,哈哈,肥箭头!
  • 这个App扩展了StatelessWidget,App本身也是一个组件。(The app extends StatelessWidget which makes the app itself a widget)。在Flutter中,几乎所有东西都是组件,包括alignment, padding, layout.
  • 来自于Material库的支架(Scaffold)组件提供了默认的app bar,title,body属性,它用来保存/容纳(holds)主屏幕的组件树(widget tree).它的子树(subtree)可能非常复杂。
  • 组件的主要功能就是提供描述如何展示其他组件或低等级(lower level)组件的build()方法。
翻译不好原文如下
A widget’s main job is to provide a build() method that describes how to display the widget in terms of other, lower level widgets.

ps 简单说 组件提供build()方法,描述如何展示其他组件或者子组件(lower level widget翻译为子组件如何?)

  • 这个例子的组件树包括Center组件,Center中包含了一个子组件TextCenter对齐(align)它的子组件树到屏幕中心

发现

  • 这个例子创建了一个 Material Design 风格的app . Material 是一种在移动端及web上标准的视觉设计语言 . Flutter 提供了丰富的 Material 风格小部件
  • main 方法使用了一个大箭头=>写法 , 它是一行代码功能或方法的缩写
  • app 继承 StatefulWidget 使得其自身也是个widget . 在 Flutter 里 , 大多数元素都是 widget , 包括对齐方式(alignment)、 内边距(padding)、布局(layout) .
  • Material 库 中的脚手架小部件 (Scaffold widget) , 提供了一个默认的导航栏、 标题、 内容属性在屏幕中维持了部件树

    本文由新葡京8455发布,转载请注明来源

    关键词: