1、监听事件:以 Listener包裹组件支持的监听包含: onPointerDown,onPointerMove,onPointerUp,onPointerCancel。
同 Listener 类似,有 IgnorePointer(忽略本身),和AbsorbPointer(不忽略本身)。 忽略事件。
更强大的手势组件 GestureDetector (onTap) , 如果需要有波纹效果则用 InkWell代替,具有类似效果的还有RaisedBuitton、FlatButton、CupertinoButton。
2、
InkWell(波纹显示按压效果组件同GestureDetector) 必须以Material 组件为祖先,点击(出现波纹)组件.
double sideLength = 50;
Widget build(BuildContext context) {
return AnimatedContainer(
height: sideLength,
width: sideLength,
duration: Duration(seconds: 2),
curve: Curves.easeIn,
child: Material(
color: Colors.yellow,
child: InkWell(
onTap: () {
setState(() {
sideLength == 50 ? sideLength = 100 : sideLength = 50;
});
},
),
),
);
}
3、column和row 不支持滚动,如果要滚动请选用ListView ,复杂列表滚动效果:GridView和CustomScrollView(多列竖向滚动)。
row 撑破横向的情况下,可以用wrap代替row
4、InheritedWidget 父节点
5、runZoned 代码执行环节范围,自定义一些代码行为,比如拦截日志输出行为等。
下面是拦截应用中所有调用print
输出日志的行为
main() {
runZoned(() => runApp(MyApp()), zoneSpecification: new ZoneSpecification(
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
parent.print(zone, "Intercepted: $line");
}),
);
}
异常捕获
runZoned(() {
runApp(MyApp());
}, onError: (Object obj, StackTrace stack) {
var details=makeDetails(obj,stack);
reportError(details);
});
需要注意的是,error-zone内部发生的错误是不会跨越当前error-zone的边界的,如果想跨越error-zone边界去捕获异常,可以通过共同的“源”zone来捕获,如
var future = new Future.value(499);
runZoned(() {
var future2 = future.then((_) { throw "error in first error-zone"; });
runZoned(() {
var future3 = future2.catchError((e) { print("Never reached!"); });
}, onError: (e) { print("unused error handler"); });
}, onError: (e) { print("catches error of first error-zone."); });
6、组件之间状态管理
- 如果状态是用户数据,如复选框的选中状态、滑块的位置,则该状态最好由父Widget管理。
- 如果状态是有关界面外观效果的,例如颜色、动画,那么状态最好由Widget本身来管理。
- 如果某一个状态是不同Widget共享的则最好由它们共同的父Widget管理。
下边是回调通知父组件的方法: ValueChanged是 值改变(方法)类型
// ParentWidget 为 TapboxB 管理状态.
//------------------------ ParentWidget --------------------------------
class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => new _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return new Container(
child: new TapboxB(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
//------------------------- TapboxB ----------------------------------
class TapboxB extends StatelessWidget {
TapboxB({Key key, this.active: false, @required this.onChanged})
: super(key: key);
final bool active;
final ValueChanged<bool> onChanged;
void _handleTap() {
onChanged(!active);
}
Widget build(BuildContext context) {
return new GestureDetector(
onTap: _handleTap,
child: new Container(
child: new Center(
child: new Text(
active ? 'Active' : 'Inactive',
style: new TextStyle(fontSize: 32.0, color: Colors.white),
),
),
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: active ? Colors.lightGreen[700] : Colors.grey[600],
),
),
);
}
}
混合状态管理 (父子都为StatefulWidget)
//---------------------------- ParentWidget ----------------------------
class ParentWidgetC extends StatefulWidget {
@override
_ParentWidgetCState createState() => new _ParentWidgetCState();
}
class _ParentWidgetCState extends State<ParentWidgetC> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return new Container(
child: new TapboxC(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
//----------------------------- TapboxC ------------------------------
class TapboxC extends StatefulWidget {
TapboxC({Key key, this.active: false, @required this.onChanged})
: super(key: key);
final bool active;
final ValueChanged<bool> onChanged;
@override
_TapboxCState createState() => new _TapboxCState();
}
class _TapboxCState extends State<TapboxC> {
bool _highlight = false;
void _handleTapDown(TapDownDetails details) {
setState(() {
_highlight = true;
});
}
void _handleTapUp(TapUpDetails details) {
setState(() {
_highlight = false;
});
}
void _handleTapCancel() {
setState(() {
_highlight = false;
});
}
void _handleTap() {
widget.onChanged(!widget.active);
}
@override
Widget build(BuildContext context) {
// 在按下时添加绿色边框,当抬起时,取消高亮
return new GestureDetector(
onTapDown: _handleTapDown, // 处理按下事件
onTapUp: _handleTapUp, // 处理抬起事件
onTap: _handleTap,
onTapCancel: _handleTapCancel,
child: new Container(
child: new Center(
child: new Text(widget.active ? 'Active' : 'Inactive',
style: new TextStyle(fontSize: 32.0, color: Colors.white)),
),
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: widget.active ? Colors.lightGreen[700] : Colors.grey[600],
border: _highlight
? new Border.all(
color: Colors.teal[700],
width: 10.0,
)
: null,
),
),
);
}
}
7、Text 与 TextSpan
Text的所有文本内容只能按同一种样式,如果我们需要对一个Text内容的不同部分按照不同的样式显示,这时就可以使用TextSpan
,它代表文本的一个“片段”。
children
是一个TextSpan
的数组,也就是说TextSpan
可以包括其他TextSpan
。而recognizer
用于对该文本片段上用于手势进行识别处理。
Text.rich(TextSpan(
children: [
TextSpan(
text: "Home: "
),
TextSpan(
text: "https://flutterchina.club",
style: TextStyle(
color: Colors.blue
),
recognizer: _tapRecognizer
),
]
))
DefaultTextStyle
如果在Widget树的某一个节点处设置一个默认的文本样式,那么该节点的子树中所有文本都会默认使用这个样式
DefaultTextStyle(
//1.设置文本默认样式
style: TextStyle(
color:Colors.red,
fontSize: 20.0,
),
textAlign: TextAlign.start,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("hello world"),
Text("I am Jack"),
Text("I am Jack",
style: TextStyle(
inherit: false, //2.不继承默认样式
color: Colors.grey
),
),
],
),
);
要使用Package中定义的字体,必须提供package
参数。例如,假设上面的字体声明位于my_package
包中。然后创建TextStyle的过程如下:
const textStyle = const TextStyle(
fontFamily: 'Raleway',
package: 'my_package', //指定包名
);
8、使用自定义字体图标
我们也可以使用自定义字体图标。iconfont.cn上有很多字体图标素材,我们可以选择自己需要的图标打包下载后,会生成一些不同格式的字体文件,在Flutter中,我们使用ttf格式即可。
假设我们项目中需要使用一个书籍图标和微信图标,我们打包下载后导入:
- 导入字体图标文件;这一步和导入字体文件相同,假设我们的字体图标文件保存在项目根目录下,路径为"fonts/iconfont.ttf":
fonts:
- family: myIcon #指定一个字体名
fonts:
- asset: fonts/iconfont.ttf
2、为了使用方便,我们定义一个MyIcons
类,功能和Icons
类一样:将字体文件中的所有图标都定义成静态变量:
class MyIcons{
// book 图标
static const IconData book = const IconData(
0xe614,
fontFamily: 'myIcon',
matchTextDirection: true
);
// 微信图标
static const IconData wechat = const IconData(
0xec7d,
fontFamily: 'myIcon',
matchTextDirection: true
);
}
3、使用
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MyIcons.book,color: Colors.purple,),
Icon(MyIcons.wechat,color: Colors.green,),
],
)
9、Container 相当于div,可设置margin,padding。
10、 防止图片溢出 设置Expanded约束
Expanded(
child: Image.network(''),
),
11、装饰器设置 border,背景
decoration: BoxDecoration(
color: Colors.white,
border: Border(
left: BorderSide(width: 0.5,color: Colors.grey);
)
),
12、装饰器设置 border,背景
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(width: 0.5,color: Colors.black12);
)
),