仿写新闻客户端
携手创作,共同成长!这是我参与「掘金日新计划 · 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尾递归编程