Flutter好客租房项目
https://www.bilibili.com/video/BV18Q4y1o7nP
4 8
P1 1.1 为什么学习 flutter 项目.
1.1 为什么学习 flutter 项目
1.市场需要 flutter--android 和 ios 使用一套设计图,却需要两批人来开发。目前flutter 开始支持 web 和桌面开发。
2.Flutter 使用更好的语言——Dart语言。Javascript 方便调试,有时性能不能满足需求,语言特性更新依赖浏览器厂商的支持;java和oc性能好,但是调试不如Javascript方便.Dart语言同时支持JiT(just in time)
和AOT(ahead of time)两种模式。开发时使用Dart的JIT运行模式,可以做到,修改的效果及时展现到页面上;产品发布后,使用Dart的AOT运行模式,保证APP的性能最优.从而极大的提高APP的开发效率.
3.Flutter 开箱即用——flutter 提供丰富的组件,能够快速的开发出 原生 app.
4.以项目的方式学习——学到更实用的知识。
P2 1.2 课程内容.
1.2 课程内容
项目知识点:使用第三方组件
通用組件封装使用静态资源
I本地图片网络图片
使用自带 icon使用字体 icon网络图片缓存超时处理
本地存储及 store 封装
数据管理 scoped_model网络请求 及 dio_http 封装
序列号及反序列化半自动生成实体类
图片上传
app icon 及启动页
面向群体:
有一定编程基础——会一门其他编程语言
有一定 flutter 基础——学完 Flutter 框架入门,或者通过官网可以安装 flutter 并运行demo。
希望通过项目来强化 flutter 相关技术
P3 1.3 项目简介.
1.3 项目简介
项目路径
基础回顾
项目框架
静态页面
前后端联调
I
构建打包
包含的页面
登陆页
注册页
首页
首页tab
搜索tab
咨询tab
我的tab
搜索页
房屋管理
添加房屋
房屋详情
设置
P4 2 基础回顾.
2.Material组件和Cupertino组件
flutter 是开箱即用的
Material 组件 就是 android 风格的组件
Cupertino 组件 就是 ios 风格的组件
3.常用组件
Text-用于显示文字的组件
Image-用于显示图片的組件
Icon-用于显示图标,有内置的 Material 和 Cupertino 风格的图标Container·类似 html 中的 div。可以很方便的添加 内外边距,对齐,背景,边角的特性。
Row,Column-用于水平和垂直方向的多组件展示。使用 flex 布局。
Stack-用于z轴方向的多组件展示。可以把一个组件堆叠到另外一个组件上面,类似 css 中的 PositionScaffold-页面的基本组件,提供了基本的页面结构。包括顶部title及功能按钮,顶部tab,底部tab,导航按钮等。
P5 3.1 初始化项目.
P6 3.2 编写一个简单页面-准备.
MaterialApp:封装了应用程序实现Material Design 所需要的一些 widget.
Scaffold:Material Design 布局结构的基本实现。
Appbar:一个Material Design应用程序栏,由工具栏和其他可能的widget组成。
P7 3.3 编写一个简单页面-实现.
P8 3.4安装fluro并添加登陆页面.
3.4 安装 fluro 并添加登陆页面
封装route 动态传值
1.了解 fluro
1.简单
2.支持参数通配符/room/:id
3.简化自定义动画
2 添加依赖
vs /page/home/index.dart 文件 自动创建文件夹
P9 3.5如何配置fluro.
3.5 如何配置fluro问题:
如何配置fluro?
分析:
看官方文档声明 路由配置 路由
关联 路由 和 materialApp使用 路由
分析示例代码
编写路由配置文件
在 Application 中配置路由一声明/配置/关联 路由测试路由
结论:
结论:
1.编写路由配置文件
1.创建 routes.dart 文件 并编写Routes类的基本结构
2.定义路由名称
3.定义路由处理函数
4.编写函数 configureRoutes 关联路由名称和处理函数
2.在 Application 中配置路由
1.定义 router
2.通过调用configureRoutes 配置 router
3.在MaterialApp 中使用 router
3.测试路由
1.在 PageContent 中添加跳转按钮
github.com/theyakka/fluro
P10 3.6配置fluro.
P11 3.7 优化路由配置.
问题:
错误页面如何处理?带参数的页面如何处理?
步骤:
1.错误页面处理
1,在/pages目录添加not-found.dart文件
2.实现 NotFoundPage
3,在/routes.dart添加-notFoundHandler
4,在/routes.dart的configureRoutes中添加router.notFoundHandler=_notFoundHandler;
5.修改 PageContent 测试
2,带参数页面处理
1,在/pages 目录添加 room_detail/index.dart 文件
2.实现 RoomDetailPage
3.在/routes.dart 添加_notFoundHandler
4,在/routes.dart的configureRoutes中添加router.notFoundHandler=_notFoundHandler
5.修改 PageContent 测试
补充:
实现页面步骤
1.添加依赖
2,编写组件模板有状态组件/无状态组件
3.如果有参数添加组件参数4.完善 build 方法
P12 4.1 登陆页-页面分析.
P13 4.2 登陆页-主体结构.
P14 4.3 登陆页-密码显示隐藏.
步骤:
1.将无状态組件改成有状态組件—右键 重构
2.添加可点击的图标—IconButton
3.添加状态-showPassword
4.根据状态展示不同内容
5.给图标添加点击事件
6.测试
P15 4.4 登陆页-细节优化.
问题及解决方案:
1.【去注册】颜色问题添加style
2.上下间距问题?添加 Padding
3.边距/异形屏幕问题?
使用 SafeArea
4.垂直高度不足问题?
使用ListView 替代Column
5.登陆按钮宽度和颜色问题?
宽度:SizedBox或者父级固定宽度颜色:手动设置
P16 4.5 注册页-添加.
P17 4.6 注册页-完善.
P18 4.7 首页-tab-分析.
结论:
1.首页共用 tab 按钮区域
2.tab 内容区的 appBar 不一样
3.4 个 tab 内容区不一样
4.可以使用 flutter 自带组件 BottomNavigationBar 实现
1.需要准备4个tab 内容区(tabView)
2.需要准备4个 BottomNavigationBarltem
api.flutter.dev/flutter/material/BottomNavigationBar-class.html
P19 4.8 首页-tab-编码.
P20 4.9 首页-tablndex-分析.
4.10 首页-tablndex-页面结构.
4.11 首页-tablndex-轮播图-准备.
分析:
有 flutter swiper!
田注:
github.com/best-flutter/flutter_swiper/blob/master/README-ZH.md
4.12 首页-tablndex-轮播图-实现.
4.13 首页-tablndex-导航-准备.
4.14 首页-tablndex-导航-实现.
InkWell) 可以点击组件
4.15组件Commonlmage封装-分析.
4.15组件Commonlmage封装-分析
问题:
轮播图的网络图片偶尔出现超时,怎么解决?
如果涉及图片方面的优化,我们是不是需要修改很多处?
结论:
自己封装一个图片组件!
细化方案:
1.根据资源地址是可以区分本地资源和网络的资源的(网络图片地址以 http 开头,本地图片地址以static 开头),所以可以共用一个图片组件
2.网络图片添加本地缓存,延长网络请求超时时间!可以使用第三方组件AdvancedNetworkimage
github.com/mchome/flutter_advanced_networkimage
4.16 组件 Commonlmage 封装-实现.
RegExp 正则
4.17 首页-tablndex-推荐-准备.
4.18 首页-tablndex-推荐-编码-主体….
4.19 首页-tablndex-推荐-编码-item部分.
4.20 首页-tablndex-资讯-准备.
4.21 首页-tablndex-资讯-编码-主体结构.
4.22 首页-tablndex-资讯-编码-item部分.
4.23首页-tablnfo.
4.24 首页-tabSearch-分析.
if()weight; ?:
4.25 首页-tabSearch-主体结构.
top+Expanded+Listview 组合 top类似stick粘贴效果
vs 断点 左右 加weight 所在位置右击重构加weight
4.26 首页-tabSearch-item 部分.
4.27 首页-tabSearch-tag 部分.
4.28 组件 SearchBar 封装-分析.
4.29 组件 SearchBar 封装-主体结构开...
4.30 组件 SearchBar 封装-完善搜索框.
步骤:
1.解决背景色,圆角-Container,TextField.InputDecoration.border=InputBorder.none
2.前置图标 InputDecoration.prefixicon
3,后置图标InputDecoration.suffixicon
4.搜索提示样式 InputDecoration.hintStyle
5,剧中InputDecoration.contentPadding
6,间距问题 使用 InputDecoration.icon 替代InputDecoration.prefixicon
431组件SearchRar封装细节完盖
4.31 组件 SearchBar 封装-细节完善.
4.32组件 SearchBar 封装-使用及优化.
4.33 首页-tabProfile-分析.
4.34 首页-tabProfile-主体结构.
4.35首页-tabProfile-登陆注册-未登陆..
4.36首页-tabProfile-登陆注册-已登陆...
4.37首页-tabProfile-功能按钮-主体结构
4.38首页-tabProfile-功能按钮-item.
warp 可以设置space
4.39 首页-tabProfile-广告及资讯
4.40 设置页.
分析:
需要 toast 弹窗,使用 fluttertoast田注
DefaultTabController
4.41 房屋管理页-主体结构.
4.42 房屋管理页-发布按钮
因为【房源发布】页面也有同样的样式,所以需要封装成组件。组件参数包含 title 和 onTap.
步骤:
1.添加 floatingActionButton 熟悉2,完善发布按钮主体结构GestureDetector>Container>Center>Text
3.修改 floatingActionButtonLocation
4.完善细节5.封装组件
4.43 发布房源页-分析.
结论:
1.CommonTitle
2.CommonFormitem
3.CommonRadioFormltem
4.CommonSelectFormitem
5.CommonPicker
6.CommonlmagePicker
7.CommonCheckButton
8.RoomAppliance
4.44 发布房源页-主体结构.
4.45 发布房源页-CommonTitle.
4.46发布房源页-CommonFormltem-.
4.47发布房源页-CommonFormltem-...
Container.decoration.BoxDecoration.border
child: GestureDetector(
behavior: HitTestBehavior. translucent, 点击空白区生效
Radio Widget
List.generate 有长度 代替map
4.48发布房源页-CommonFormltem-...
4.49发布房源页-CommonRadioForml..
4.50发布房源页-CommonSelectForm..
4.51 发布房源页-CommonPicker-分析.
结论:
CommonPicker.showPicker 是一个 class 的静态方法
半屏弹窗—showCupertinoModalPopup
选择区域—CupertinoPicker
使用:
CupertinoPicker Widget
4.52 发布房源页-CommonPicker-主体..
4.53 发布房源页-CommonPicker-细节..
4.54 发布房源页-房屋图像-主体结构.
4.55 发布房源页-房屋图像-添加删除.
1.添加一 使用第三方组件 image picker 读取本地图片
https://www.cnblogs.com/ilgnefz/p/15954507.html
4.56 发布房源页-房屋标题描述.
4.57 发布房源页-房屋配置-分析.
4.58 发布房源页-房屋配置-实现.
4.59 房屋详情页-分析.
Share.share('https://itcast.cn');
4.60 房屋详情页面-主体结构.
4.61房屋详情页面-底部按钮.
4.62 房屋详情页面-房屋图片&房屋基...
4.63房屋详情页面-房屋详细信息
4.64 房屋详情页面-房屋配置.
4.65 房屋详情页面-房屋概况&猜你喜欢.
maxLines Text Widget 属性
4.66 filterBar-分析.
4.67 filterBar-展示区域.
4.68 filterBar-picker 部分.
4.69 filterBar-drawer部分-展示部分.
4.70 filterBar-drawer部分-数据分析.
4.71 filterBar-drawer 部分-ScopedMo...
4.72 filterBar-drawer 部分-ScopedMo...
4.73 filterBar-drawer 部分-ScopedMo...
1.有状态组件生命周期 initState—只执行一次,没有context,或者 context 不完整2.有状态组件生命周期 didChangeDependencies 依赖变更后就会执行,有context,会执行多次
3.一次执行,并且需要 context
5.1介绍Dio.
结论:
使用 dio 作为 app 的网络请求工具。
Dio 对 HttpClient 的封装,增加了一些功能如 拦截器,全局配置,请求取消等。
5.2 封装DioHttp.
https://www.fastmock.site/mock/432a14676095fee4c04836707d74972f/api
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:goodhouse/config.dart';
class DioHttp {
late Dio _client;
late BuildContext context;
static DioHttp of(BuildContext context) {
return DioHttp._internal(context);
}
DioHttp._internal(BuildContext context) {
if (_client == null || context != this.context) {
this.context = context;
var options = BaseOptions(
baseUrl: Config.BaseUrl,
connectTimeout: Duration(seconds: 10), //1000*10
receiveTimeout: Duration(seconds: 10, microseconds: 3), //1000*3
extra: {'context': context});
var client = Dio(options);
this._client = client;
}
}
Future<Response<Map<String, dynamic>>> get(String path,
[Map<String, dynamic>? params, String? token]) async {
var options = Options(headers: {'Authorization': token});
return await _client.get(path, queryParameters: params, options: options);
}
Future<Response<Map<String, dynamic>>> post(String path,
[Map<String, dynamic>? params, String? token]) async {
var options = Options(headers: {'Authorization': token});
return await _client.post(path, data: params, options: options);
}
Future<Response<Map<String, dynamic>>> postFormData(String path,
[Map<String, dynamic>? params, String? token]) async {
var options = Options(
contentType: ContentType.parse('multipart/form-data').toString(),
headers: {'Authorization': token});
return await _client.post(path, data: params, options: options);
}
}
5.3注册页联调.
dev.itcastor.com:3333/#/user/addPet
dart/covert json.decode
5.4 登陆页联调--分析.
5.4 登陆页联调--分析
问题:
1.登陆状态怎么和其他页面同步?
2.再次打开 app,是否需要二次登陆?
3.登陆过期如何处理?
分析:
1,使用ScopedModel同步登陆信息(token).
2.登陆成功后,将 token 写入本地存储;添加一个app 启动页,app启动的时候,加载token!
3.在 DioHttp 中添加 Dio 拦截器,当登陆过期是,打开登陆页。
shared_preferences文档 添加和使用本地缓存:
5.5 封装Store.
5.5 封装 Store问题:
本地缓存 shared_preferences 的api可能会变?
结论:
将 shared_preferences 封装成 store详细分析:
1.内部数据 final SharedPreferences storage;
2.方法
1.getString(StoreKeys key)async)
2.setString(StoreKeys key,String value)async()
3.getStringList(StoreKeys key)async04.setStringList(StoreKeys key,List
实现步骤:
1.新建文件/utils/store.dart
2.添加 shared_preferences 依赖
3.编写类的基本结构
4.实现初始化方法
5.实现 getString setString getStringList setStringList
6.添加 storeKeys
import 'dart:ui_web';
import 'package:shared_preferences/shared_preferences.dart';
enum StoreKeys {
token,
}
class Store {
static late StoreKeys storeKeys;
final SharedPreferences _store;
static Future<Store> getInstance() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return Store._internal(prefs);
}
Store._internal(this._store);
getString(StoreKeys key) async {
return _store.get(key.toString());
}
setString(StoreKeys key, String value) async {
return _store.setString(key.toString(), value);
}
getStringList(StoreKeys key) async {
return _store.getStringList(key.toString());
}
setStringList(StoreKeys key, List<String> value) async {
return _store.setStringList(key.toString(), value);
}
}
5.6实现AuthModel.
5.6 实现 AuthModel分析:
1.内部数据 token
2.方法
1.String get token2.bool get isLogin
3.void initApp(BuildContext context)async 04.void login(String token,BuildContext context)O
5.void logout()
步骤:
I
5.7 登陆页联调.
5.8使用AuthModel及退出登陆
5.9 完善个人信息.
5.10 model 生成半自动化.
5.10 model 生成半自动化问题:
工厂构造函数代码能否自动生成?
方案:
使用 json serializable
5.11优化model.
5.12 城市选择器-分析.
分析:
1.城市选择使用 sity pickers
2.需要在本地缓存中 存储 city,需要使用 Store
3.目前仅部分城市可用,在config 中添加可用城市列表4.多个页面共享当前 city 状态,需要使用 ScopedModel
5.13 城市选择器-实现.
model+cache
vuex+storage
5.14联调FilterBar.
5.15 联调找房页.
5.16房屋详情页.
5.17 房屋管理页.
5.18 房源发布-分析.
5.19 房源发布-条件数据.
5.20 房源发布-小区选择-主流程.
5.21房源发布-小区选择-细节完善及联...
106
I 5.22 房源发布-图片上传.
5.23 房源发布-数据校验及提交.
5.24 房源发布-优化.
5.25 登陆过期处理.
请求拦截
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:goodhouse/config.dart';
import 'package:goodhouse/utils/common_toast.dart';
class DioHttp {
late Dio _client;
late BuildContext context;
static DioHttp of(BuildContext context) {
return DioHttp._internal(context);
}
DioHttp._internal(BuildContext context) {
if (_client == null || context != this.context) {
this.context = context;
var options = BaseOptions(
baseUrl: Config.BaseUrl,
connectTimeout: Duration(seconds: 10), //1000*10
receiveTimeout: Duration(seconds: 10, microseconds: 3), //1000*3
extra: {'context': context});
Interceptor interceptor = InterceptorsWrapper(
onResponse: (response, handler) {
// if (null == response) return response;
// var status = json.decode(res.toString())['status'];
// if (404 == status) {
// CommonToast.showToast('api error');
// return response;
// }
// //...其他status
// return response;
},
);
var client = Dio(options);
client.interceptors.add(interceptor);
this._client = client;
}
}
Future<Response<Map<String, dynamic>>> get(String path,
[Map<String, dynamic>? params, String? token]) async {
var options = Options(headers: {'Authorization': token});
return await _client.get(path, queryParameters: params, options: options);
}
Future<Response<Map<String, dynamic>>> post(String path,
[Map<String, dynamic>? params, String? token]) async {
var options = Options(headers: {'Authorization': token});
return await _client.post(path, data: params, options: options);
}
Future<Response<Map<String, dynamic>>> postFormData(String path,
[Map<String, dynamic>? params, String? token]) async {
var options = Options(
contentType: ContentType.parse('multipart/form-data').toString(),
headers: {'Authorization': token});
return await _client.post(path, data: params, options: options);
}
}
5.26 添加 flutter 启动页.
5.26 添加 flutter 启动页问题:
重启 app 之后,需要重新登陆方案:
I在启动页处理
启动页就是一个普通的页面,延迟 3秒跳转到首页效果:
6.1 构建打包分析.
6 构建打包
6.1 构建打包分析
主要包含几部分
准备
桌面图标修改应用名称修改启动图片修改
构建
资源地址:/resource/chapter6/01静态资源/package添加启动页后仍然有明显的白屏!
6.2 构建 Android 包.
步骤:
1.修改应用名称
/项目目录/android/app/src/main/AndroidManifest.xml 文件 application 标签 android:label 属性
2.修改图标及背景图
文件地址:/resource/chapter6/01静态资源/package/android/res
目标地址:/项目目录/android/app/src/main/res
3.修改构建配置
在 android/app/build.gradle 文件中 android.lintoption 添加属性 checkReleaseBuilds false
4.构建
fiptter build apk
5.查看文件
6.3 构建 ios 包.
6.3 构建 ios 包
效果:
生成打包文件,能在开启开发模式的手机上运行(需要 苹果开发者账号)。
步骤:
1.修改应用名称
/项目目录/ios/Runner/info.plist 文件修改key 为 CFBundleName 的值。
2.修改图标及背景图
文件地址:/resource/chapter6/01静态资源/package/ios/Assets.xcassets目标地址:/项目目录/Runner/Assets.xcassets
3.构建
flutter build ios查看文件
H
7 Flutter 总结.
7总结
1.回顾实现的功能/页面
实现了完整的登陆注册,添加房源,查找房源,查看房源的功能。
登陆页注册页
I首页
首页tab搜索tab咨询tab我的tab搜索页
房屋管理添加房屋房厘详情
设置
2.回顾项目知识点
项目知识点:使用第三方组件
I通用组件封装使用静态资源
本地图片网络图片
使用自带 icon使用字体 icon网络图片缓存超时处理
本地存储及 store 封装数据管理 scoped_model网络请求 及 dio_http 封装序列号及反序列化半自动生成实体类图片上传
app icon 及 启动页
3.个人感悟
技术一直在更新;唯有终身学习,才能让自己保持竞争力!
rrx rwx 777
bug dsx otherHuix
https://www.cnblogs.com/lxlx1798/articles/11371301.html 屏幕适配 flex 100% Media expand
flutter的大小单位默认为dp。
GestureDetector
项目github
https://github.com/Danonlylane/goodhouse
封装 dio
https://blog.csdn.net/Eqiqi/article/details/138152643
https://www.jianshu.com/p/75f0988f0bac
标签:租房,options,添加,首页,context,好客,组件,Flutter,页面 From: https://www.cnblogs.com/KooTeam/p/18606828