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, 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), ), ), 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)), ), 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], 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( 0.5,color: Colors.grey);
)
),
12、装饰器设置 border,背景
decoration: BoxDecoration( color: Colors.white, border: Border( bottom: BorderSide( 0.5,color: Colors.black12); ) ),