歡迎、引導 | 登入、註冊 | 主頁 |
---|---|---|
環境搭建
可以參考 flutter.cn/docs/get-st… 搭建
Flutter 使用到的語言為 Dart
Dart 語言學習可以看 gitee.com/shizidada/d…
建立專案
// --org com.moose.plus 建立包名
// moose_app 應用名稱
flutter create --org com.moose.plus moose_app
複製程式碼
moose_app
目錄介紹
├── android // android 平臺執行程式碼
│ ├── ...
├── ios // ios 平臺執行程式碼
│ ├── ...
├── lib // flutter 平臺執行程式碼
│ ├── main.dart // 主入口檔案
├── test // 測試
│ ├── ...
├── web // web 平臺
│ ├── ...
└── pubspec.yaml // flutter 執行依賴
└── ...
複製程式碼
開始搭建 Flutter 專案執行腳手架
程式碼目錄
- 在 lib 目錄下建立 core 目錄,與 UI 無關到邏輯程式碼
- 在 lib 目錄下建立 ui 目錄,UI 展示檢視程式碼 ├── lib │ ├── core │ ├── ui
修改 main.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'app.dart';
void main() {
// 主入口執行 --> 主要程式碼 --> app.dart
runApp(ATHApp());
// android 平臺 statusBar 沉浸式
if (Platform.isAndroid) {
SystemUiOverlayStyle systemUiOverlayStyle =
SystemUiOverlayStyle(statusBarColor: Colors.transparent);
SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
}
}
複製程式碼
新增專案所需依賴
- 國內映象,訪問速度快 pub.flutter-io.cn/
dependencies:
flutter:
sdk: flutter
# 構建路由模組
fluro: ^2.0.3
# svg 圖片顯示, flutter_svg 新版本存在問題,使用臨時修復版本,取從 github 上分支,後面換 release 版本
flutter_svg:
git:
url: git://github.com/gskinnerTeam/flutter_svg.git
ref: 12b55b464d2e253f411a17798527a7daa2c00ceb
# 螢幕適配 新版本使用和其他版本有區別
flutter_screenutil: ^4.0.3+3
# 輪播圖
flutter_swiper: ^1.1.6
shared_preferences: ^2.0.4
複製程式碼
建立 app.dart,主要執行介面
import 'package:flutter/material.dart';
class ATHApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return buildApp(context);
}
Widget buildApp(BuildContext context) {
return MaterialApp(
// 應用在後臺掛起時顯示標題
title: 'Moose Flutter Learn',
// 修改全域性 app 樣式
theme: Theme.of(context).copyWith(
appBarTheme: Theme.of(context).appBarTheme.copyWith(
color: kPrimaryColor,
elevation: 0,
brightness: Brightness.light,
)),
// 不現實 debug 標籤
debugShowCheckedModeBanner: false,
// 主頁
home: ATHSplashScreen());
}
}
複製程式碼
應用歡迎介面
...
class ATHSplashScreen extends StatelessWidget {
static final String routeName = "app://splash";
@override
Widget build(BuildContext context) {
return Scaffold(
body: ATHSplashBody(),
);
}
}
....
複製程式碼
ATHSplashBody
- 顯示一張圖片 --> 可能廣告
- 倒數計時結束或者點選進入 app
class ATHSplashBody extends StatefulWidget {
@override
_ATHSplashBodyState createState() => _ATHSplashBodyState();
}
class _ATHSplashBodyState extends State<ATHSplashBody> {
Timer _timer;
int _count = 5;
@override
void initState() {
super.initState();
_startTime();
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints.expand(),
child: Image.asset("assets/images/welcome.png", fit: BoxFit.fill),
),
Positioned(
top: 60,
right: 40,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(8.w)),
child: GestureDetector(
onTap: () {
_navigationPage();
},
child: Container(
color: Colors.black12.withAlpha(200),
width: 180.w,
height: 50.h,
alignment: Alignment.center,
child: Text(
"跳過廣告 $_count",
style: TextStyle(color: Colors.white),
),
),
),
),
),
],
);
}
_startTime() async {
var _duration = Duration(seconds: 1);
Timer(_duration, () {
// 空等1秒之後再計時
_timer = Timer.periodic(const Duration(milliseconds: 1000), (v) {
_count--;
if (_count <= 0) {
if (_timer != null) _timer.cancel();
_navigationPage();
} else {
setState(() {});
}
});
return _timer;
});
}
void _navigationPage() async {
_timer.cancel();
// 需要判斷是否為第一次進入 app
ATHNavigator.pushFromRight(context, ATHGuideScreen.routeName);
}
}
複製程式碼
構建fluro
路由架子
Flutter 可以使用自帶的 router‘s,使用 fluro 方便維護管理路由
├── lib │ ├── core │ ├── ui │ ├──├── routers │ ├──├──├── application.dart │ ├──├──├── route_handlers.dart │ ├──├──├── routers.dart
application.dart 定義
- 維護 FluroRouter(其他版本 Router),用於頁面跳轉
import 'package:fluro/fluro.dart';
class ATHApplication {
static FluroRouter router;
}
複製程式碼
route_handlers.dart 定義
- 栗子見程式碼
- 定義每一個顯示的頁面
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
Handler splashHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return ATHSplashScreen();
});
Handler guideHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return ATHGuideScreen();
});
複製程式碼
routers.dart 定義具體路由跳轉規則
import 'package:fluro/fluro.dart';
import 'route_handlers.dart';
class ATHRoutes {
static void configureRoutes(FluroRouter router) {
router.define(ATHSplashScreen.routeName, handler: splashHandler);
router.define(ATHGuideScreen.routeName, handler: guideHandler);
}
}
複製程式碼
使用定義的路由
- 修改 app.dart
- 初始化 FluroRouter
....
ATHApp({Key key}) : super(key: key) {
final router = FluroRouter();
ATHRoutes.configureRoutes(router);
ATHApplication.router = router;
}
....
Widget buildApp() {
home: ATHSplashScreen(),
// 新增掛在到 app 上
onGenerateRoute: ATHApplication.router.generator
}
....
複製程式碼
螢幕適配
- 可以獲取螢幕畫素轉換為設計稿對應的尺寸
- 使用
flutter_screenutil: ^4.0.3+3
模組簡化操作
使用 flutter_screenutil
- pubspec.yaml 新增 flutter_screenutil 依賴
- 修改 app.dart
@override
Widget build(BuildContext context) {
// ScreenUtilInit 為 flutter_screenutil 提供 API
return ScreenUtilInit(
// 預設設計稿尺寸
designSize: Size(750, 1334),
// 設定是否根據系統字型大小
allowFontScaling: false,
builder: () => buildApp(context));
}
複製程式碼
- 在後面使用直接可以使用
栗子 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 參考 github.com/OpenFlutter…
應用引導介面
使用 flutter_swiper
- 最後一張引導圖顯示跳轉按鈕
class ATHGuideScreen extends StatefulWidget {
static final String routeName = "app://guide";
@override
_ATHGuideScreenState createState() => _ATHGuideScreenState();
}
class _ATHGuideScreenState extends State<ATHGuideScreen> {
List<String> guideImages = [
'assets/images/guide-1.jpeg',
'assets/images/guide-2.jpeg',
];
void _handleCheck() async {
ATHNavigator.pushReplace(context, ATHWelcomeScreen.routeName,
clearStack: true);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Swiper(
itemCount: guideImages.length,
itemBuilder: (BuildContext context, int position) {
String imagePath = guideImages[position];
return Stack(
fit: StackFit.passthrough,
alignment: Alignment.center,
children: [
Image.asset(imagePath, fit: BoxFit.cover),
position == guideImages.length - 1
? Positioned(
bottom: 100.h,
child: TextButton(
onPressed: () {
_handleCheck();
},
style: ButtonStyle(
padding: MaterialStateProperty.all(
EdgeInsets.symmetric(
vertical: 16.h, horizontal: 32.w)),
backgroundColor:
MaterialStateProperty.all(Colors.white)),
child: Text(
"立即體驗",
style: TextStyle(color: Colors.black),
),
),
)
: SizedBox()
],
);
},
// 設定頁碼
pagination: SwiperPagination(
alignment: Alignment.bottomCenter,
builder: DotSwiperPaginationBuilder(
color: Colors.black54, activeColor: Colors.white)),
loop: false,
scrollDirection: Axis.horizontal,
),
);
}
}
複製程式碼