作者:Mo Malaka
声明:本文对原文部分内容进行了精简(原文共 104 条,本文约 30 条)并做了简单翻译。为便于快速定位原文位置,保留了原文的编号。不足之处还请指正,感兴趣的可以阅读原文。 :)
你好读者,
这篇文章列出了我在过去几个月发布的 100 多个(原文 100+)技巧。如果你是 Flutter/Dart 世界的新手,其中一些可能会对你有所帮助。
3- 使用 Future.wait
等待多个 Future
的结果完成
class someAPI {
Future<int> getThings() => Future.value(3000);
Future<int> getItems() => Future.value(300);
Future<int> getStuff() => Future.value(30);
}
...
final api = someAPI();
final values = await Future.wait([
api.getThings(),
api.getItems(),
api.getStuff(),
]);
print(values);
6- 使用 flutter/services.dart
SystemChrome
锁定设备方向
import 'package:flutter/services.dart';
...
void main() async {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
runApp(App());
}
7- 你可以使用 dart:io
库编写特定平台的代码
import 'dart:io' show Platform;
...
if (Platform.isIOS) {
doSomethingforIOS();
}
if (Platform.isAndroid) {
doSomethingforAndroid();
}
8- 将任何 Color 转换为 Material Color
const Map<int, Color> color = {
50: Color.fromRGBO(255, 207, 68, .1),
100: Color.fromRGBO(255, 207, 68, .2),
200: Color.fromRGBO(255, 207, 68, .3),
300: Color.fromRGBO(255, 207, 68, .4),
400: Color.fromRGBO(255, 207, 68, .5),
500: Color.fromRGBO(255, 207, 68, .6),
600: Color.fromRGBO(255, 207, 68, .7),
700: Color.fromRGBO(255, 207, 68, .8),
800: Color.fromRGBO(255, 207, 68, .9),
900: Color.fromRGBO(255, 207, 68, 1),
};
const MaterialColor custom_color = MaterialColor(0xFFFFCF44, color);
9- 使用 flutter/services.dart
SystemChrome
隐藏状态栏
import 'package:flutter/services.dart';
void main() {
SystemChrome.setEnabledSystemUIOverlays([]);
/// 上面接口已废弃,最新方式为:
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
}
11- 使用 FadeInImage
和 transparent_image
库来显示一个透明的占位图,等待图像加载完成时淡入显示
import 'package:transparent_image/transparent_image.dart';
...
FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: someImageUrl,
fit: BoxFit.fill,
),
13- 定制 TextField
光标样式
TextField(
cursorColor: Colors.purple,
cursorRadius: Radius.circular(8.0),
cursorWidth: 8.0,
)
15- 使用 Expanded
调整子 widget 大小,以适应 Row
或 Column
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset('images/pic1.jpg'),
),
Expanded(
child: Image.asset('images/pic2.jpg'),
),
Expanded(
child: Image.asset('images/pic3.jpg'),
),
],
);
16- 使用 Hero
实现以动画的方式,将 widget 从一个页面移动到下一个页面
// Page 1
Hero(
tag: "FlyingHero",
child: Icon(
Icons.party_mode_outlined,
size: 50.0,
),
),
...
// Page 2
Hero(
tag: "FlyingHero",
child: Icon(
Icons.party_mode_outlined,
size: 150.0,
),
),
18- 使用 ThemeData
定义整个应用程序的颜色、字体、形状、设计样式。可以这种方式在一个地方集中设置你所需要的风格。
MaterialApp(
title: appName,
theme: ThemeData(
// The default brightness and colors.
brightness: Brightness.light,
primaryColor: Colors.lightGreen[500],
accentColor: Colors.amber[600], /// 该字段已过时
// The default font family.
fontFamily: 'Georgia',
// TextTheme & text styling
textTheme: TextTheme(
headline1: TextStyle(fontSize: 64.0, fontWeight: FontWeight.bold),
headline6: TextStyle(fontSize: 36.0, fontStyle: FontStyle.italic),
bodyText2: TextStyle(fontSize: 14.0, fontFamily: 'Hind'),
),
),
home: MyHomePage(
title: appName,
),
);
19- 使用 package:flutter/foundation.dart
中的常量 kReleaseMode
在 debug 或 release 模式下执行代码
import 'package:flutter/foundation.dart';
if (kReleaseMode) {
// Release Mode
print('release mode');
} else {
print('debug mode');
}
23- 使用 padLeft
和 padRight
分别在字符串左侧和右侧填充字符。
String s = "fun";
print(s.padLeft(10, ',.*')); // ',.*,.*,.*,.*fun'
print(s.padRight(10, ',.*')); // 'fun,.*,.*,.*,.*'
25- 将 debugShowCheckedModeBanner
设置为 false
可以删除右上角调试横幅标记
MaterialApp(
debugShowCheckedModeBanner: false,
// other arguments
)
28- 要编写任何 Dart 程序——无论是脚本还是 Flutter 应用程序——都必须定义 main()
函数,它是每个应用程序的入口点
void main() {
var list = ['London', 'Dublin', 'Paris'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
}
29- 在按下按钮时更改按钮的文本颜色
TextButton(
onPressed: () {},
style: ButtonStyle(
foregroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) return Colors.pink;
return Colors.black; // Defer to the widget's default.
}),
),
child: Text(
'Change My Color',
style: TextStyle(fontSize: 30),
),
),
32- Dart 允许创建一个可调用的类,可以将类的实例作为函数调用
class WelcomeToTheCity {
// Defining call method
String call(String a, String b, String c) => 'Welcome to $a$b$c';
}
void main() {
var welcome_to_city = WelcomeToTheCity();
// Calling the class through its instance
var welcome_msg = welcome_to_city('SanDiego ', 'CA ', 'USA');
print(welcome_msg);
}
33- 使用 InkWell
创建水波纹效果,产生触摸响应的视觉体验
InkWell(
splashColor: Colors.red,
onTap: () {},
child: Card(
elevation: 5.0,
child: Text(
' Click This ',
style: Theme.of(context).textTheme.headline2,
),
),
),
38- 使用 FittedBox
来缩放调整内部的子部件。它可以限制其子部件的大小避免超过限制,也可以根据可用的大小重新缩放它们。
Center(
child: Row(children: [
Expanded(
child: FittedBox(
child: Text(
"It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.",
maxLines: 1,
style: TextStyle(fontSize: 23),
),
),
),
]))
41- Mixins
可以实现不通过创建子类的方式插入代码块
mixin Fluttering {
void flutter() {
print('fluttering');
}
}
abstract class Bird with Fluttering {
void flap() {
print('flap flap');
}
}
class Hawk extends Bird {
void doHawkThing() {
flap();
flutter();
print('Hawk is Flying');
}
}
main() {
var hawk = new Hawk();
hawk.doHawkThing();
}
42- 可以将一个函数作为参数传递给另一个函数
void main() {
const list = ['London', 'Dublin', 'Belfast'];
list.forEach(
(item) => print('City Of $item'));
}
43- Getter 和 Setter 是提供对象属性读写访问权限的特定方法
class Rectangle {
double left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: right and bottom.
double get right => left + width;
set right(double value) => left = value - width;
double get bottom => top + height;
set bottom(double value) => top = value - height;
}
void main() {
var rect = Rectangle(3, 4, 20, 15);
print(rect.left);
rect.right = 12;
print(rect.left);
}
44- 有四种不同的方式来追加或连接字符串
void main() {
//1- Using ‘+’ operator.
String str1 = "Dart";
String str2 = "Is";
String str3 = "Fun";
print(str1 + str2 + str3);
//2- String interpolation.
print('$str1 $str2 $str3');
//3- Directly writing string literals.
print('Dart' 'Is' 'Fun');
//4- Strings.join() method.
// Creating List of strings
List<String> str = ["Dart", "Is", "Fun"];
String _thestr = str.join();
print(_thestr);
_thestr = str.join(" ");
print(_thestr);
}
49- 使用 barrierDismissible
属性来防止点击 Dialog
外部区域时关闭 AlertDialog
。
...
showDialog<String>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) => AlertDialog(
title: const Text('This is a title'),
content: const Text('This is a description'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.pop(context, 'OK'),
child: const Text('OK'),
),
],
),
),
...
51- 使用 ShaderMask
为子节点设置渐变外观
Center(
child: ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (Rect bounds) {
return LinearGradient(
colors: [Colors.red, Colors.green],
tileMode: TileMode.clamp,
).createShader(bounds);
},
child:
const Text('This is a colorful Text', style: TextStyle(fontSize: 36)),
),
)
54- 使用 ColorFiltered
对其子节点设置颜色过滤器
Column(
children: [
// The original image
Image.network('https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1d18e23b15fb427293c63c269c8a6847~tplv-k3u1fbpfcp-no-mark:480:480:0:0.awebp?'),
// The black-and-white image
ColorFiltered(
colorFilter: ColorFilter.mode(Colors.grey, BlendMode.saturation),
child: Image.network('https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1d18e23b15fb427293c63c269c8a6847~tplv-k3u1fbpfcp-no-mark:480:480:0:0.awebp?'),
),
],
)
57- 可以使用 LayoutBuilder
获取父 Widget 大小,并根据父 Widget 大小创建子 Widget 树
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth >= 750) {
return Container(
color: Colors.green,
height: 100,
width: 100,
);
} else {
return Container(
color: Colors.yellow,
height: 100,
width: 100,
);
}
},
)
75- 使用 GestureDetector
检测手势,如点击、双击、按下、长按、平移、拖动、缩放等
Container(
color: _color,
height: 200.0,
width: 200.0,
child: GestureDetector(
onTap: () {
setState(() {
_color = Colors.yellow;
});
},
),
)
77- 使用 Future.delayed()
将程序暂停一段时间
await Future.delayed(const Duration(seconds: 1));
82- 使用 Flexible
修复 Text Overflow 错误
Flexible(
child: Text(
'Flutter Text Overflow while adding long text. how to wrap text in flutter ',
style: TextStyle(fontSize: 20),
),
)
86- 使用 PhysicalModel
添加自定义阴影效果并自定义其颜色和形状
PhysicalModel(
elevation: 6.0,
shape: BoxShape.circle,
shadowColor: Colors.black,
color: Colors.white,
child: Container(
height: 120.0,
width: 120.0,
alignment: Alignment.center,
child: Text('Content'),
),
)
91- 使用 Tooltip
帮助解释按钮或其他用户界面操作的功能
Tooltip(
message: 'I am a Tooltip',
triggerMode: TooltipTriggerMode.tap,
child: Text('Hover over the text to show a tooltip.'),
)
92- SelectableText
允许用户选择/复制 UI 上的内容
const SelectableText(
'Hello! How are you?',
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold),
)
100- Baseline
可以根据其 child 的基线定位 child 的位置
Center(
child: Container(
color: Colors.blue,
height: 120.0,
width: 120.0,
child: Baseline(
child: Container(
color: Colors.red,
height: 60.0,
width: 60.0,
),
baseline: 20.0,
baselineType: TextBaseline.alphabetic,
),
),
)
101- Baner 会在另一个Widget的角落上方显示一条对角线消息
Center(
child: Container(
margin: const EdgeInsets.all(10.0),
color: Colors.yellow,
height: 100,
child: ClipRect(
child: Banner(
message: "hello",
location: BannerLocation.topEnd,
color: Colors.red,
child: Container(
color: Colors.yellow,
height: 100,
child: Center(
child: Text("Hello, banner!"),
),
),
),
),
),
)
103/104 - IntrinsicWidth/IntrinsicHeight 可以将它的子 widget 的宽度/高度调整其本身实际的宽度/高度
...
IntrinsicWidth(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
width: 200,
height: 100,
color: Colors.teal,
),
Expanded(
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
],
),
)
...
IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
width: 150,
height: 100,
color: Colors.teal,
),
Container(
width: 150,
height: 200,
color: Colors.red,
)
],
),
)
...