Flutter之導航欄骨架實現

一、簡介

Flutter是谷歌的移動UI框架,可以快速在iOSAndroid上構建高質量的原生用戶界面。FlutterDart作爲開發框架和widget的語言。

二、優勢

React-NativeWeex核心是通過Javascript開發,執行時需要Javascript解釋器,UI是通過原生控件渲染。Flutter使用CC ++、Dart和Skia2D渲染引擎)構建。在IOS上,Flutter引擎的C/C ++代碼使用LLVM編譯,任何Dart代碼都是AOT編譯爲本地代碼的,Flutter應用程序使用本機指令集運行(不涉及解釋器)。而在Android下,Flutter引擎的C/C ++代碼是用AndroidNDK編譯的,任何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參數詳解

PageViewAndroid中也是很常用的一個控件,可以配合TabBarBottomBar做頁面切換。也有很多廣告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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章