一、簡介
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);