仿寫新聞客戶端
攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第17天,點選檢視活動詳情
新建專案,加入圖片字型,編寫歡迎介面
新建專案
flutter create jimmy_flutter_demo
加入圖片字型
在根目錄上新建一個 assets
資料夾
bash
assets
fonts // 存放字型
images // 存放圖片
在 pubspec.yaml
檔案設定 images
的路徑內容:
bash
assets:
- assets/images/
在 pubspec.yaml
檔案設定 fonts
的路徑內容:
bash
fonts:
- family: Avenir
fonts:
- asset: assets/fonts/Avenir-Book.ttf
weight: 400
- family: Montserrat
fonts:
- asset: assets/fonts/Montserrat-SemiBold.ttf
weight: 600
編寫歡迎頁面
新增螢幕適配的包。
bash
# 螢幕適配
flutter_screenutil: ^1.0.2
拉取新包:flutter pub get
獲取直接安裝 flutter pub add flutter_screenutil
。
設定螢幕見 lib/common/utils/screen.dart
。
設定這個 app
的一些色調,見 lib/common/values/colors.dart
新增歡迎頁面 lib/pages/welcome/welcomePage.dart
更改入口檔案 lib/main.dart
```bash import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:jimmy_flutter_demo/pages/welcome/welcomePage.dart';
void main() => runApp(MyApp());
// 檢視 http://github.com/OpenFlutter/flutter_screenutil/blob/master/README_CN.md
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { //填入設計稿中裝置的螢幕尺寸,單位dp return ScreenUtilInit( designSize: const Size(360, 690), minTextAdapt: true, splitScreenMode: true, builder: (context, child) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'First Method', theme: ThemeData( primarySwatch: Colors.blue, textTheme: Typography.englishLike2018.apply(fontSizeFactor: 1.sp), ), home: child, ); }, child: const WelcomePage(), ); } } ```
這裡需要對
flutter_screenutil
做全域性的引入。
然後對歡迎頁面進行新增,內容如下:
```bash import 'package:flutter/material.dart'; import 'package:jimmy_flutter_demo/common/utils/utils.dart'; import 'package:jimmy_flutter_demo/common/values/values.dart';
class WelcomePage extends StatelessWidget { const WelcomePage({Key? key}) : super(key: key);
// 頁頭標題 Widget _buildPageHeaderTitle() { return Container( margin: EdgeInsets.only(top: duSetHeight(65)), child: Text( "Features", textAlign: TextAlign.center, style: TextStyle( color: AppColors.primaryText, fontFamily: "Montserrat", fontWeight: FontWeight.w600, fontSize: duSetFontSize(24), ), ), ); }
// 頁頭說明 Widget _buildPageHeaderDetail() { return Container( width: duSetWidth(242), height: duSetHeight(70), margin: EdgeInsets.only(top: duSetHeight(14)), child: Text( "The best of news channels all in one place. Trusted sources and personalized news for you.", textAlign: TextAlign.center, style: TextStyle( color: AppColors.primaryText, fontFamily: "Avenir", fontWeight: FontWeight.normal, fontSize: duSetFontSize(16), height: 1.3, ), ), ); }
// 特性說明 // 寬度 80 + 20 + 195 = 295 Widget _buildFeatureItem(String imageName, String intro, double marginTop) { return Container( width: duSetWidth(295), height: duSetHeight(80), margin: EdgeInsets.only(top: duSetHeight(marginTop)), child: Row( children: [ Container( width: duSetWidth(80), height: duSetHeight(80), child: Image.asset( "assets/images/$imageName.png", fit: BoxFit.none, ), ), const Spacer(), Container( width: duSetWidth(195), child: Text( intro, textAlign: TextAlign.center, style: TextStyle( color: AppColors.primaryText, fontFamily: "Avenge", fontWeight: FontWeight.normal, fontSize: duSetFontSize(16), ), ), ), ], ), ); }
// 開始按鈕 Widget _buildStartButton() { return Container( width: duSetWidth(295), height: duSetHeight(44), margin: EdgeInsets.only(bottom: duSetHeight(20)), child: TextButton( onPressed: () => {}, style: ButtonStyle( backgroundColor: MaterialStateProperty.all(AppColors.primaryElement), textStyle: MaterialStateProperty.all(const TextStyle( color: AppColors.primaryElementText, )), ), child: const Text("Get started"), ), ); }
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children:
上面的 TextButton 本來使用的是 FlatButton, 但是它已經被棄用了。
相關的效果圖:
靜態路由,元件抽取,登陸註冊頁面
為了實現靜態路由,我們來定義下登陸和註冊的頁面:
- 登入頁 lib/pages/sign_in/sign_in.dart
- 註冊頁 lib/pages/sign_up/sign_up.dart
- 靜態路由 lib/routes.dart
```bash // 登陸頁面初始化 import 'package:flutter/material.dart';
class SignInPage extends StatelessWidget { SignInPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children:
```
```bash // 註冊頁面初始化 import 'package:flutter/material.dart';
class SignUpPage extends StatelessWidget { SignUpPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children:
```bash // 路由資訊 import 'package:jimmy_flutter_demo/pages/sign_in/sign_in.dart'; import 'package:jimmy_flutter_demo/pages/sign_up/sign_up.dart';
// 靜態路由 var staticRoutes = { "/sign-in": (context) => SignInPage(), // 登入 "/sign-up": (context) => SignUpPage(), // 註冊 };
```
安裝使用 fluttertoast
報錯的解決:
bash
[Parse Issue (Xcode): Module 'fluttertoast' not found
解決方案:
bash
1. 進入專案 ios 資料夾,刪除檔案 **"Podfile"** 和 **"Podfile. Lock"**
2. ios 目錄下,在終端執行 `flutter clean` 命令列
3. 回到專案根目錄,在終端執行 `flutter pub get`
4. ios 目錄下,在終端執行 `pod install`
元件 appBar 拆分過程的報錯:The argument type 'Widget' can't be assigned to the parameter type 'PreferredSizeWidget?'
解決方案:
``bash
因為我們定義了 appBar 元件是
Widget,我們應該定義其為
PreferredSizeWidget`。
Widget transparentAppBar({
required BuildContext context,
required List
// 改為
PreferredSizeWidget transparentAppBar({
required BuildContext context,
required List
元件抽取
比如: toast
```bash import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:jimmy_flutter_demo/common/utils/utils.dart'; import 'package:fluttertoast/fluttertoast.dart';
Future toastInfo({ required String msg, Color backgroundColor = Colors.black, Color textColor = Colors.white, }) async { return await Fluttertoast.showToast( msg: msg, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.TOP, timeInSecForIosWeb: 1, backgroundColor: backgroundColor, textColor: textColor, fontSize: duSetFontSize(16), ); } ```
又比如:appBar
```bash import 'package:flutter/material.dart'; import 'package:jimmy_flutter_demo/common/values/values.dart';
// 透明背景的 AppBar
PreferredSizeWidget transparentAppBar({
// 使用 PreferredSizeWidget 定義,而不是 Widget
required BuildContext context,
required List
```
Dio 的封裝使用
- 處理報錯:
Non-nullable instance field '_storage' must be initialized.\ Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
解決方案,在變數 _storage
新增 late
修飾符。
- 處理報錯
The argument type 'void Function(RequestOptions)' can't be assigned to the parameter type 'void Function(RequestOptions, RequestInterceptorHandler)?'
封裝dio
的時候出現。
解決方案,可以嘗試方法如下:
bash
initializeInterceptor(){
_dio.interceptors.add(InterceptorsWrapper(
onError: (error, errorInterceptorHandler ){
print(error.message);
},
onRequest: (request, requestInterceptorHandler){
print("${request.method} | ${request.path}");
},
onResponse: (response, responseInterceptorHandler) {
print('${response.statusCode} ${response.statusCode} ${response.data}');
}
));
}
後續更新...
往期精彩推薦
如果讀者覺得文章還可以,不防一鍵三連:關注➕點贊➕收藏
- 前端開發中 5 個很讚的資源
- 懂點心理學 - 馬太效應
- Flutter 構建一個 todo list 應用
- Dart 知識點 - 資料型別
- Dart 知識點 - 混入 Mixin
- Dart 知識點 - 集合 List, Set, Map
- Flutter - 使用 push(), pop() 和路由進行導航
- Dart 知識點 - 面向物件基礎
- Flutter: Stateful 掛件 vs Stateless 掛件
- Flutter 實現登入 UI
- Dart 知識點 - 抽象類和介面
- 自 2020 年以來全球的開源商業化軟體融資情況
- IstioCon 2022 回顧及錄影、PPT 分享
- 網頁實現 1CM 物理長度
- Flutter 開發出現的那些 Bugs 和解決方案「持續更新... 」
- 仿寫新聞客戶端
- Beyond Istio OSS —— Istio 服務網格的現狀及未來
- 在外企的工作生活「年中總結」
- 如何在 Istio 中整合 SPRIRE?
- Javascript尾遞迴程式設計