霸圖鎮(zhèn)樓
仿閑魚底部導(dǎo)航欄帶有中間凸起圖標
需求情景: 需要實現(xiàn)一個類似閑魚APP的底部導(dǎo)航欄的實現(xiàn)
Demo地址 : https://github.com/hanlin19900610/flutter_bottom_navigation_bar
要實現(xiàn)的效果如圖
好的,下面開始上代碼了:
一. 在main.dart文件中,定義APP的入口信息
import 'package:flutter/material.dart';import 'pages/MainPage.dart';void main() => runApp(LightLanguageClient());class LightLanguageClient extends StatelessWidget{ @override
Widget build(BuildContext context) { return MaterialApp(
title: 'Demo',
theme: ThemeData(
primarySwatch: Colors.blue
),
home: MainPage(),
);
}
}
二. 我們需要定義三個頁面,功能類似Android的Fragment,分別為HomePage.dart, AssistantPage.dart,MinePage.dart, 這三個頁面的代碼很簡單:
import 'package:flutter/material.dart';class HomePage extends StatefulWidget{ @override
State<StatefulWidget> createState() { return _HomePageState();
}
}class _HomePageState extends State<HomePage>{ @override
Widget build(BuildContext context) { return MaterialApp(
home: Scaffold(
body: Center(
child: Text('這是首頁'),
),
),
);
}
}
這個三個頁面的代碼都一樣就沒有都貼出來
三.現(xiàn)在我們就需要去創(chuàng)建我們的主頁了,”MainPage.dart”文件
第一步,我們先去實現(xiàn)一個最簡單的底部導(dǎo)航欄
import 'package:flutter/material.dart';import 'HomePage.dart';import 'AssistantPage.dart';import 'MinePage.dart';class MainPage extends StatefulWidget { @override
State<StatefulWidget> createState() { return _MainPage();
}
}class _MainPage extends State<MainPage> with SingleTickerProviderStateMixin {
PageController pageController; int page = 0; @override
Widget build(BuildContext context) { return MaterialApp(
home: Scaffold(
body: new PageView(
children: <Widget>[HomePage(), AssistantPage(), MinePage()],
controller: pageController,
onPageChanged: onPageChanged,
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('首頁')),
BottomNavigationBarItem(icon: Icon(Icons.assessment), title: Text('助手')),
BottomNavigationBarItem(icon: Icon(Icons.person), title: Text('我的')),
],
onTap: onTap,
currentIndex: page,
),
));
} @override
void initState() { super.initState();
pageController = PageController(initialPage: this.page);
} @override
void dispose() { super.dispose();
pageController.dispose();
} void onTap(int index) {
pageController.animateToPage(index,
duration: const Duration(milliseconds: 300), curve: Curves.ease);
} void onPageChanged(int page) {
setState(() { this.page = page;
});
}
}
在MainPage.dart中我們用到了幾個控件:
1. PageView : 此控件類似Android的ViewPager,把之前創(chuàng)建的3個頁面一次添加進去,之后需要給PageView設(shè)置一個控制器-PageController,給PageView設(shè)置一個onPageChanged頁面切換監(jiān)聽方法,此方法的功能類似與Android中ViewPager中的OnPageChangeListener里的監(jiān)聽方法
2. BottomNavigationBar :此控件主要用于配置底部導(dǎo)航欄,詳細用法請參見官方文檔,在此控件的使用中,我們需要設(shè)置三個屬性,
items: 添加底部導(dǎo)航欄的每個Item
onTap: 為底部導(dǎo)航欄設(shè)置點擊事件
currentIndex: 為底部導(dǎo)航設(shè)置當前選中項
四.我們要實現(xiàn)仿閑魚的底部導(dǎo)航欄,需要重構(gòu)一下底部導(dǎo)航欄,
重構(gòu)方案:
1.把中間的文字去掉
2.在BottomNavigationBar控件的中上的位置放入一個圖片
3.重構(gòu)底部導(dǎo)航的事件方法
4.禁止PageView的滑動事件
現(xiàn)在開始重構(gòu):
1.要在BottomNavigationBar上面覆蓋一個圖片,我們需要用到一個布局Widget—-Stack,類似于Framelayout
class _MainPage extends State<MainPage> with SingleTickerProviderStateMixin {
PageController pageController; int page = 0; //添加圖片地址,需要動態(tài)更換圖片
String bigImg = 'images/home_green.png'; @override
Widget build(BuildContext context) { return MaterialApp(
home: Scaffold(
body: new PageView(
children: <Widget>[HomePage(), AssistantPage(), MinePage()],
controller: pageController,
onPageChanged: onPageChanged,
), //重構(gòu)bottomNavigationBar
bottomNavigationBar: Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('首頁')),
BottomNavigationBarItem(icon: Icon(Icons.assessment), title: Text('')),
BottomNavigationBarItem(icon: Icon(Icons.person), title: Text('我的')),
],
onTap: onTap,
currentIndex: page,
),
),
Align(
alignment: Alignment.bottomCenter,
child: InkWell(
child: new Image.asset(bigImg,width: 80.0,height: 80.0,),
onTap:onBigImgTap,
),
)
],
)
));
} @override
void initState() { super.initState();
pageController = PageController(initialPage: this.page);
} @override
void dispose() { super.dispose();
pageController.dispose();
} //修改bottomNavigationBar的點擊事件
void onTap(int index) { if (index != 1) {
setState(() { this.bigImg = 'images/home_green.png';
});
}
pageController.animateToPage(index,
duration: const Duration(milliseconds: 300), curve: Curves.ease);
} //添加圖片的點擊事件
void onBigImgTap() {
setState(() { this.page = 1; this.bigImg = 'images/icon_home.png';
onTap(1);
});
} void onPageChanged(int page) {
setState(() { this.page = page;
});
}
}
重構(gòu)完成之后,效果圖如下,我們發(fā)現(xiàn)這并不是我們想要的,底部導(dǎo)航欄我們是實現(xiàn)了,但是PageView被遮蓋了
PageView被遮蓋的解決辦法,我們給Stack添加一個可以指定高度的父級—Container,修改的代碼如下:
bottomNavigationBar: Container(
height: 100.0,
child: Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home), title: Text('首頁')),
BottomNavigationBarItem(
icon: Icon(Icons.accessibility_new), title: Text('')),
BottomNavigationBarItem(
icon: Icon(Icons.person), title: Text('我的')),
],
onTap: onTap,
currentIndex: page,
),
),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: InkWell(
child: new Image.asset(
bigImg,
width: 80.0,
height: 80.0,
),
onTap: onBigImgTap,
),
)),
],
),
)
然后我們需要禁止PageView的滑動,我們只需要在給PageView設(shè)置一個屬性就好了
physics: NeverScrollableScrollPhysics(),
在運行Flutter項目的時候出現(xiàn)了一個問題,運行時會出現(xiàn)一段時間的白屏,解決辦法:
解決方案很簡單,Android原生的白屏問題可以通過為 Launcher Activity 設(shè)置 windowBackground 解決,而 Flutter 也是基于此辦法,同時優(yōu)化了 Flutter 初始化階段的白屏問題(覆蓋一個launchView)坞靶,只用兩步設(shè)置便能解決 Flutter 中白屏問題。
在項目的 android/app/src/main/res/mipmap-xhdpi/ 目錄下添加閃屏圖片直晨;
打開 android/app/src/main/res/drawable/launch_background.xml 文件汗销,這個文件就是閃屏的背景文件衙傀,具體如何設(shè)置可以查閱 Android Drawable跟束,我在 demo 中的設(shè)置如下:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/background_dark" />
<!-- You can insert your own image assets here -->
<item
android:bottom="84dp">
<bitmap
android:src="@mipmap/launch_image" />
</item>
</layer-list>
如此一來,我們就完成了,文章開始提出的需求了.
Demo地址 : https://github.com/hanlin19900610/flutter_bottom_navigation_bar
剛開始接觸Flutter,代碼寫的有些混亂,可能有些問題考慮不是很深入,有不足之處,還請各位大佬指出