欢迎、引导 登录、注册 主页
从 Flutter 2.0 开始学 - 项目搭建 - 图1 从 Flutter 2.0 开始学 - 项目搭建 - 图2 从 Flutter 2.0 开始学 - 项目搭建 - 图3

环境搭建

可以参考 https://flutter.cn/docs/get-started/install/macos 搭建

Flutter 使用到的语言为 Dart

Dart 语言学习可以看 https://gitee.com/shizidada/dart-learn

创建项目

  1. // --org com.moose.plus 创建包名
  2. // moose_app 应用名称
  3. flutter create --org com.moose.plus moose_app

moose_app

目录介绍

  1. ├── android // android 平台运行代码
  2. ├── ...
  3. ├── ios // ios 平台运行代码
  4. ├── ...
  5. ├── lib // flutter 平台运行代码
  6. ├── main.dart // 主入口文件
  7. ├── test // 测试
  8. ├── ...
  9. ├── web // web 平台
  10. ├── ...
  11. └── pubspec.yaml // flutter 运行依赖
  12. └── ...

开始搭建 Flutter 项目运行脚手架

代码目录

  • 在 lib 目录下创建 core 目录,与 UI 无关到逻辑代码
  • 在 lib 目录下创建 ui 目录,UI 展示视图代码
  1. ├── lib
  2. ├── core
  3. ├── ui

修改 main.dart

  1. import 'dart:io';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter/services.dart';
  4. import 'app.dart';
  5. void main() {
  6. // 主入口运行 --> 主要代码 --> app.dart
  7. runApp(ATHApp());
  8. // android 平台 statusBar 沉浸式
  9. if (Platform.isAndroid) {
  10. SystemUiOverlayStyle systemUiOverlayStyle =
  11. SystemUiOverlayStyle(statusBarColor: Colors.transparent);
  12. SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
  13. }
  14. }

添加项目所需依赖

  1. dependencies:
  2. flutter:
  3. sdk: flutter
  4. # 构建路由模块
  5. fluro: ^2.0.3
  6. # svg 图片显示, flutter_svg 新版本存在问题,使用临时修复版本,取从 github 上分支,后面换 release 版本
  7. flutter_svg:
  8. git:
  9. url: git://github.com/gskinnerTeam/flutter_svg.git
  10. ref: 12b55b464d2e253f411a17798527a7daa2c00ceb
  11. # 屏幕适配 新版本使用和其他版本有区别
  12. flutter_screenutil: ^4.0.3+3
  13. # 轮播图
  14. flutter_swiper: ^1.1.6
  15. shared_preferences: ^2.0.4

创建 app.dart,主要运行界面

  1. import 'package:flutter/material.dart';
  2. class ATHApp extends StatelessWidget {
  3. @override
  4. Widget build(BuildContext context) {
  5. return buildApp(context);
  6. }
  7. Widget buildApp(BuildContext context) {
  8. return MaterialApp(
  9. // 应用在后台挂起时显示标题
  10. title: 'Moose Flutter Learn',
  11. // 修改全局 app 样式
  12. theme: Theme.of(context).copyWith(
  13. appBarTheme: Theme.of(context).appBarTheme.copyWith(
  14. color: kPrimaryColor,
  15. elevation: 0,
  16. brightness: Brightness.light,
  17. )),
  18. // 不现实 debug 标签
  19. debugShowCheckedModeBanner: false,
  20. // 主页
  21. home: ATHSplashScreen());
  22. }
  23. }

应用欢迎界面

  1. ...
  2. class ATHSplashScreen extends StatelessWidget {
  3. static final String routeName = "app://splash";
  4. @override
  5. Widget build(BuildContext context) {
  6. return Scaffold(
  7. body: ATHSplashBody(),
  8. );
  9. }
  10. }
  11. ....

ATHSplashBody

  • 显示一张图片 —> 可能广告
  • 倒计时结束或者点击进入 app
  1. class ATHSplashBody extends StatefulWidget {
  2. @override
  3. _ATHSplashBodyState createState() => _ATHSplashBodyState();
  4. }
  5. class _ATHSplashBodyState extends State<ATHSplashBody> {
  6. Timer _timer;
  7. int _count = 5;
  8. @override
  9. void initState() {
  10. super.initState();
  11. _startTime();
  12. }
  13. @override
  14. Widget build(BuildContext context) {
  15. return Stack(
  16. children: <Widget>[
  17. ConstrainedBox(
  18. constraints: BoxConstraints.expand(),
  19. child: Image.asset("assets/images/welcome.png", fit: BoxFit.fill),
  20. ),
  21. Positioned(
  22. top: 60,
  23. right: 40,
  24. child: ClipRRect(
  25. borderRadius: BorderRadius.all(Radius.circular(8.w)),
  26. child: GestureDetector(
  27. onTap: () {
  28. _navigationPage();
  29. },
  30. child: Container(
  31. color: Colors.black12.withAlpha(200),
  32. width: 180.w,
  33. height: 50.h,
  34. alignment: Alignment.center,
  35. child: Text(
  36. "跳过广告 $_count",
  37. style: TextStyle(color: Colors.white),
  38. ),
  39. ),
  40. ),
  41. ),
  42. ),
  43. ],
  44. );
  45. }
  46. _startTime() async {
  47. var _duration = Duration(seconds: 1);
  48. Timer(_duration, () {
  49. // 空等1秒之后再计时
  50. _timer = Timer.periodic(const Duration(milliseconds: 1000), (v) {
  51. _count--;
  52. if (_count <= 0) {
  53. if (_timer != null) _timer.cancel();
  54. _navigationPage();
  55. } else {
  56. setState(() {});
  57. }
  58. });
  59. return _timer;
  60. });
  61. }
  62. void _navigationPage() async {
  63. _timer.cancel();
  64. // 需要判断是否为第一次进入 app
  65. ATHNavigator.pushFromRight(context, ATHGuideScreen.routeName);
  66. }
  67. }

构建fluro 路由架子

Flutter 可以使用自带的 router‘s,使用 fluro 方便维护管理路由

  1. ├── lib
  2. ├── core
  3. ├── ui
  4. ├──├── routers
  5. ├──├──├── application.dart
  6. ├──├──├── route_handlers.dart
  7. ├──├──├── routers.dart

application.dart 定义

  • 维护 FluroRouter(其他版本 Router),用于页面跳转
  1. import 'package:fluro/fluro.dart';
  2. class ATHApplication {
  3. static FluroRouter router;
  4. }

route_handlers.dart 定义

  • 栗子见代码
  • 定义每一个显示的页面
  1. import 'package:fluro/fluro.dart';
  2. import 'package:flutter/material.dart';
  3. Handler splashHandler = Handler(
  4. handlerFunc: (BuildContext context, Map<String, List<String>> params) {
  5. return ATHSplashScreen();
  6. });
  7. Handler guideHandler = Handler(
  8. handlerFunc: (BuildContext context, Map<String, List<String>> params) {
  9. return ATHGuideScreen();
  10. });

routers.dart 定义具体路由跳转规则

  1. import 'package:fluro/fluro.dart';
  2. import 'route_handlers.dart';
  3. class ATHRoutes {
  4. static void configureRoutes(FluroRouter router) {
  5. router.define(ATHSplashScreen.routeName, handler: splashHandler);
  6. router.define(ATHGuideScreen.routeName, handler: guideHandler);
  7. }
  8. }

使用定义的路由

  • 修改 app.dart
  • 初始化 FluroRouter
  1. ....
  2. ATHApp({Key key}) : super(key: key) {
  3. final router = FluroRouter();
  4. ATHRoutes.configureRoutes(router);
  5. ATHApplication.router = router;
  6. }
  7. ....
  8. Widget buildApp() {
  9. home: ATHSplashScreen(),
  10. // 添加挂在到 app 上
  11. onGenerateRoute: ATHApplication.router.generator
  12. }
  13. ....

屏幕适配

  • 可以获取屏幕像素转换为设计稿对应的尺寸
  • 使用 flutter_screenutil: ^4.0.3+3 模块简化操作

使用 flutter_screenutil

  • pubspec.yaml 添加 flutter_screenutil 依赖
  • 修改 app.dart
  1. @override
  2. Widget build(BuildContext context) {
  3. // ScreenUtilInit 为 flutter_screenutil 提供 API
  4. return ScreenUtilInit(
  5. // 默认设计稿尺寸
  6. designSize: Size(750, 1334),
  7. // 设置是否根据系统字体大小
  8. allowFontScaling: false,
  9. builder: () => buildApp(context));
  10. }
  • 在后面使用直接可以使用

    栗子
    ScreenUtil().setWidth(540) (sdk>=2.6 : 540.w) //根据屏幕宽度适配尺寸
    ScreenUtil().setHeight(200) (sdk>=2.6 : 200.h) //根据屏幕高度适配尺寸(一般根据宽度适配即可)
    ScreenUtil().radius(200) (sdk>=2.6 : 200.r) //根据宽度或高度中的较小者进行调整
    ScreenUtil().setSp(24) (sdk>=2.6 : 24.sp) //适配字体

根据 API 参考 https://github.com/OpenFlutter/flutter_screenutil/blob/master/README_CN.md

应用引导界面

使用 flutter_swiper

  • 最后一张引导图显示跳转按钮
  1. class ATHGuideScreen extends StatefulWidget {
  2. static final String routeName = "app://guide";
  3. @override
  4. _ATHGuideScreenState createState() => _ATHGuideScreenState();
  5. }
  6. class _ATHGuideScreenState extends State<ATHGuideScreen> {
  7. List<String> guideImages = [
  8. 'assets/images/guide-1.jpeg',
  9. 'assets/images/guide-2.jpeg',
  10. ];
  11. void _handleCheck() async {
  12. ATHNavigator.pushReplace(context, ATHWelcomeScreen.routeName,
  13. clearStack: true);
  14. }
  15. @override
  16. Widget build(BuildContext context) {
  17. return Scaffold(
  18. body: Swiper(
  19. itemCount: guideImages.length,
  20. itemBuilder: (BuildContext context, int position) {
  21. String imagePath = guideImages[position];
  22. return Stack(
  23. fit: StackFit.passthrough,
  24. alignment: Alignment.center,
  25. children: [
  26. Image.asset(imagePath, fit: BoxFit.cover),
  27. position == guideImages.length - 1
  28. ? Positioned(
  29. bottom: 100.h,
  30. child: TextButton(
  31. onPressed: () {
  32. _handleCheck();
  33. },
  34. style: ButtonStyle(
  35. padding: MaterialStateProperty.all(
  36. EdgeInsets.symmetric(
  37. vertical: 16.h, horizontal: 32.w)),
  38. backgroundColor:
  39. MaterialStateProperty.all(Colors.white)),
  40. child: Text(
  41. "立即体验",
  42. style: TextStyle(color: Colors.black),
  43. ),
  44. ),
  45. )
  46. : SizedBox()
  47. ],
  48. );
  49. },
  50. // 设置页码
  51. pagination: SwiperPagination(
  52. alignment: Alignment.bottomCenter,
  53. builder: DotSwiperPaginationBuilder(
  54. color: Colors.black54, activeColor: Colors.white)),
  55. loop: false,
  56. scrollDirection: Axis.horizontal,
  57. ),
  58. );
  59. }
  60. }

从 Flutter 2.0 开始学 - Widget 组件化

从 Flutter 2.0 开始学 - 路由封装、界面跳转、登录注册 UI