一、简介
Flutter
是谷歌的移动UI
框架,可以快速在iOS
和Android
上构建高质量的原生用户界面。Flutter
用Dart
作为开发框架和widget
的语言。
二、优势
React-Native
、Weex
核心是通过Javascript
开发,执行时需要Javascript
解释器,UI
是通过原生控件渲染。Flutter使用C
、C ++
、Dart和Skia
(2D
渲染引擎)构建。在IOS
上,Flutter
引擎的C/C ++
代码使用LLVM
编译,任何Dart
代码都是AOT
编译为本地代码的,Flutter
应用程序使用本机指令集运行(不涉及解释器)。而在Android
下,Flutter
引擎的C/C ++
代码是用Android
的NDK
编译的,任何Dart
代码都是AOT
编译成本地代码的,Flutter
应用程序依然使用本机指令集运行(不涉及解释器)。因此,Flutter
能达到原生应用一样的性能。
三、资源网站
Flutter
教程网:http://www.flutterj.com/?post=47
Flutter
插件网站: https://pub.flutter-io.cn/
Flutter
中文网: https://flutterchina.club/
Flutter
自带的例子:在Flutter
安装路径的example
目录下就有例子,推荐学习一遍,很不错。
四、开发自己的一个APP
一个通用的APP
,基本上是由以下几部分组成的:
导航栏+内容区+底部菜单栏就是我们整个APP
的骨架,其他的页面也是在这个上面去扩展。
接下来,看一下我要实现的样子:
下面将一步步讲述实现过程。
4.1. 创建一个TabNavigator.dart
文件
该文件是核心文件,我们的页面等页面都需要注册到里面。我们需要借助Scaffold
脚手架实现这个功能。
4.1.1. 代码实现
import 'package:blog/pages/BlogPage.dart';
import 'package:blog/pages/HomePage.dart';
import 'package:blog/pages/SelfPage.dart';
import 'package:blog/pages/SourcePage.dart';
import 'package:flutter/material.dart'; // 这个是必须引入的要注意
class TabNavigator extends StatefulWidget {
@override
_TabNavigatorState createState() => _TabNavigatorState();
}
class _TabNavigatorState extends State<TabNavigator> {
// 菜单栏 默认颜色和激活颜色
final _defaultColor = Colors.white;
final _activeColor = Colors.black54;
// 记录当前那个item被选中·
int _currentIndex = 0;
// 创建一个页面控制器, 并将页面的initialPage,初始为 0
final PageController _pageController = PageController(initialPage: 0);
@override
Widget build(BuildContext context) {
// 脚手架
return Scaffold(
// 在内容区使用PageView将首页等页面注册进去
body: PageView(
// 设置页面切换的方法
onPageChanged: (index) {
// setState 更新_currentIndex
setState(() {
_currentIndex = index;
});
},
controller: _pageController,
children: <Widget>[
HomePage(),
BlogPage(),
SourcePage(),
SelfPage()
],
),
// 设置底部导航栏组
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
// 设置图标,flutter的图标下面有链接
icon: Icon(Icons.home, color: _defaultColor),
// 被选中之后的图标
activeIcon: Icon(Icons.home, color: _activeColor),
// 设置文字颜色
title: Text('首页', style: TextStyle(color: _currentIndex != 0 ? _defaultColor : _activeColor))
),
BottomNavigationBarItem(
icon: Icon(Icons.event_note, color: _defaultColor),
activeIcon: Icon(Icons.event_note, color: _activeColor),
title: Text('文章', style: TextStyle(color: _currentIndex != 1 ? _defaultColor : _activeColor))
),
BottomNavigationBarItem(
icon: Icon(Icons.storage, color: _defaultColor),
activeIcon: Icon(Icons.storage, color: _activeColor),
title: Text('资源', style: TextStyle(color: _currentIndex != 2 ? _defaultColor : _activeColor))
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle, color: _defaultColor),
activeIcon: Icon(Icons.account_circle, color: _activeColor),
title: Text('我的', style: TextStyle(color: _currentIndex != 3 ? _defaultColor : _activeColor))
)
],
// 设置最初的item下标
currentIndex: _currentIndex,
// 点击之后,跳转页面,修改_currentIndex
onTap: (index) {
print(index);
_pageController.jumpToPage(index);
setState(() {
_currentIndex = index;
});
},
// 设置没有被点击也显示文字
type: BottomNavigationBarType.fixed,
// 设置背景色
backgroundColor: Colors.blue
),
);
}
}
4.1.2. Scaffold
参数详解
接下来,我们来重点介绍一下这个脚手架的一个参数(也可以查看官网文档:https://api.flutter.dev/flutter/material/Scaffold/Scaffold.html):
class Scaffold extends StatefulWidget {
/// Creates a visual scaffold for material design widgets.
const Scaffold({
Key key,
this.appBar, // 用来定义顶部导航栏
this.body, // 用来展示APP的主体部分, 主体部分大部分是通过组合Container,Column,Row,Stack来实现的
this.floatingActionButton, // 定义浮动在body右下角的组件。Flutter项目创建之后默认那个例子中就用到了这个参数。
this.floatingActionButtonLocation, // 浮动按钮放置的位置,4个枚举
this.floatingActionButtonAnimator, // 浮动按钮放置的动画
this.persistentFooterButtons, // 固定在下方显示的按钮
this.drawer, // 左侧边栏控件,就是那个像QQ一样的抽屉
this.endDrawer, // 右侧边栏控件
this.bottomNavigationBar, // 底部菜单栏,可以传入一个Flutter 提供的BottomNavigationBar来实现导航栏
this.bottomSheet, // 从底部弹出一个Widget, Flutter提供了两种方式显示,形式有点不同,一个是ModalBottomSheet, 一个是PersistentBottomSheet。
this.backgroundColor, // 背景颜色
this.resizeToAvoidBottomPadding, // 控制界面内容body是否重新布局来避免底部被覆盖了,比如当键盘显示的时候,重新布局避免被键盘盖住内容。默认值为 true, 此功能在v1.1.9之后不推荐使用。
this.resizeToAvoidBottomInset, // 如果在支架上方显示了屏幕上的键盘,则可以调整主体的大小以避免键盘重叠,这可以防止键盘遮盖主体内部的小部件。
this.primary = true, // 是否填充顶部
this.drawerDragStartBehavior = DragStartBehavior.start,
this.extendBody = false,
this.extendBodyBehindAppBar = false,
this.drawerScrimColor, // 用于在打开抽屉时遮罩背景颜色。
this.drawerEdgeDragWidth, // 水平滑动将打开抽屉的区域的宽度
}) : assert(primary != null),
assert(extendBody != null),
assert(extendBodyBehindAppBar != null),
assert(drawerDragStartBehavior != null),
super(key: key);
......
}
Flutter
的图标网站: https://material.io/resources/icons/?style=baseline
4.1.3. PageView
参数详解
PageView
在Android
中也是很常用的一个控件,可以配合TabBar
、BottomBar
做页面切换。也有很多广告Banner
页用PageView
来实现。Flutter
也有这个Widget
,用法更灵活方便。
PageView({
Key key,
this.scrollDirection = Axis.horizontal, // 可以控制滚动方向, 横向和纵向
this.reverse = false, // 是控制滚动方向,比如横向滚动的时候,一般我们是从右往左滚动,这个参数设置成true就是默认反一反,变成从左往右滚动。
PageController controller, // 页面控制器,可以控制跳转到某一页,可以控制PageView初始显示页面等
this.physics, // 是处理滚动到最前或滚动到最后的时候的动画效果,Flutter默认有提供几个实现好的效果,BouncingScrollPhysics、ClampingScrollPhysics等
this.pageSnapping = true, // 控制滚动方式, 默认是PageView都是一页一页翻的, 设置为false 是 PageView就可以一点点滚动,就是不用整页滚动过去,滚动到一半的时候也能停下来。
this.onPageChanged, // 监听事件,页面切换就调用一次,并传回当前显示页面的序号。
List<Widget> children = const <Widget>[], // 存放要切换的页面
this.dragStartBehavior = DragStartBehavior.start, // 处理拖动开始行为的方式。 如果设置为DragStartBehavior.start,则将在检测到拖动手势时开始滚动拖动行为。如果设置为 DragStartBehavior.down,它将在首次检测到down事件时开始。
}) : controller = controller ?? _defaultPageController,
childrenDelegate = SliverChildListDelegate(children),
super(key: key);
PageView
提供了另外两种的构造方法:这种方式需要注意一点,如果不设置itemCount,PageView
默认是无限个数的,也就是能一直往后翻页下去,index一直往上增加。
static var users = [
'http://xxxx',
'http://xxxx',
'http://xxxx'
]
PageView.builder(
itemBuilder: (context, index){
return Center(
child: Image.network(urls[index], fit: BoxFit.fitWidth),
);
},
itemCount: urls.length,
)
另一个方式是通过custom
,更加底层点,需要提供SliverChildDelegate
,生成所有的子页面。一般使用不需要用到这个。就不上代码了。
4.2. 修改main.dart
还需要修改默认的main.dart
代码,将我们的TabNavigator.dart
引进去。
import 'package:blog/navigator/TabNavigator.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// 注入我们的 TabNavigator()
home: TabNavigator(),
);
}
}
4.3. 增加首页
这里首页和其他的页面一样,大同小异,只介绍HomePage
,这里这个页面我们就加一个导航栏。
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
// 增加顶部导航栏
appBar: AppBar(
// 文字居中
centerTitle: true,
title: Text('首页')
),
// 内容区就简单加一个居中文字
body: Center(
child: Text("首页"),
),
);
}
}
这样就可以实现上面那个效果,基本上APP
的骨架就搭建好了。
4.1.3. 导航栏AppBar
参数详解
AppBar({
Key key,
this.leading, // 在标题前面显示的一个控件,在首页通常显示应用的 logo;在其他界面通常显示为返回按钮
this.automaticallyImplyLeading = true,
this.title, // Toolbar 中主要内容,通常显示为当前界面的标题文字
this.actions, // 一个 Widget 列表,代表 Toolbar 中所显示的菜单,对于常用的菜单,通常使用 IconButton 来表示;对于不常用的菜单通常使用 PopupMenuButton 来显示为三个点,点击后弹出二级菜单。
this.flexibleSpace,
this.bottom, // 这个小部件出现在应用程序栏的底部。 通常是一个TarBar,即一个标签栏
this.elevation,
this.shape,
this.backgroundColor, // 背景色
this.brightness, // Appbar的亮度,有白色和黑色两种主题,默认ThemeData.primaryColorBrightness
this.iconTheme, // icon主题设置
this.actionsIconTheme, // 选中icon主题
this.textTheme, // 文本主题设置
this.primary = true, // 是否显示在任务栏顶部
this.centerTitle, // 标题是否居中显示
this.titleSpacing = NavigationToolbar.kMiddleSpacing, // 横轴上围绕title内容的间距 0.0即占据所有有用空间
this.toolbarOpacity = 1.0, // 应用程序栏的工具栏的透明程度。值1.0是完全不透明的,值0.0是完全透明的
this.bottomOpacity = 1.0, // appBar底部透明度,设置方式同toolbarOpacity
}) : assert(automaticallyImplyLeading != null),
assert(elevation == null || elevation >= 0.0),
assert(primary != null),
assert(titleSpacing != null),
assert(toolbarOpacity != null),
assert(bottomOpacity != null),
preferredSize = Size.fromHeight(kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)),
super(key: key);