目录
- GestureDetector
- 点击事件
- 双击事件
- 长按事件
- 水平/垂直拖动事件
- 缩放事件
- InkWell
- Ink
- Listener
- 案例
GestureDetector
GestureDetector 是手势识别的组件,可以识别点击、双击、长按事件、拖动、缩放等手势
点击事件
点击相关事件包括:
- onTapDown:按下时回调。
- onTapUp:抬起时回调。
- onTap:点击事件回调。
- onTapCancel:点击取消事件回调。
按下然后抬起调用顺序
onTapDown-> onTapUp-> onTap
按下后移动调用顺序
onTapDown-> onTapCancel
示例
class _YcHomeBodyState extends State<YcHomeBody> { | |
String desc = ''; | |
Color containerColor = Colors.red; | |
@override | |
Widget build(BuildContext context) { | |
return GestureDetector( | |
child: Column( | |
children: [ | |
Container( | |
width:, | |
height:, | |
color: containerColor, | |
), | |
const SizedBox( | |
width:, | |
height:, | |
), | |
Text("点击事件:$desc") | |
], | |
), | |
onTapDown: (TapDownDetails tapDownDetails) { | |
setState(() { | |
desc += '按下,'; | |
containerColor = Colors.blue; | |
}); | |
}, | |
onTapUp: (TapUpDetails tapUpDetails) { | |
setState(() { | |
desc += '抬起,'; | |
containerColor = Colors.red; | |
}); | |
}, | |
onTap: () { | |
setState(() { | |
desc += '点击,'; | |
containerColor = Colors.yellow; | |
}); | |
}, | |
onTapCancel: () { | |
setState(() { | |
desc += '取消,'; | |
containerColor = Colors.pink; | |
}); | |
}, | |
); | |
} | |
} |
双击事件
双击是快速且连续2次在同一个位置点击,双击监听使用onDoubleTap方法
return GestureDetector( | |
child: Column( | |
children: [ | |
Container( | |
width:, | |
height:, | |
color: containerColor, | |
), | |
const SizedBox( | |
width:, | |
height:, | |
), | |
Text("点击事件:$desc") | |
], | |
), | |
onDoubleTap: () { | |
setState(() { | |
desc = '双击了'; | |
}); | |
}, |
长按事件
长按事件(LongPress)包含长按开始、移动、抬起、结束事件,说明如下:
- onLongPressStart:长按开始事件回调。
- onLongPressMoveUpdate:长按移动事件回调。
- onLongPressUp:长按抬起事件回调。
- onLongPressEnd:长按结束事件回调。
- onLongPress:长按事件回调。
示例
return GestureDetector( | |
child: Column( | |
children: [ | |
Container( | |
width:, | |
height:, | |
color: containerColor, | |
), | |
const SizedBox( | |
width:, | |
height:, | |
), | |
Text("点击事件:$desc") | |
], | |
), | |
onLongPressStart: (v) { | |
setState(() { | |
desc += '长按开始,'; | |
print("长按开始:$v"); | |
}); | |
}, | |
onLongPressMoveUpdate: (v) { | |
setState(() { | |
desc += '长按移动,'; | |
print("长按移动:$v"); | |
}); | |
}, | |
onLongPressUp: () { | |
setState(() { | |
desc += '长按抬起,'; | |
print("长按抬起"); | |
}); | |
}, | |
onLongPressEnd: (v) { | |
setState(() { | |
desc += '长按结束,'; | |
print("长按结束:$v"); | |
}); | |
}, | |
onLongPress: () { | |
setState(() { | |
desc += '长按回调,'; | |
print("长按回调"); | |
}); | |
}); |
执行顺序
1、长按开始->回调->结束->抬起
2、长按开始->回调->移动->结束->抬起
水平/垂直拖动事件
垂直/水平拖动事件包括按下、开始、移动更新、结束、取消事件,以垂直为例说明如下:
- onVerticalDragDown:垂直拖动按下事件回调
- onVerticalDragStart:垂直拖动开始事件回调
- onVerticalDragUpdate:指针移动更新事件回调
- onVerticalDragEnd:垂直拖动结束事件回调
- onVerticalDragCancel:垂直拖动取消事件回调
GestureDetector( | |
onVerticalDragStart: (v) => print('onVerticalDragStart'), | |
onVerticalDragDown: (v) => print('onVerticalDragDown'), | |
onVerticalDragUpdate: (v) => print('onVerticalDragUpdate'), | |
onVerticalDragCancel: () => print('onVerticalDragCancel'), | |
onVerticalDragEnd: (v) => print('onVerticalDragEnd'), | |
child: Center( | |
child: Container( | |
width:, | |
height:, | |
color: Colors.red, | |
), | |
), | |
) |
缩放事件
缩放(Scale)包含缩放开始、更新、结束。说明如下:
- onScaleStart:缩放开始事件回调。
- onScaleUpdate:缩放更新事件回调。
- onScaleEnd:缩放结束事件回调。
GestureDetector( | |
onScaleStart: (v) => print('onScaleStart'), | |
onScaleUpdate: (ScaleUpdateDetails v) => print('onScaleUpdate'), | |
onScaleEnd: (v) => print('onScaleEnd'), | |
child: Center( | |
child: Container( | |
width:, | |
height:, | |
color: Colors.red, | |
), | |
), | |
) |
InkWell
InkWell 组件在用户点击时出现“水波纹”效果。事件和属性挺多的,就看一下常用的
设置水波纹颜色
点击和长按都能够触发水波纹,点击波纹效果快,长按波纹效果慢
return InkWell( | |
onTap: (){ | |
print("点击了"); | |
}, | |
splashColor: Colors.red, | |
child: const Text('点击InkWell,水波纹'), | |
); |
给字体添加边距和圆角边框,扩大“水波纹”效果:
Center( | |
child: InkWell( | |
onTap: () { | |
print("点击了"); | |
}, | |
splashColor: Colors.red, | |
child: Container( | |
padding: const EdgeInsets.all(), | |
decoration: BoxDecoration( | |
border: Border.all(color: Colors.red), | |
borderRadius: const BorderRadius.all(Radius.circular())), | |
child: const Text('点击InkWell,水波纹'))), | |
); |
可以看到水波纹会超出圆角,为了解决这个问题可以使用Ink
Ink
Ink控件用于在[Material]控件上绘制图像和其他装饰,以便[InkWell]、[InkResponse]控件的“水波纹”效果在其上面显示。
return Center( | |
child: Ink( | |
decoration: const BoxDecoration( | |
gradient: LinearGradient( | |
begin: Alignment.topLeft, | |
end: Alignment.bottomRight, | |
colors: [Color(xFFDE2F21), Color(0xFFEC592F)]), | |
borderRadius: BorderRadius.all(Radius.circular())), | |
child: InkWell( | |
borderRadius: const BorderRadius.all(Radius.circular()), | |
child: Container( | |
padding: const EdgeInsets.symmetric(vertical:, horizontal: 20), | |
child: const Text( | |
'这是InkWell的点击效果', | |
style: TextStyle(color: Colors.white), | |
), | |
), | |
onTap: () {}, | |
), | |
)); | |
} |
总感觉有点复杂,InkWell 会导致水纹超出边框,就需要外面再套一层组件,然后还要写个渐变,不知道咋形容。
Listener
Listener 是一个监听指针事件的控件,比如按下、移动、释放、取消等指针事件,但Listener无法监听鼠标特有的事件,比如:移入、悬停、移出事件。鼠标事件使用MouseRegion监听。
通常情况下,监听手势事件使用GestureDetector,GestureDetector是更高级的手势事件。
Listener的事件介绍如下:
- onPointerDown:按下时回调
- onPointerMove:移动时回调
- onPointerUp:抬起时回调
Listener( | |
onPointerDown: (PointerDownEvent pointerDownEvent) { | |
print('$pointerDownEvent'); | |
}, | |
onPointerMove: (PointerMoveEvent pointerMoveEvent) { | |
print('$pointerMoveEvent'); | |
}, | |
onPointerUp: (PointerUpEvent upEvent) { | |
print('$upEvent'); | |
}, | |
child: Container( | |
height:, | |
width:, | |
color: Colors.blue, | |
alignment: Alignment.center, | |
), | |
) |
常用属性说明如下:
position:相对屏幕的坐标的偏移。
localPosition:相对当前控件的偏移。
pressure:按压力度。
delta:2次指针移动事件的偏移。
orientation:指针移动方向
案例
进度按钮
// 使用枚举定义按钮的状态 | |
enum ButtonStates { none, loading, done } | |
class YcHomeBody extends StatefulWidget { | |
const YcHomeBody({Key? key}) : super(key: key); | |
State<YcHomeBody> createState() => _YcHomeBodyState(); | |
} | |
class _YcHomeBodyState extends State<YcHomeBody> { | |
//定义按钮的状态 | |
ButtonStates _buttonStates = ButtonStates.none; | |
Widget build(BuildContext context) { | |
return Center( | |
child: MaterialButton( | |
color: Colors.blue, | |
textColor: Colors.white, | |
minWidth:, | |
height:, | |
//通过自定义方法,根据情况返回相应的组件 | |
child: _build(), | |
onPressed: () { | |
//点击按钮后将按钮状态变为加载中 | |
setState(() { | |
_buttonStates = ButtonStates.loading; | |
//延迟s后将状态变为完成 | |
Future.delayed(const Duration(seconds:), () { | |
setState(() { | |
_buttonStates = ButtonStates.done; | |
}); | |
}); | |
}); | |
}, | |
), | |
); | |
} | |
//自定义方法 | |
_build() { | |
if (_buttonStates == ButtonStates.none) { | |
//无状态 | |
return const Text("登录"); | |
} else if (_buttonStates == ButtonStates.loading) { | |
//进度条组件 | |
return const CircularProgressIndicator( | |
backgroundColor: Colors.white, | |
strokeWidth:, | |
); | |
} else if (_buttonStates == ButtonStates.done) { | |
return const Icon( | |
Icons.check, | |
color: Colors.white, | |
); | |
} | |
} | |
} |
代码看着很长但是逻辑很简单,定义了一个枚举类型的按钮类型。一开始类型为无状态,此时显示登录;当点击按钮后,状态变为加载中,显示圆形进度条组件;2s后将按钮状态变为加载完成,现成完成的图标