热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Flutter入门实例

Dart4Flutter-01–变量,类型和函数Dart4Flutter–02–控制流和异常Dart4Flutter–03–类和泛型Dart4Flutter–04–异步和库Dart

Dart4Flutter -01 – 变量, 类型和 函数

Dart4Flutter – 02 –控制流 和异常

Dart4Flutter – 03 – 类和泛型

Dart4Flutter – 04 – 异步和库

Dart4Flutter -拾遗01 – flutter-dart环境搭建

flutter入门 – 状态管理

Flutter 入门实例1

Flutter 入门-本地访问-MethodChannel

自从10年前Android和iOS出现,在移动开发界,跨平台开发一直是一个目标。一个跨平台的应用可以帮助公司和团队节省大量的时间和精力。

过去这些年,已经发布了很多跨平台的开发工具,包括来自adobe基于web的PhoneGap,来自Microsoft的Xamarin,来自Facebook的React Native。

最近进入跨平台界的工具是来自google的flutter,现在已经发布了第一个预览版。flutter拥有开发效率高、UI渲染快,更容易的自定义组件、和在两个平台上和本地应用一样的性能。

介绍

flutter应用是用dart语言开发的,Dart和其他语言,例如Kotlin Swift一样,拥有很多共同的语言特性,而且可以转化为Javascript代码。

作为一个跨平台框架,flutter非常像React Native,例如flutter支持响应式和声明是编程。但是和React Native不一样的是,flutter不需要Javascript桥接,这样可提升整个应用的性能和应用启动的时间。Dart是通过AOT技术取得了上述的表现。

另一方面,拥有JIT的Flutter,支持在开发期间,不需要从头构建整个应用,就可以刷新UI,提供开发效率。

正如本教程将要展示的,flutter框架是建立在组件思想之上的。在flutter中,组件不单单指应用的视图,而是整个界面甚至是真个应用。

除了开发跨Android和iOS应用,学习flutter将给你一个在Fuchsia平台开发的超前开始。Fuchsia是google开发中的实验性的操作系统。

本教程,我们构建一个app,首先从github api中获取一个组织的成员信息,然后将成员信息展示在一个滚动列表中。
《Flutter 入门实例》

当开发app时,可是使用Android模拟器、iOS模拟器或者同时使用。

在构建app时,我们将学习flutter一下内容:

  • 配置开发环境
  • 创建工程
  • Hot reload
  • 引入文件和库
  • 使用组件和创建自己的组件
  • 创建网络请求
  • 在列表中展示列表项
  • 添加应用主题
    有也将顺便学习一点Dart。

开始

Flutter开发可以在macOS,Linux或Windows上完成。 虽然您可以在Flutter工具链中使用任何编辑器,但IntelliJ IDEA,Android Studio和Visual Studio Code的IDE插件可以简化开发工作。 我们将在本教程中使用Android Studio。

配置开发环境

您可以在这找到配置flutter开发环境的说明,具体步骤因平台而异,但主要步骤是:

  1. 下载flutter SDK,地址
  2. 将flutter的bin目录添加到path中
  3. 执行flutter doctor命令,他会安装flutter框架,包括dart,而且提示你任何其他需要安装的依赖。
  4. 安装其他依赖
  5. 在IDE中安装flutter插件
  6. 测试驱动应用
    Flutter网站上提供的说明做得非常好,并允许您在所选平台上轻松设置开发环境。 本教程的其余部分假设您已经为Flutter开发设置了Android Studio,并且您已经解决了flutter doctor发现的任何问题。

创建工程

  • 如下所示选择File->new->new Flutter Project
    《Flutter 入门实例》
  • 如下所示选择Flutter Application,点击next.
    《Flutter 入门实例》
  • 如下如所示填写项目名称、Flutter SDK的路径、项目存储目录。
    《Flutter 入门实例》

在Android Studio中,您会在左侧看到一个显示项目结构的面板。 有iOS和Android的文件夹,以及包含main.dart的lib文件夹。 您将本教程中的只在lib文件夹中工作。
《Flutter 入门实例》
将main.dart中的代码替换为以下内容:

import 'package:flutter/material.dart';
void main() => runApp(new GHFlutterApp());
class GHFlutterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'GHFlutter',
home: new Scaffold(
appBar: new AppBar(
title: new Text('GHFlutter'),
),
body: new Center(
child: new Text('GHFlutter'),
),
),
);
}
}

顶部附近的main()函数使用=>运算符,为了单行函数运行应用程序。 您有一个名为GHFlutterApp的应用程序。
你在这里看到你的应用程序本身是一个StatelessWidget(无状态组件)。Flutter应用程序中的大多数实体都是组件,无论是无状态的还是有状态的。 您重写组件的build()方法来创建您的应用的组件。 您正在使用MaterialApp 组件,该组件提供了大量遵循Material Design规范应用组件。

对于本入门教程,通过选择它并敲击Delete键,从项目中删除test文件夹中的测试文件widget_test.dart

你可以在macOS上,启动iOS模拟器。 您也可以在macOS,Linux或Windows上使用Android模拟器。

《Flutter 入门实例》

您看到的慢速模式banner表示应用程序正在以调试模式运行。

您可以通过单击Android Studio窗口顶部工具栏右侧的停止按钮来停止正在运行的应用程序:

《Flutter 入门实例》

Hot Reload

flutter支持Hot Reload 功能。flutter中的Hot reload和Android Studio的Instant Run类似。
构建并运行应用程序,使其在模拟器或模拟器上运行:
《Flutter 入门实例》
现在,不停止正在运行的应用程序,将应用程序栏字符串更改为其他内容:

appBar: new AppBar(
title: new Text('GHFlutter App'),
),

现在单击工具栏上的热重新加载按钮:
《Flutter 入门实例》
在一两秒钟内,您会看到正在运行的应用程序中反映了变化的内容:

由于Flutter处于开发阶段,热重新加载功能可能无法正常工作,但总体而言,在构建UI时节省时间。

引入文件

您不需要将所有的Dart代码保存在一个main.dart文件中,而是希望能够从您创建的其他类中导入。 现在您将看到一个用于导入字符串的示例,这将有助于您应用的本地化。
在lib文件夹中右键单击并选择New File创建一个名为strings.dart的文件:
在新建的文件中添加如下类:

class Strings {
static String appTitle = "GHFlutter";
}

在main.dart的顶部添加如下引入:

import 'strings.dart';

如下更新应用的title:

return new MaterialApp(
title: Strings.appTitle,

更新其他的字符串,使用新的字符串文件,所以最终GHFlutterApp类如下:

class GHFlutterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: Strings.appTitle,
home: new Scaffold(
appBar: new AppBar(
title: new Text(Strings.appTitle),
),
body: new Center(
child: new Text(Strings.appTitle),
),
),
);
}
}

构建并运行应用程序,您应该看不到任何变化,但现在您正在使用字符串文件中的字符串。

组件

几乎Flutter应用程序的每个元素都是一个组件。组件被设计成不可变的,因为使用不可变组件有助于保持应用程序UI的轻量级。

您将使用两种基本类型的组件:

Stateless: 仅依赖于自己的配置信息的组件,例如图像视图中的静态图像
Stateful: 需要维护动态信息的组件,并通过与状态对象交互来实现
无状态和有状态的组件在每个帧的Flutter应用程序中重绘,不同之处在于有状态组件将其配置委托给状态对象。

要开始制作自己的组件,请在main.dart的底部创建一个新类:

class GHFlutter extends StatefulWidget {
@override
createState() => new GHFlutterState();
}

你已经创建了一个StatefulWidget子类,并且你重写了createState()方法来创建它的状态对象。 现在在GHFlutter上添加一个GHFlutterState类:

class GHFlutterState extends State {
}

GHFlutterState使用GHFlutter的参数扩展状态。

制作新组件时的主要任务是重写在组件呈现在屏幕上时调用的build()方法。

重写GHFlutterState 的build()方法:

@override
Widget build(BuildContext context) {

}

最终如下:

@override
Widget build(BuildContext context) {
return new Scaffold (
appBar: new AppBar(
title: new Text(Strings.appTitle),
),
body: new Text(Strings.appTitle),
);
}

Scaffold 是material design组件的容器。 它充当组件层次结构的根。 您已将AppBar和一个body添加到scaffold中,并且每个都包含一个Text组件

更新GHFlutterApp,以便它使用新的GHFlutter组件作为其home属性,而不是构建默认的scaffold:

class GHFlutterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: Strings.appTitle,
home: new GHFlutter(),
);
}
}

构建并运行应用程序,您将看到新的组件正在运行:
《Flutter 入门实例》
现在还没有多少变化,但是现在你已经开始构建新的组件。

网络请求

之前,您将自己的strings.dart文件导入到项目中。 您可以同样导入Flutter框架的其他库或者Dart的库。

例如,您现在将使用框架中的库来进行HTTP网络调用,并将生成的JSON响应解析为Dart对象。 在main.dart的顶部添加两个新的引入:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'strings.dart';

您会看到当前未使用的指标在引入上。

Dart应用程序是单线程的,但Dart支持在其他线程上运行代码以及运行异步代码,通过使用async/await模式,从而不会阻止UI线程。

您将进行异步网络调用以检索GitHub组织成员列表。 在GHFlutterState顶部添加一个空List作为属性,并添加一个属性来保存文本样式(_biggerFont):

var _members = [];
final _biggerFOnt= const TextStyle(fontSize: 18.0);

名字以下划线开头的变量表示类的私有成员变量。
要进行异步HTTP调用,请在GHFlutterState中添加一个_loadData()方法:

_loadData() async {
String dataURL = "https://api.github.com/orgs/raywenderlich/members";
http.Response respOnse= await http.get(dataURL);
setState(() {
_members = JSON.decode(response.body);
});
}

您已将async关键字添加到_loadData()中,以告诉Dart它是异步的,但是http.get()的await关键字表示阻塞执行。 通过dataUrl设置API的请求地址。

当HTTP调用完成时,您将回调传递给在UI线程上同步运行的setState()。 这时,您解码JSON响应并将其赋值给_members变量。
在GHFlutterState中重写initState方法,在initState中调用_loadData() 方法。当组件状态初始化时,_loadData()会被调用,加载数据。

@override
void initState() {
super.initState();
_loadData();
}

使用 ListView

现在您已经有了成员列表,您需要一种方法在列表UI中显示它们。 Dart提供了一个ListView组件,可让您在列表中显示数据。 ListView的作用类似于Android上的RecyclerView和iOS上的UITableView,通过重复回收利用以后的view,使列表滚动更加顺滑。
在GHFlutterState中添加_buildRow()方法:

Widget _buildRow(int i) {
return new ListTile(
title: new Text("${_members[i]["login"]}", style: _biggerFont)
);
}

您将返回一个ListTile组件,该组件显示第iJSON成员的”login”值,还使用您之前创建的文本样式(_biggerFont)。

更新build方法,使body属性值为ListView.builder:

body: new ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: _members.length,
itemBuilder: (BuildContext context, int position) {
return _buildRow(position);
}),

您已添加padding,将itemCount设置为成员数量,设置itemBuilder调用_buildRow(),传递postion变量。

您可以尝试热重新加载,但可能会收到”Full restart may be required”的消息。 如果是这样,重启:
《Flutter 入门实例》

发起网络请求,解析数据,并在列表中显示结果是很容易的!
《Flutter 入门实例》

添加分割线

为了在列表中增加分割线,需要翻倍list的itemCount属性,然后list中的position为偶数时返回Divider组件。

body: new ListView.builder(
itemCount: _members.length * 2,
itemBuilder: (BuildContext context, int position) {
if (position.isOdd) return new Divider();
final index = position ~/ 2;
return _buildRow(index);
}),

一定要itemCount翻倍,因为增加了分割线,所以删除padding。在itemBuilder中,返回Divider组件,或者通过整数除法计算一个新的index,利用_buildRow(index)返回一个组件。

尝试重新加载,你应该在列表中看到分割线:
《Flutter 入门实例》
要在每行中添加padding,可以在_buildRow()中使用Padding组件:

Widget _buildRow(int i) {
return new Padding(
padding: const EdgeInsets.all(16.0),
child: new ListTile(
title: new Text("${_members[i]["login"]}", style: _biggerFont)
)
);
}

ListTile现在是Padding的子部件。 热加载以查看行上的padding而不是分隔符上的Padding。

解析为自定义类型

在上一节中,JSON解析器将JSON响应中的每个成员都作为Dart Map类型实例添加到_members列表中,这相当于Kotlin中的Map或Swift中的Dictionary。
但是,如果你想使用自定义类。
在main.dart文件中添加Member类:

class Member {
final String login;
Member(this.login) {
if (login == null) {
throw new ArgumentError("login of Member cannot be null. "
"Received: '$login'");
}
}
}

member有一个login属性,和一个构造函数,在构造函数中当login值为null时,会抛出一个error。
更新GHFlutterState类中的_members变量声明,所以现在他就是一个Member对象的list

var _members = [];

更新_buildRow()方法使用Member对象的login属性而不是map的”login”key的值。

title: new Text("${_members[i].login}", style: _biggerFont)

现在更新在_loadData()中的传递给setState()的回调,将map解析为Member对象,添加到member对象list中。

setState(() {
final membersJSON = JSON.decode(response.body);
for (var memberJSON in membersJSON) {
final member = new Member(memberJSON["login"]);
_members.add(member);
}
});

如果你热加载,有可能看到一个错误,这时你重新启动。

下载图片

每个member都有一个头像url.你将添加头像到Member类中,然后在app中显示头像。

在Member类中添加avatarUrl属性,这个属性不能为null。

class Member {
final String login;
final String avatarUrl;
Member(this.login, this.avatarUrl) {
if (login == null) {
throw new ArgumentError("login of Member cannot be null. "
"Received: '$login'");
}
if (avatarUrl == null) {
throw new ArgumentError("avatarUrl of Member cannot be null. "
"Received: '$avatarUrl'");
}
}
}

更新_buildRow()方法,通过NetworkImage 和 the CircleAvatar 组件显示头像。

Widget _buildRow(int i) {
return new Padding(
padding: const EdgeInsets.all(16.0),
child: new ListTile(
title: new Text("${_members[i].login}", style: _biggerFont),
leading: new CircleAvatar(
backgroundColor: Colors.green,
backgroundImage: new NetworkImage(_members[i].avatarUrl)
),
)
);
}

设置头像为ListTile的leading属性,头像将显示在title的前面。
更新_loadData()方法,使在创建一个新的Member时使用map的”avatar_url”值。

final member = new Member(memberJSON["login"], memberJSON["avatar_url"]);

构建运行,你将能看到每一个行的头像。
《Flutter 入门实例》

整理代码

大部分代码现在位于main.dart文件中。 为了使代码更清晰一点,你可以重构组件和你已经添加到他们自己的文件中的类。
在lib文件夹中创建名为member.dart和ghflutter.dart的文件。 将Member类移入member.dart,并将GHFlutterState和GHFlutter类转移到ghflutter.dart。
您不需要member.dart中的任何导入语句,但flutter.dart中的导入应如下所示:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'member.dart';
import 'strings.dart';

您还需要更新main.dart中的导入,所以整个文件包含以下内容:

import 'package:flutter/material.dart';
import 'ghflutter.dart';
import 'strings.dart';
void main() => runApp(new GHFlutterApp());
class GHFlutterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: Strings.appTitle,
home: new GHFlutter(),
);
}
}

通过构建并运行应用程序,您应该看不到任何更改,但代码现在更清晰一些

添加主题

您可以通过将主题属性添加到您在main.dart中创建的MaterialApp来轻松地将主题添加到应用程序:

lass GHFlutterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: Strings.appTitle,
theme: new ThemeData(primaryColor: Colors.green.shade800),
home: new GHFlutter(),
);
}
}

您正在使用绿色阴影作为Material Design主题颜色值。

构建并运行应用程序,以查看新的主题:

《Flutter 入门实例》

大部分应用截图都来自Android模拟器。 您也可以在iOS模拟器中运行最终的主题应用程序:
《Flutter 入门实例》
这就是我所说的跨平台

最终代码地址

参考

https://www.raywenderlich.com/188257/getting-started-with-flutter


推荐阅读
  • 本文探讨了如何在 Google Sheets 中通过自定义函数实现 AJAX 调用。具体介绍了编写脚本的方法,以便在电子表格中发起 AJAX 请求,从而实现数据的动态获取与更新。这种方法不仅简化了数据处理流程,还提高了工作效率。 ... [详细]
  • TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得
    TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得 ... [详细]
  • 作为140字符的开创者,Twitter看似简单却异常复杂。其简洁之处在于仅用140个字符就能实现信息的高效传播,甚至在多次全球性事件中超越传统媒体的速度。然而,为了支持2亿用户的高效使用,其背后的技术架构和系统设计则极为复杂,涉及高并发处理、数据存储和实时传输等多个技术挑战。 ... [详细]
  • 今日精选:10款实用的jQuery随机效果插件
    在今天的精选内容中,我们推荐了10款实用的jQuery随机效果插件。这些插件不仅功能强大,而且设计精良,能够为您的网页增添独特的互动体验。从动态图像效果到文本动画,每款插件都提供了丰富的自定义选项,帮助开发者轻松实现创意视觉效果。特别值得一提的是,其中一款插件集成了与Google API的无缝对接,使数据展示更加生动和直观。 ... [详细]
  • EMURGO Africa 与 Adaverse 合作投资 Momint,推动 Cardano NFT 生态系统在非洲市场的扩展 ... [详细]
  • Framework7:构建跨平台移动应用的高效框架
    Framework7 是一个开源免费的框架,适用于开发混合移动应用(原生与HTML混合)或iOS&Android风格的Web应用。此外,它还可以作为原型开发工具,帮助开发者快速创建应用原型。 ... [详细]
  • 如何在Linux服务器上配置MySQL和Tomcat的开机自动启动
    在Linux服务器上部署Web项目时,通常需要确保MySQL和Tomcat服务能够随系统启动而自动运行。本文将详细介绍如何在Linux环境中配置MySQL和Tomcat的开机自启动,以确保服务的稳定性和可靠性。通过合理的配置,可以有效避免因服务未启动而导致的项目故障。 ... [详细]
  • 在 Vue 应用开发中,页面状态管理和跨页面数据传递是常见需求。本文将详细介绍 Vue Router 提供的两种有效方式,帮助开发者高效地实现页面间的数据交互与状态同步,同时分享一些最佳实践和注意事项。 ... [详细]
  • 本文深入探讨了 hCalendar 微格式在事件与时间、地点相关活动标记中的应用。作为微格式系列文章的第四篇,前文已分别介绍了 rel 属性用于定义链接关系、XFN 微格式增强链接的人际关系描述以及 hCard 微格式对个人和组织信息的描述。本次将重点解析 hCalendar 如何通过结构化数据标记,提高事件信息的可读性和互操作性。 ... [详细]
  • Hadoop 2.6 主要由 HDFS 和 YARN 两大部分组成,其中 YARN 包含了运行在 ResourceManager 的 JVM 中的组件以及在 NodeManager 中运行的部分。本文深入探讨了 Hadoop 2.6 日志文件的解析方法,并详细介绍了 MapReduce 日志管理的最佳实践,旨在帮助用户更好地理解和优化日志处理流程,提高系统运维效率。 ... [详细]
  • 当前,众多初创企业对全栈工程师的需求日益增长,但市场中却存在大量所谓的“伪全栈工程师”,尤其是那些仅掌握了Node.js技能的前端开发人员。本文旨在深入探讨全栈工程师在现代技术生态中的真实角色与价值,澄清对这一角色的误解,并强调真正的全栈工程师应具备全面的技术栈和综合解决问题的能力。 ... [详细]
  • REST API 时代落幕,GraphQL 持续引领未来
    尽管REST API已广泛使用多年,但在深入了解GraphQL及其解决的核心问题后,我深感其将引领未来的API设计趋势。GraphQL不仅提高了数据查询的效率,还增强了灵活性和性能,有望成为API开发的新标准。 ... [详细]
  • 如何有效解决MySQL中预编译语句失效的问题及专业应对策略 ... [详细]
  • vue github开源项目_2018 年最好的 45 个 Vue 开源项目汇总
    vuegithub开源项目_2018年最好的45个Vue开源项目汇总,Go语言社区,Golang程序员人脉社 ... [详细]
  • 网站秒开算什么,Google
    作为一家活在Web世界的公司,Google对提升网页性能一直是不遗余力。今天,为了让用户能够更快地浏览网页,Google联合8家科技公司以及近30家新闻机构一起发布了一个名为移动页 ... [详细]
author-avatar
手机用户2502882485
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有