1. 前情回顾
嗨,正在掉头发的你们好,我是洋小洋,本集咱们接着聊一下GooGle的“亲儿子”Flutter。那自从上篇文章分享之后,有一些掘友也发表了一些很有意思的评论。那咱们首先来回顾一下
1.1 读读评论
在这里挑选3位的评论,觉得挺有趣,毕竟咱也不是设计师,这也不得不证明了一个产品的UI是多么的重要,当然也是随机在评论区,贴上他们的链接,也可以看看对方会不会有什么技术上的专栏,大家互相学习。之后的每一段路,我也都对从评论区贴上你们的奇葩评论
1.2 上集成就
-
掘金社区Flutter模块7天内热榜第1
-
掘金社区Flutter模块热门第3
-
掘金社区Flutter模块最新第8
-
截止目前25赞10评论
虽然我也不太喜欢掘金的搜索算法,听说更新了,期待越来越好,大家能够分享自己对于技术的探索
2. 写在前面
不知不觉一周又过去了,实际开发的过程中还是会有很多坑的,这个循序渐进会和大家分享,包括像Provider和后台交互的流程等。Dio的企业化配置等。那在本集咱们还是画界面
- 上段旅程传送门 Flutter实战 从头撸一个「孤岛」APP(No.1、项目初始化、屏幕适配)
- 本文词数:2901
- 阅读时长:看你个人
- 阅读预警:多链接、多图
2.1 本章目标
如图所示,还是那么一个Low的界面,下面的内容可能会有点无聊,不过真的很肝,期待与你相遇
2.2 分享列表
- 一个很棒的Flutter学习资源列表 一个偏中文的资源分享,包括一些插件
- Take the Flutter Clock challenge 官方出的《时钟挑战》
2.3 Flutter数据
-
谷歌开发的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面 Flutter No.7
-
一些数据的指数
3. 着手开发
3.1 vscode 插件
- Flutter 语法检测、代码补全、代码重构、运行调试和热重载
- Dart
- Flutter Widget Snippets Widget 代码片段
- Awesome Flutter Snippets 提供常用函数的代码片段
那由于一个APP 一上来就直接登录页或者注册页。是有点生硬的,对用户来说是极为不友好的,凡事都要慢慢来,有个过程不是吗?其实在闪屏的过程中,是会做一些判断的,你如判断用户有没有登录等
3.2 拉取代码
发现我们并没有提交更新
- 新建开发分支
接着咱们新建一个开发分支,用来记录新的一个章节,这个章节咱们要做的是闪屏和引导页,如题
- DEBUG 调试
在上周的时候 我们是通过在项目的根目录下flutter run
运行项目,然后R
与r
进行切换
本周咱们借助Vscode
debug 调试模式
3.3 公共变量处理Global
在评论区,有掘友提到,底部的导航也太大,其实我们是已经适配过屏幕的不是吗?通过一个插件flutter_screenutil
,当然也可以采取其他的方式,比如MediaQuery
可以拿到widget
以及设备的的宽高
那么什么是全局变量呢, 全局变量就是单纯指会贯穿整个APP生命周期的变量,用于单纯的保存一些信息,或者封装一些全局工具和方法的对象。
我们先打算新建一个global.dart
用来存放比如说常用的宽度、高度、以及字体大小
cd utils
copy nul > global.dart // 新建一个global.dart(windows下)
复制代码
import 'package:flutter_screenutil/flutter_screenutil.dart';
/// 页面常见的宽度与高度
// 宽度
double width100 = ScreenUtil.getInstance().setWidth(100);
// 高度
double height100 = ScreenUtil.getInstance().setHeight(100);
复制代码
接着我们在底部的导航栏看下直接用我们的变量,当然第一步还是引入
import '../utils/global.dart';
复制代码
我们来进行测试下,把上一段结尾咱们引入的图片全部先删除,写上一段测试文字
当我们重启之后,显然是可以的
3.4 闪屏 splash screen
我们第一步还是新建一个page页面,并命名为splash_screen_page
/// 闪屏的页面
import 'package:flutter/material.dart';
class SplashScreenPage extends StatelessWidget {
const SplashScreenPage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Text('闪屏页面'),
),
);
}
}
复制代码
然后在main.dart
引用并使用,这时我们已经不再引入底部的导航界面了
return MaterialApp(
debugShowCheckedModeBanner: false, // 去除调试
title: '孤岛',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SplashScreenPage()); // 这里使用引导页,也就是说当用户一进来的时候,是一个闪屏
}
复制代码
接着咱们就写属于这个孤岛APP 闪屏页,首先了解下几个部件
- SingleChildScrollView 主要是控制里边的部件溢出,可以进行滚动
- BoxDecoration 主要是对容器进行修饰的,比如背景色,宽高等
这里我们使用一下渐变 gradient
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
// 线性渐变 有个渐变的过程
Color.fromRGBO(0, 0, 0, 0.2),
Color.fromRGBO(0, 0, 0, 0.4)
],
begin: FractionalOffset.topCenter, // 顶部居中
end: FractionalOffset.bottomCenter)), //
复制代码
效果是这个样子的
这个时候应用的第一个页面便是闪屏页面,然后我们写这个页面的主要内容
child: Container(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 30),
),
//
Text('孤岛',
style: TextStyle(
fontSize: fontSize200, fontWeight: FontWeight.w600))
],
),
),
复制代码
这里注意,fontSize: fontSize200
我们直接使用公共的global的声明定义好的大小就可
好了 跑一下
不尽如意的是,报了错误
The method '/' was called on null.
复制代码
这个问题很简单,其实是我们在使用屏幕适配的时候,并没有初始化
显然这样就可以了,我们接着插入一张图片,放在这儿就会好些了
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(assetName)
)
),
复制代码
放什么图片呢,就还是放一张保守点的吧,感觉她越来越不像《孤岛App》了
**图片资源来自B站UP主 **wlop- (如有侵权,请联系 Blog)
老规矩咱们还是需要在pubspec.yaml
中配置一下,闪屏静态时候的样子咱们暂且这个样子
还记得我们上一段旅程有一起看过MaterialApp
的源码
const MaterialApp({
Key key,
this.navigatorKey,
this.home,
this.routes = const <String, WidgetBuilder>{}, // 我们暂时会用到这个路由的配置
this.initialRoute,
this.onGenerateRoute,
this.onUnknownRoute,
this.navigatorObservers = const <NavigatorObserver>[],
this.builder,
this.title = '',
this.onGenerateTitle,
this.color,
this.theme,
this.darkTheme,
this.themeMode = ThemeMode.system,
this.locale,
this.localizationsDelegates,
this.localeListResolutionCallback,
this.localeResolutionCallback,
this.supportedLocales = const <Locale>[Locale('en', 'US')],
this.debugShowMaterialGrid = false,
this.showPerformanceOverlay = false,
this.checkerboardRasterCacheImages = false,
this.checkerboardOffscreenLayers = false,
this.showSemanticsDebugger = false,
this.debugShowCheckedModeBanner = true,
})
复制代码
主要目的便是当闪屏结束的时候,跳转到引导页面
return MaterialApp(
debugShowCheckedModeBanner: false, // 去除调试
title: '孤岛',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SplashScreenPage(),
routes: {
'guidePages': (context) {
return GuidePages(); // 跳转到引导页面
}
},
);
复制代码
设计一个计时器,用来等计时器结束的时候,跳转
/// 设计一个计时器,用来等计时器结束的时候,跳转
jumpPage(){
return Timer(duration, callback);
}
/// 源码其实是这样的
factory Timer(Duration duration, void callback()) {
if (Zone.current == Zone.root) {
// No need to bind the callback. We know that the root's timer will
// be invoked in the root zone.
return Zone.current.createTimer(duration, callback);
}
return Zone.current
.createTimer(duration, Zone.current.bindCallbackGuarded(callback));
}
复制代码
- duration 就是延迟
- callback 就是回调,在时间结束做什么事情
由于之前咱们是用的是StatelessWidget
也就是说我们需要在一个时间调用页面跳转的方法暂时我们改用有状态的部件StatefulWidget
,完整代码是这样
import 'dart:async';
/// 闪屏的页面
import 'package:flutter/material.dart';
import '../utils/global.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class SplashScreenPage extends StatefulWidget {
SplashScreenPage({Key key}) : super(key: key);
@override
_SplashScreenPageState createState() => _SplashScreenPageState();
}
class _SplashScreenPageState extends State<SplashScreenPage> {
/// 设计一个计时器,用来等计时器结束的时候,跳转
jumpPage() {
return Timer(Duration(milliseconds: 3000), () {
Navigator.pushReplacementNamed(context, 'guidePages');
});
}
@override
void initState() {
super.initState();
jumpPage();
}
@override
Widget build(BuildContext context) {
ScreenUtil.instance = ScreenUtil(width: 750, height: 1334)..init(context);
return Scaffold(
backgroundColor: Colors.white, // 背景色
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/splash_screen.jpg'),
fit: BoxFit.cover)), // 添加背景图片
child: Container(
child: Center(
child: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 30),
),
Text('欢迎来到孤岛',
style: TextStyle(
fontSize: fontSize40,
color: Colors.white10,
fontWeight: FontWeight.w600)),
SizedBox(
height: height100,
),
Text('By 洋小洋',
style: TextStyle(
fontSize: fontSize40,
color: Colors.white10,
fontWeight: FontWeight.w600))
],
),
),
),
),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
// 线性渐变 有个渐变的过程
Color.fromRGBO(0, 0, 0, 0.2),
Color.fromRGBO(0, 0, 0, 0.5)
],
begin: FractionalOffset.topCenter, // 顶部居中
end: FractionalOffset.bottomCenter)), // 底部居中
),
));
}
}
复制代码
好了,我们先阶段性的看下一起实现的效果
3.5 引导页
在走过了闪屏之后,我们期望能有个引导页,顾名思义就是引导用户下一步下一步,这里咱们采用第三方的包intro_views_flutter 2.8.0
截止目前包的版本是2.8.0
包名 | 传送 |
---|---|
intro_views_flutter | intro_views_flutter |
-
将此添加到包的pubspec.yaml文件中:
dependencies: intro_views_flutter: ^2.8.0 复制代码
-
您可以从命令行安装软件包:
$ flutter pub get 复制代码
-
现在,在Dart代码中,您可以使用:
import 'package:intro_views_flutter/intro_views_flutter.dart'; 复制代码
一波流操作后,就可以是使用了,具体使用的方法还是需要看一下API
属性 | 数据类型 | 描述 | 默认值 |
---|---|---|---|
pageColor | Color | 设置页面的颜色。 | Null |
mainImage | Image / Widget | 设置页面的主图像。 | Null |
title | Text / Widget | 设置页面的标题文本。 | Null |
body | Text / Widget | 设置页面的正文。 | Null |
iconImageAssetPath | String | 设置将在页面气泡中显示的图标图像路径。 | Null |
iconColor | Color | 设置页面气泡图标的颜色。 | Null |
bubbleBackgroundColor | Color | 设置页面气泡背景色。 | Colors.white / Color(0x88FFFFFF) |
textStyle | TextStyle | 为标题和正文设置TextStyle | title: color: Colors.white , fontSize: 50.0 body: color: Colors.white , fontSize: 24.0 |
titleTextStyle | TextStyle | 设置标题的TextStyle | color: Colors.white , fontSize: 50.0 |
bodyTextStyle | TextStyle | 为正文设置TextStyle | color: Colors.white , fontSize: 24.0 |
bubble | Widget | 为内部气泡设置自定义小部件 | null |
那咱们就根据使用的小细则定义一个PageViewModel
PageViewModel(
pageColor: const Color(0xFF03A9F4),
// iconImageAssetPath: 'assets/air-hostess.png',
iconColor: Colors.pink,
bubbleBackgroundColor: Colors.pink,
// bubble: Image.asset('images/jiche.jpg'),
body: Text(
'这是属于你我的孤岛',
),
title: Text(
'No.1',
),
// titleTextStyle: TextStyle(fontFamily: 'MyFont', color: Colors.white),
// bodyTextStyle: TextStyle(fontFamily: 'MyFont', color: Colors.white),
mainImage: Container(
decoration:
BoxDecoration(border: Border.all(width: 1, color: Colors.red)),
child: Image.asset(
// 图片
'images/jiche.jpg',
height: width750,
width: height1314,
fit: BoxFit.cover,
// alignment: Alignment.center, // 居中显示
),
)),
复制代码
在images
文件夹咱们又新增了几张图片,用于引导页的展示,图片素材有的是在这儿找的
那现在效果就差不多了,来一起看下
4. 写在最后
很高兴你能耐住性子看到这儿,尤其是在这个快节奏的生活和工作中,我们在今天的这段旅程已经完成了两部分
- 闪屏
- 引导页
写到现在已经是凌晨2:35分了
由于这周看了下这个
又出去浪荡了一圈,不过也还没有断更,也算对自己的一个激励吧,所以也请你给个鼓励,评论点赞,当然是感觉还行的话,说不定就出现在下一章节的[读读评论]
我是洋小洋,下回见,本节代码会同步更新仓库 github.com/yayxs/flutt…
--END