flutter-开发问题系列之七   2021-11-13


这是 todoline++ 项目开发过程中遇到的问题系列, 记录下来供大家参考。
本篇记录一些开发中遇到的疑问:

todoline++ 官网请看这里: https://todoline-plus-plus.github.io/

1 dart 如何使用绝对值?

1
2
3
4
void main() {  
var a = -12;
print(a.abs());
}

2 flutter Align 中的 widthFactor 做什么用?

book.flutterchina.club/chapter4/alignment.html

3 flutter 如何画圆形进度条?

1
2
3
4
5
6
7
8
9
SizedBox(
height: 200,
width: 200,
child: CircularProgressIndicator(
backgroundColor: Colors.grey[200],
valueColor: const AlwaysStoppedAnimation(Colors.blue),
value: 0.7,
),
)

CircularProgressIndicator 是画圆形进度条的组件
SizedBox 用于调整大小

存在的问题:

CircularProgressIndicator 无法屏幕居中, SizeBox 外面加一个 Container 也没有用
SizeBox 外面加一个 Container 并且设置 Container 的高度和宽度, 会更改 CircularProgressIndicator 的大小, 这时候 SizeBox 的高宽设置失效

解决办法:

我自己就是在 SizeBox 外面加一个 Row, 并设置 Row 的 mainAxisAlignment: MainAxisAlignment.center 实现居中

意外:

后来我发现, 网上有文章说可以使用 Container 让他居中
coder.work/article/7442938
我现在不知道我自己的情况为什么会这样

来源:

book.flutterchina.club/chapter3/progress.html

如果想看更多绘画圆形组件的请看这里:
zhuanlan.zhihu.com/p/145634328

4 IconButton 如何调整原来的 padding ?

1
2
3
4
5
6
7
8
9
10
11
 Container(
padding: const EdgeInsets.all(0),
width: 30,
height: 30,
child: IconButton(
icon: const Icon(Icons.keyboard_arrow_up),
onPressed: () {
Message.toast(context, "previous todo");
}
),
)

在外面套一个 Container, 设置 padding 为 0, 同时设置宽高就可以。

来源:
blog.csdn.net/weixin_43298955/article/details/115720294

5 fluter 如何让两个组件层叠起来?

请用 Stack 配合 Positioned 这两个组件来布局
来源: book.flutterchina.club/chapter4/stack.html

6 Flutter textField 的 onEditingComplete 事件为什么没有触发?

这个事件的错误需要在输入框中按回车键, 但是我同时发现, 如果是 maxline > 1, 按回车键就会失效。

7 dar 语言中, 对一组字符串? 如何去掉重复数据?

把这一组字符串放到 Set 类型的变量中, 他会自动去重。

8 dart 语言操作符 ??= 是什么意思?

1
b ??= val;

如果 b 为空, 将 val 的值赋值给 b, 否则保持 b 原来的值不变。

9 dart 语言如何设计单利模式?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class BeanFactory {
static final List<BeanFactory> _factoryList = [];
late final TodoService _todoService;

static _BeanFactory() {}

static BeanFactory init() {
if (_factoryList.isEmpty) {
DatabaseFactory.generateDatabase();
_factoryList.add(_BeanFactory());
}
return _factoryList[0];
}

getTodoService() {
_todoService ??= TodoServiceImpl();
return _todoService;
}
}

上面的设计似乎没有问题, 但是 flutter run 了以后, 报错如下:
Operand of null-aware operation ‘??=’ has type ‘TodoService’ which excludes null

_todoService 已经定义成非 null, 怎么还需要判断他是不是 null 呢? 这部是相互矛盾吗?

于是, 我把它定义出 null-able: TodoService? _todoService; 然后在运行 flutter run, 进而报错:

1
Invalid value: Valid value range is empty

报错的语句是:

1
2
3
4
5
6
static BeanFactory init() {
...
...
...
return _factoryList[0]; // 报错
}

最后我不得不承认, dart 语言中, 对于单例模式, 我不会设计, 只好搜索, 正确而且完整的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class BeanFactory {
static final List<BeanFactory> _factoryList = [];
TodoService? _todoService;

BeanFactory._init();

static BeanFactory init() {
if (_factoryList.isEmpty) {
DatabaseFactory.generateDatabase();
_factoryList.add(BeanFactory._init());
}
return _factoryList[0];
}

getTodoService() {
_todoService ??= TodoServiceImpl();
return _todoService;
}
}

注意:
构造函数定义成私有的方法: BeanFactory._init();

来源:
jianshu.com/p/dad432427b3b

10 关于 DateTime 和 时间戳之间的转换?

1
2
3
4
5
6
void dateFromMS() {
DateTime now = DateTime.now();
int ms = now.millisecondsSinceEpoch;
DateTime now2 = DateTime.fromMicrosecondsSinceEpoch(ms);
print("${now.toString()}, ${ms}, ${now2.toString()}");
}
1
2021-11-08 14:10:06.139508, 1636351806139, 1970-01-20 06:32:31.806139

为什么会这样? 为什么转换之前是当前日期, 转换之后是 1970 年?
请注意 milliseconds(毫秒, 千分之一秒) 和 Microseconds(微妙, 百万分之一秒) 的区别

11 dart 导入的类名重复怎么办?

解决方法:
采用 as 语句来进行重命名, 例如:

1
import 'package:xxx/xxx/todo.dart' as todo_item

如何定义变量:

1
late todo_item.Todo _item;

我们可以把 todo_item 当作包名来看待, Todo 就是类名

12 flutter 如何单独给 checkbox 更改显示颜色?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 Checkbox(
value: false,
onChanged: onSelectedItem,
fillColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return ThemeData.from(colorScheme: ColorScheme.light()).disabledColor;
}
if (states.contains(MaterialState.selected)) {
return ThemeData().toggleableActiveColor;
}
// 最终返回
return todoItemColor;
}),
)

来源:
jianshu.com/p/bca01ce93f79

13 flutter TextField 如何赋值?

设置 TextField.controller 属性, 并且通过 controller 来赋值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
TextEditingController _titleController = TextEditingController();
_titleController.value = _titleController.value.copyWith(
text: _item.title ?? ""
);
~~~.controller =
注意: 我们只需要设置 TextField.controller:_titleController 即可

参考:
jianshu.com/p/f6f84d3a0292


# 14 dart 日期和字符串如何进行转换?
A) 字符串转成日期
~~~dart
// 1.
DateTime datetime1 = DateTime.parse("2020-01-10");

// 2.
DateTime datetime2 = HttpDate.parse("2020-01-10");

// 3.
DateFormat format = DateFormat("yyyy-MM-dd");
DateTime datetime3 = format.parse("2020-01-10");

B) 日期转成字符串

1
2
DateFormat format = DateFormat("yyyy-MM-dd");
DateTime datetime1 = format.format(DateTime.now());

来源:
woolha.com/tutorials/dart-convert-string-to-datetime

15 flutter 中使用 sqlLite, 测试时运行 windows 应用, 如何查看 sqlLite 中的数据?

目前无解, 有人建议使用 moor, 来源:
stackoverflow.com/questions/60170406/is-there-a-solution-to-work-with-sqlite-on-flutter-desktop-for-windows

但这是2021年年初的情况, 目前我的数据已经可以存储和获取, 但遇到问题时就不知道如何查看数据库里面的数据。

16 dart 如何取模?

dart 取模运算标识符为 ~/, java 是 %, 但在 dart 中, % 表示取余。

17 dart 如何给枚举 (enum) 添加方法?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
enum DateType {
millionSecond,
second,
minute,
hour,
day,
month,
year,
custom
}

extension DateTypeExtension on DateType {
String get name => describeEnum(this);

int get toMinute {
if (this == DateType.hour) {
return 60;
} else if (this == DateType.day) {
return 60 * 24;
} else if (this == DateType.month) {
return 60 * 24 * 30;
} else if (this == DateType.year) {
return 60 * 24 * 365;
} else {
return 0;
}
}

static List<String> labels() {
// ms: million second, s: second, m: minute, h: hour,
//d: day, M: month, y: year
return ["ms", "s", "m", "h", "d", "M", "y"];
}

}

在上面的代码中, 我们给 DateType 这个枚举类添加 2 个方法: name, toMinute, 还添加了一个方法 labels

这就是 extension 的用法

1
2
3
print(DateType.hour.name); // hour
print(DateType.hour.toMinute); // 60
print(DateTypeExtension.labels()); // ["ms", "s", "m", "h", "d", "M", "y"]

注意: static 方法要使用时, 引用名只能使用 Exception 类的名称, 不能使用枚举类名, 在上面的例子中, DateType.labels() 将会引发报错。

18 为什么代码会一片混乱, 如何让他看起来更简洁一点?

今天看到自己的代码一片混乱, 于是进行了重构, 得出下面的结论:
两个或者两个以上的变量, 如果在某个地方使用到其中一个变量, 另外一个变量也会不可避免的使用到, 我们应该将他们封装曾一个实体类, 然后只需要定义一个变量, 这个变量的数据类型就是该实体类。

这样做的好处:

  1. 代码简洁
    2) 可读性高

举例子:
todoline++ 项目中的待办任务, 预计消耗时间我们需要显示 5 min, 6 hr 之类, 用来表示 5 分钟, 6 小时, 这样的话, 我们就需要两个变量来表示, 一个用来表示时间量, 另外一个用来表示时间类型, 但当我们大量使用到这两个变量时, 方法之间的参数传递, 以及分钟和小时之间的转换, 就会让代码看起来到处都见到这两个变量的身影, 当我们封装成一个实体类了以后, 变量只需要定义一个就可以了, 参数传递也需要一个变量就可以了, 更重要的是, 与这两个变量有关的操作, 都可以封装在实体类中, 代码得到重复利用, 看起来也就简洁多了。

19 flutter 如何旋转 icon 图标?

  1. 方案1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Transform.rotate(
    angle: 330 * 3.14159 / 180, // 330 代表旋转的度数
    child: IconButton(
    iconSize: 40,
    icon: const Icon(Icons.send),
    onPressed: () {

    },
    ),
    )
  2. 方案2
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    RotatedBox(
    quarterTurns: 4, // 只能填写1,2,3,4, 分别代表90度,180度,270度,360度
    child: IconButton(
    iconSize: 40,
    icon: const Icon(Icons.send),
    onPressed: () {

    },
    ),
    )

个人推荐使用方案1, 旋转的度数比较精确

20 如何实现点击按钮, App 页面底部弹出窗口, 窗口上面可以输入文字, 弹出的时候自动调出软键盘, 关闭的时候自动关闭软键盘?

使用 showModelButtonSheet 来实现底部弹出窗口, 至于上面布局 TextField 就不用说了!

设置 TextField.autoFocus = true 就能实现自动弹出软键盘, 关闭窗口后, 软键盘会自动消失。

软键盘弹出后把 TextField 遮盖了怎么办?

请参考这里来解决: codeleading.com/article/44633407955/

弹出的窗口中, 使用 setState 无法更新界面怎么办?

我做测试看到的效果, 需要点击两次界面才会更新, 根据网上的说法, 当我们在 showModalBottomSheet 调用 setState 的时候, 相当于 showModalBottomSheet 这个类里面进行更新, 但是这个类里面包裹的组件并没有更新, 这是我脑补的结果, 那么我们怎么办呢?

使用 StatefulBuilder, 具体参考这里: jianshu.com/p/949a638cd465

上面 3 个问题, 全部解决代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
popupModelButtonSheet() {
int _todoType = 0;
TextEditingController _titleController = TextEditingController();

showModalBottomSheet(
context: context,
isScrollControlled: true, // !important
builder: (BuildContext context) {
return StatefulBuilder(builder: (builder, sate) {
return SingleChildScrollView( // !important
child: Container(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), // !important
child: Container(
padding: const EdgeInsets.fromLTRB(5, 0, 5, 5),
height: MediaQuery.of(context).size.height * 0.20,
color: const Color(0xfff1f1f1),
child: Column(
children: [
Row(
children: [
Expanded(
flex: 10,
child: AppWidget.getLayoutOfTodoTitle(_titleController, true),
),
Expanded(
flex: 2,
child: AppWidget.getLayoutOfTodoType(_todoType, (int? index) {
sate(() {
_todoType = index ?? 0;
});
}, todoTypeColorList[_todoType]),
),
],
),
]
),
),
),
);
});
},
);
}

上面标识为 important 的, 这是防止软键盘覆盖内容的重点。

21 flutter 如何使用路由?

1
2
3
4
5
6
7
8
9
10
11
12
MaterialApp(
...
...
...
routes: {
"/home": (context) => const UserRegister(title:""),
"/Inbox": (context) => const Inbox(title: 'Inbox'),
"/Todo": (context) => const Todo(title: 'Todo Item'),
},
initialRoute: "/home",
home: const Todo(title: 'Todo Item'),
);

设置路由后 App 运行的第一个界面是 initialRoute 指定的页面, 而不是 home 界面, 但是不是不设置 home 就会报错。

22 MaterialApp 设置 initialRoute 后, home 有什么作用?

未知, 目前不知道

23 flutter 如何在页面初始化的时候进行路由跳转?

背景:
flutter 使用 sqlite 来存储数据, 在用户打开页面的时候, 先从 sqlLite 中获取用户数据, 如果用户数据存在, 就进入用户主页, 否则让用户注册, 这样的话就需要进行跳转,要么跳转到用户注册页面, 要么跳转到用户主页, 如何在页面初始化的时候进行跳转呢?

如何在初始化的时候进行跳转?

重写 initState() 方法, 然后在里面进行跳转, 不要在 build 方法里面跳转, build 方法是渲染页面使用的, 他要求必须返回 Widget 对象, 而且还不能返回 null 值.

floor 初始化数据库是异步进行, 在 initState() 方法里面初始化数据库, 然后获取数据库对象为空, 怎么办?

我的解决办法是, 在 main 页面中重写 createElement() 方法, 并在里面初始化数据库, 在跳转页面中获取数据库对象。

注意:
stateless 页才可以重写 createElement 方法, statefull 页面请在 initState 进行。

24 flutter 在 windows 上调试, 如何清空 sqlite 数据库?

背景:
flutter 使用 sqlLite 来存储数据, 并使用 floor 框架进行映射, 在调试的时候, 有时候我们需要清空数据库, 在 android 中我们可以通过卸载 APP 来达到清空数据库的目的, 可以是在 windows 中, 我们如何清空数据库呢?

解决办法:
我的做法是, 使用 cmd 命令 flutter clean 运行一下, 我们就可以清空数据库了。

25 flutter 如何定义和使用路由?

  1. 如何定义路由?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     MaterialApp(
    routes: {
    "/Home": (context) => const Home(title:""),
    "/SignUp": (context) => const SignUp(title:""),
    "/Inbox": (context) => const Inbox(title: 'Inbox'),
    "/Todo": (context) => const Todo(title: 'Todo Item'),
    },
    initialRoute: firstPage,
    home: const Home(title:""),
    )
  2. 如何通过路由跳转到某个页面?
    Navigator.pushNamed(context, “/Inbox”, arguments: list[0]);

  3. 如何返回上一个页面?
    Navigator.pop(context);

26 flutter 中 GestureDetector 做什么用?

就是负责跟用户的手势交互

来源: blog.csdn.net/LJLThomson/article/details/116463135

27 A RenderFlex overflowed by 16 pixels on the right

发生这个问题, 我的经验是, 分配给组件的屏幕空间太小, 无法完全显示引起, 特别是使用 Expanded 组件, 通过 flex 属性按照比例来设置显示宽度, 如果分配的屏幕空间太小, 就会报错。

28 DropdownButton 实现的下拉框, 图标和文字距离太大, 如何修改?

只需要调整 DropdownButton 的宽度就可以, 他会自动调整好的。

29 TextField 如何取消下划线?

TextField.decoration.border: InputBorder.none,

来源: blog.csdn.net/mp624183768/article/details/116496546

30 DropdownButton 选择项目后没有更新, 怎么办?

按照这个说明无法解决问题:
fluttercampus.com/guide/126/how-to-fix-dropdown-button-not-switching-selected-item-in-flutter/

附: 按照上面的说明, 行不通的原因是:
setState 方法中重新赋值的变量不是全局变量, 他需要是类的全局变量, 单纯在 build 里面定义该变量不行, 一个可能的原因是, flutter 区分有状态和无状态的组件, 有状态组件更新时会自动更新该页面的所有组件, 这样的话他需要重新运行一遍 build 方法, 才会重新渲染页面。 既然重新运行了 build 方法, build 方法中定义的变量就得重新定义, 这样的话 setState 方法中赋值永远失败, 这是我个人脑补的结果。

31 dart enum 如何获取名称?

1
2
enum Color{red, black}
String name = Color.red.toString(); // name = Color.red

如何想获取字符串 red, 怎么办?
String name = Color.red.toString().split(“.”).last();

来源: stackoverflow.com/questions/29567236/dart-how-to-get-the-value-of-an-enum

32 flutter 如何添加浮动按钮?

什么是浮动按钮?
即我们平时看到的在 App 界面右下角的加号按钮

如何添加浮动按钮?
fluttr 界面布局, 都会用到 Scaffold, Scaffold 有 floatingActionButton 属性, 给这个属性设置一个 wiget 即可?

33 flutter IconButton 如何设置背景色和前景色?

我看到别人的浮动按钮, 那个加号按钮, 外面的圆圈是绿色或者蓝色, 里面的加号是白色, 我如何调整像他们一样调整背景色和前景色?

icon 只有一种颜色, 我们之所以看到外面蓝色的圆圈, 里面是白色的加号, 那是因为图标中间加号这些区域是空心的, 可以看到后面的背景色, 只要整个页面背景色是白色, 把图标颜色调成蓝色即可看到这个效果。

34 flutter 如何使用下拉选择框

1
2
3
4
5
6
DropdownButton(
items:[
Icon(Icons.calendar_today),
Icon(Icons.loop),
]
)

来源: jianshu.com/p/cba2171bcf30


分享到:


  如果您觉得这篇文章对您的学习很有帮助, 请您也分享它, 让它能再次帮助到更多的需要学习的人. 您的支持将鼓励我继续创作 !
本文基于署名4.0国际许可协议发布,转载请保留本文署名和文章链接。 如您有任何授权方面的协商,请邮件联系我。

Contents

  1. 1 dart 如何使用绝对值?
  2. 2 flutter Align 中的 widthFactor 做什么用?
  3. 3 flutter 如何画圆形进度条?
    1. 存在的问题:
    2. 解决办法:
    3. 意外:
    4. 来源:
  • 4 IconButton 如何调整原来的 padding ?
  • 5 fluter 如何让两个组件层叠起来?
  • 6 Flutter textField 的 onEditingComplete 事件为什么没有触发?
  • 7 dar 语言中, 对一组字符串? 如何去掉重复数据?
  • 8 dart 语言操作符 ??= 是什么意思?
  • 9 dart 语言如何设计单利模式?
  • 10 关于 DateTime 和 时间戳之间的转换?
  • 11 dart 导入的类名重复怎么办?
  • 12 flutter 如何单独给 checkbox 更改显示颜色?
  • 13 flutter TextField 如何赋值?
  • 15 flutter 中使用 sqlLite, 测试时运行 windows 应用, 如何查看 sqlLite 中的数据?
  • 16 dart 如何取模?
  • 17 dart 如何给枚举 (enum) 添加方法?
  • 18 为什么代码会一片混乱, 如何让他看起来更简洁一点?
  • 19 flutter 如何旋转 icon 图标?
  • 20 如何实现点击按钮, App 页面底部弹出窗口, 窗口上面可以输入文字, 弹出的时候自动调出软键盘, 关闭的时候自动关闭软键盘?
    1. 软键盘弹出后把 TextField 遮盖了怎么办?
    2. 弹出的窗口中, 使用 setState 无法更新界面怎么办?
  • 21 flutter 如何使用路由?
  • 22 MaterialApp 设置 initialRoute 后, home 有什么作用?
  • 23 flutter 如何在页面初始化的时候进行路由跳转?
  • 24 flutter 在 windows 上调试, 如何清空 sqlite 数据库?
  • 25 flutter 如何定义和使用路由?
  • 26 flutter 中 GestureDetector 做什么用?
  • 27 A RenderFlex overflowed by 16 pixels on the right
  • 28 DropdownButton 实现的下拉框, 图标和文字距离太大, 如何修改?
  • 29 TextField 如何取消下划线?
  • 30 DropdownButton 选择项目后没有更新, 怎么办?
  • 31 dart enum 如何获取名称?
  • 32 flutter 如何添加浮动按钮?
  • 33 flutter IconButton 如何设置背景色和前景色?
  • 34 flutter 如何使用下拉选择框