代码详细代码参见Demo
Demo地址 -> wechat_demo
其他相关联文章
7、Flutter - 项目实战 - 仿微信(一)BottomNavigationBar 4个主页面显示
8、Flutter - 项目实战 - 仿微信(二)发现页面
9、Flutter - 项目实战 - 仿微信(三)我的页面
10、Flutter - 项目实战 - 仿微信(四)数据准备
11、Flutter - 项目实战 - 仿微信(五)通讯录
12、Flutter - 项目实战 - 仿微信(六)聊天页面
要实现的效果就是如下图的 BottomNavigationBar 能点击并切换页面
代码详细代码参见Demo(目前还有点小问题,不影响本片文章所诉内容的功能。后面写文章的时候会处理掉)
Demo地址 -> wachat_demo
创建工程和创建文件就不在说明,同时为了后面优化和修改将 BottomNavigationBar 功能抽取到一个类中实现,其他实现方式不再讲解
import 'package:flutter/material.dart';
import 'package:wechat/root_page.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(
//1, 0, 0, 0.0 设置为透明 0.0透明度 item长按
highlightColor: Color.fromRGBO(1, 0, 0, 0.0),
//tabbar item点击
splashColor: Color.fromRGBO(1, 0, 0, 0.0),
cardColor: Color.fromRGBO(1, 1, 1, 0.5),
primarySwatch: Colors.blue,
//点击的水波纹去掉。tabbar
//visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: RootPage(),
);
}
}
在Flutter中使用ThemeData来在应用中共享颜色和字体样式,Theme有两种:全局Theme和局部Theme。 全局Theme是由应用程序根MaterialApp创建的Theme 。
参考:https://www.jianshu.com/p/8d8ded72e673
- highlightColor: Color.fromRGBO(1, 0, 0, 0.0), //bar 的长按背景颜色设置为透明
- splashColor: Color.fromRGBO(1, 0, 0, 0.0), //bar的点击背景颜色设置为透明
- cardColor: Color.fromRGBO(1, 1, 1, 0.5), // 用在卡片(Card)上的Material的颜色。
- primarySwatch: Colors.blue, //主题颜色,除了tabbar、navigationBar之外,还有其他地方的主题颜色
MaterialApp 是符合MaterialApp Design设计理念的入口Widget,从源码可以看出该widget的构造方法中有多个参数,但是基本上大多数参数是可以省略的。
MaterialApp({
Key key,
this.title = '', // 设备用于为用户识别应用程序的单行描述
this.home, // 应用程序默认路由的小部件,用来定义当前应用打开的时候,所显示的界面
this.color, // 在操作系统界面中应用程序使用的主色。
this.theme, // 应用程序小部件使用的颜色。
this.routes = const {}, // 应用程序的顶级路由表
this.navigatorKey, // 在构建导航器时使用的键。
this.initialRoute, // 如果构建了导航器,则显示的第一个路由的名称
this.onGenerateRoute, // 应用程序导航到指定路由时使用的路由生成器回调
this.onUnknownRoute, // 当 onGenerateRoute 无法生成路由(initialRoute除外)时调用
this.navigatorObservers = const [], // 为该应用程序创建的导航器的观察者列表
this.builder, // 用于在导航器上面插入小部件,但在由WidgetsApp小部件创建的其他小部件下面插入小部件,或用于完全替换导航器
this.onGenerateTitle, // 如果非空,则调用此回调函数来生成应用程序的标题字符串,否则使用标题。
this.locale, // 此应用程序本地化小部件的初始区域设置基于此值。
this.localizationsDelegates, // 这个应用程序本地化小部件的委托。
this.localeListResolutionCallback, // 这个回调负责在应用程序启动时以及用户更改设备的区域设置时选择应用程序的区域设置。
this.localeResolutionCallback, //
this.supportedLocales = const [Locale('en', 'US')], // 此应用程序已本地化的地区列表
this.debugShowMaterialGrid = false, // 打开绘制基线网格材质应用程序的网格纸覆盖
this.showPerformanceOverlay = false, // 打开性能叠加
this.checkerboardRasterCacheImages = false, // 打开栅格缓存图像的棋盘格
this.checkerboardOffscreenLayers = false, // 打开渲染到屏幕外位图的图层的棋盘格
this.showSemanticsDebugger = false, // 打开显示框架报告的可访问性信息的覆盖
this.debugShowCheckedModeBanner = true, // 在选中模式下打开一个小的“DEBUG”横幅,表示应用程序处于选中模式
})
参考 :https://www.jianshu.com/p/20ce0fe051a1
这里用到的几个主页面引用,这几个页面后面再做介绍。这里不做详细说明,只要先创建这几个页面能显示出来即可
import 'package:flutter/material.dart';
import 'package:wechat/pages/chat/chat_page.dart';
import 'package:wechat/pages/discover/discover_page.dart';
import 'package:wechat/pages/friends.dart';
import 'package:wechat/pages/mine.dart';
class RootPage extends StatefulWidget {
@override
_RootPageState createState() => _RootPageState();
}
List _pages = [
ChatPage(),
FriendsPage(),
DiscoverPage(),
MinePage(),
];
class _RootPageState extends State {
int _currentIndex = 0;
final PageController _controller = PageController(initialPage: 0);
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
//页面滚动变化时调用
// onPageChanged: (int index){
// _currentIndex = index;
// setState(() {});
// },
physics: NeverScrollableScrollPhysics(), //禁止页面滚动,tabbar页面
controller: _controller,
children: _pages,
),
bottomNavigationBar: BottomNavigationBar(
onTap: (index) {
setState(() {
_currentIndex = index;
});
_controller.jumpToPage(index);
},
//tabbar item字体大小
selectedFontSize: 12.0,
currentIndex: _currentIndex, //默认启动显示的item 从0开始
fixedColor: Colors.green, //选中的颜色
type: BottomNavigationBarType.fixed, //固定
items: [
BottomNavigationBarItem(
icon: Image.asset(
'images/tabbar_chat.png',
width: 20,
height: 20,
),
activeIcon: Image.asset(
'images/tabbar_chat_hl.png',
width: 20,
height: 20,
),
title: Text('微信')),
BottomNavigationBarItem(
icon: Image.asset(
'images/tabbar_friends.png',
width: 20,
height: 20,
),
activeIcon: Image.asset(
'images/tabbar_friends_hl.png',
width: 20,
height: 20,
),
title: Text('通讯录')),
BottomNavigationBarItem(
icon: Image.asset(
'images/tabbar_discover.png',
width: 20,
height: 20,
),
activeIcon: Image.asset(
'images/tabbar_discover_hl.png',
width: 20,
height: 20,
),
title: Text('发现')),
BottomNavigationBarItem(
icon: Image.asset(
'images/tabbar_mine.png',
width: 20,
height: 20,
),
activeIcon: Image.asset(
'images/tabbar_mine_hl.png',
width: 20,
height: 20,
),
title: Text('我')),
],
),
);
}
}
Stateful 里面 是树状结构,里面一旦build 是从头至尾全部重新渲染
尽可能的少用Stateful ,如果界面上只有少部分是需要变化的,就不需要全部都用stateful, 不需要变化的可以用 stateless
Scaffold 实现了基本的Material布局,只要是在 Material 中定义了的单个界面显示的布局控件元素,都可以使用Scaffold 来绘制。可以理解为布局的容器,用以绘制我们的界面
提供展示抽屉(drawers,比如:左边栏)、通知(snack bars) 以及底部按钮(bottom sheets)。
Scaffold 主要的属性说明
appBar:显示在界面顶部的一个 AppBar
相关连接:https://flutterchina.club/catalog/samples/
body:当前界面所显示的主要内容
floatingActionButton: 在 Material 中定义的一个功能按钮。
persistentFooterButtons:固定在下方显示的按钮。https://material.google.com/components/buttons.html#buttons-persistent-footer-buttons
drawer:侧边栏控件
bottomNavigationBar:显示在底部的导航栏按钮栏。可以查看文档:Flutter学习之制作底部菜单导航
backgroundColor:背景颜色
resizeToAvoidBottomPadding: 控制界面内容 body
是否重新布局来避免底部被覆盖了,比如当键盘显示的时候,重新布局避免被键盘盖住内容。默认值为 true。
Flutter中使用功能的图片,并不想xcode 中直接拖入用图片名那么简单,是需要配置并且使用图片路径的。
2.2.1、首先将images文件夹及其资源文件,copy到工程中
2.2.2、配置安卓项目使用图片 和 icon
2.2.3、配置安卓启动图
2.2.4、配置 iOS的启动图和icon
配置ios,不过多说明。用xcode配置就行了
目前先做了 BottomNavigationBar 的点击显示4个主要页面,后面会挨个实现这4个页面。主要是模仿微信的界面样式,熟悉Flutter的UI 及其布局。如文中有错误还望指正,共同进步。