IOS端
1. ios模拟器不弹键盘通过快捷键:command + shift + k。
Android端
其他
1. 自定义屏幕适配类HYSizeFit()时,使用之前需使用对应类初始化即HYSizeFit.init(),才可使用内部方法和属性如HYSizeFit.setPx()。(在这里可使用Dart2.6以后提供的extension方法)。
2. 通过api接收的json要转换成Flutter可以使用的model数据;
或者也可以不用转换,直接 ["属性名"] 获取值即可。
3. 使用GestureDetector()组件解决要使空白区域产生点击效应,添加: behavior:HitTestBehavior.opaque。
4. initState()里面不可以有async方法,可以通过新建另外的异步方法,将此方法添加到initState()里面。
5. 四舍五入取2位小数:toStringAsFixed(2)---String类型
转为double:double.parse()
四舍五入取整数:toStringAsFixed(0)---String类型
转为double:int.parse()
其他类似;
6. 求时间间隔:
time = DateTime.parse("2020-12-14 08:38:42").difference("2020-12-12 04:36:23")
time.inDays: 按天数表示
time.inhours: 按小时数表示
time.inMinutes: 按分钟数表示
time.inSeconds: 按秒数表示
7. 跳转页面传参数(一般参数是个map对象,比如某条数据详情)
单个参数:
传参:onTap: () {Navigator.of(context).pushNamed("/productionDetails", arguments: _productionData);},
获参:final Map data = ModalRoute.of(context).settings.arguments;
多个参数:
传参:arguments传入的是一个Object,传多个参数,可以使用{}或者[]包裹;
获参:final Map data = ModalRoute.of(context).settings.arguments;
(用 final List data([]包裹即为数组) 或者 final Map data({}包裹即为map) 获取)。
8. 父子组件传值
1) 父组件给子组件传值:
父组件:class HYFather{
@override
Widget build(BuildContext context) {
return Container(
child: HYChild(data);
child: HYChild(data1,data2);
);
}
}
子组件:class HYChild{
final Map data;
HYChild(this.data);
}
2) 子组件通过回调通知给父组件:
9. ListView组件取消上下滑动: 添加属性:physics: NeverScrollableScrollPhysics()。
10. 关于ListView组件上拉加载、下拉刷新和api分页请求的代码安排:
1) 上拉加载:
-----stata里面定义监听器:ScrollController _controller;
-----在ListView.builder里面添加 controller: _controller;
-----在initState方法里面初始化监听器并且监听滚动的距离,如果大于api分页请求的数量,则请求下一页数据:
_controller = ScrollController();
_controller.addListener((){
if(_controller.position.pixels >= _controller.position.maxScrollExtent){
_offset += 7;
_getProductionData();
}
})
2) 下拉刷新:
-----在ListVie.builder外面包裹RefreshIndicator();
-----给其属性onRefresh添加实现方法 onRefresh: _onRefresh;
-----实现_onRefresh方法:先把列表数据清空,然后插入最新请求的前10条,然后展示完毕之后继续上拉加载的逻辑。
3) api分页请求:
var data = await Http.request("production/list","GET",params: {"offset": _offset, "limit": _limit});
11. 基线对齐的属性:crossAxisAlignment: CrossAxisAlignment.baseline,textBaseline: TextBaseline.ideographic。
12. 属性和变量的区别?
本质上一样,属性用于描述对象,变量更多用于逻辑运算。(属性也是变量,只不过属于对象)
13. 关于导航栏:
使用IndexedStack来保持页面状态的优点就是配置简单,但是它也有很大的缺点:IndexedStack中管理的子页面在一开始就全部一次性加载出来了,不管有没有显示出来,然后通过index属性来确定到底显示哪一个页面。
14. 关于切换页面保持页面状态的解决方法:
1) 使用IndexedStack()组件实现,它的作用是显示第index个child,其它child在页面上是不可见的,但所有child的状态都被保持,只需要将现在的body用IndexedStack包裹一层即可。
15. setState()方法只存在于StatefulWidget中。
16. Container()组件宽度:
如果不给Container组件设置宽度,那么其宽度为取决于子组件的宽度;
设置其宽度为满屏宽度:width: MediaQuery.of(context).size.width(或者 double.infinity)
17.
--使用shared_preferences用来本地存储的使用步骤:
1) 安装依赖:shared_preferences: ^0.5.12
2) 引入插件并且封装本地信息存储的公共类(以存token为例)
import 'package:shared_preferences/shared_preferences.dart';
class Local {
static String _token;
static setToken(token) async{
final p1 = await SharedPreferences.getInstance();
await p1.setString(_token, token);
}
static getToken() async{
final p1 = await SharedPreferences.getInstance();
return p1.getString(_token);
}
static delToken() async{
final p1 = await SharedPreferences.getInstance();
p1.remove(_token);
}
}
3) 使用:
引入公共类;
设置:Local.setToken(data["content"]["auth_token"]);
获取:Local.getToken().then((res){
if(res != null){
setState(() {
_token = res;
});
}
});
删除:Local.delToken()
--关于添加多个属性:
如果在该公共类中添加多个属性,现在的使用情况会导致只能设置一个属性,设置多个会出现覆盖则会变成最后一个属性的值的情况;现在的解决办法是shared_preferences设置一个,其他需要设置存储的变量在使用位置用shared_preferences原生实现。
18. 使用TextFormField()组件作为输入框时,app会自动获取鼠标焦点并且弹出键盘,设置点击空白处收起键盘:
用GestureDetector()组件包裹当前最外层组件,然后添加
behavior: HitTestBehavior.translucent,
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
}
19. 去除手机模拟器右上角的Debug标签,在materialApp里面添加属性:debugShowCheckedModeBanner: false。
20. 关于页面初始化:
1) 首页home.dart中,Scaffold()里面的bottomNavigationBar()组件的IndexedStack()的pages属性对应有哪些组件,那么app启动之后就会初始化这些页面,也会执行initState方法中的异步请求。
2) 如果上面的某些异步请求带token,那么不能把异步请求放在initState方法中,可以放在点击登陆并且成功的按钮事件中,然后再传给home页面。
21. 关于抽象类和抽象方法的应用场景:(以下特点在 C++ 语言中可能有所区别)
1) 抽象方法必须定义在抽象类中,即用关键字abstract修饰的方法;
2) 继承抽象类之后,必须实现抽象类中的抽象方法;其他方法可以不实现;
3) 抽象类一般适用在大型的api库或者工具库中。
22. 为什么Flutter设计的时候stateFulWidget的build方法放在state中?
1) build出来的的widget是需要依赖State中的变量(状态/数据);
2) 在Flutter运行过程中,widget是不断销毁和创建的,当自己的状态发生改变时,并不希望重新建一个新的State。
23. 关于widget的生命周期:(主要针对于statefulwidget)
1) 生命周期的作用:
初始化一些数据、变量、状态;发送网络请求;一些事件的监听比如controller添加添加监听事件;管理内存比如一些定时器、controller手动销毁。
2) statefulwidget生命周期的执行顺序:(举例类名为HYHomeContent)
第一是执行HYHomeContent的构造方法;
第二是执行HYHomeContent的createState方法;
第三是执行_HYHomeContentState的构造方法;
第四是执行_HYHomeContentState的initState方法;
第五是执行_HYHomeContentState的build方法;
第六是执行_HYHomeContentState的dispose方法(页面销毁时调用);
List属性和方法
- 属性
lenght:数组长度
first:数组第一个元素
last:数组最后一个元素
reversed:数组元素顺序相反
isEmpty:是否为空
isNotEmpty:是否为非空
- 方法
add():像数组添加元素
addAll(list):给一个数组添加另一个新的数组
insert(索引,值):给数组某指定位置添加某元素,其之后元素依次顺延
insertAll(索引,数组):给数组某指定位置添加某数组,其之后元素依次顺延
remove():删除指定值
removeAt(索引):删除指定索引对应的值
removeRange(索引,索引):删除指定索引范围的值
removeLast():删除数组最后一个元素
removeWhere((){}):删除满足某条件的元素,没有返回值,直接改变原数组
clear():删除所有元素
setRang(索引,索引,数组值):修改数组中某区间元素为指定值,其后元素依次顺延
setAll(索引,数组值):修改指定索引后的数组值
replaceRange(索引,索引,值):替换数组中某区间范围的值为某一个值
fillRange(索引,索引,值):将数组中某区间范围的值每个都换成替换的值
getRange(索引,索引):获取数组某区间范围的值
sublist(索引,索引):获取指定区间的值(如果只有一个索引,则获取的是该索引到最后的值)
any((){}):判断数组内是否有满足条件的元素
every((){}):判断数组所有元素都满足某条件
contains():判断数组是否包含某元素
firstWhere((){},orElse:(){}):获取满足条件的第一个元素,如果未找到符合条件的元素,则进入orElse
lastWhere((){},orElse:(){}):获取满足条件的最后一个元素,如果未找到符合条件的元素,则进入orElse
indexWhere((){}):获取满足条件的第一个元素的索引,若不存在返回-1
indexWhere((){},索引):从索引值开始获取满足条件的第一个元素的索引,若不存在返回-1
lastIndexWhere((){}):获取满足条件的最后一个元素的索引,若不存在返回-1
lastIndexWhere((){},索引):从索引值开始获取满足条件的最后一个元素的索引,若不存在返回-1
indexOf():获取某值第一次出现的索引,若不存在返回-1
indexOf(值,索引):从索引值开始获取某值第一次出现的索引,若不存在返回-1
lastIndexOf():获取某值第一次出现的索引,若不存在返回-1
lastIndexOf(值,索引):从索引值开始,获取某值第一次出现的索引,若不存在返回-1
singleWhere((){},orElse:(){}):获取唯一元素,如果不存在,执行orElse;如果存在该元素但是出现次数不唯一,直接抛出错误进入catch
join():把数组中的元素用指定字符拼接成字符串
toSet():数组去重
forEach():遍历数组
map((e){return }):按指定条件返回一个新数组
reduce((val,element){return }):返回数组元素总和(累加器)
sort((a,b){return a-b;}):排序,按回调中return结果的正负数来排序
报错
1. Unhandled Exception: setState() or markNeedsBuild() called during build
报错原因:父组件没初始化完,子组件就去操作initstate里面setState了。
解决办法:在子组件的initState()方法中添加WidgetsBinding.instance.addPostFrameCallback((_){}),该函数体内放置setState的操作。
2. 在home页面的IndexedStack的children属性中写入的页面都会在进入home页面初始化,如果有涉及到需要从前一个页面点击跳转且传值过来获取值的情况,要判断初始化时值为null的情况。