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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章