效果:
代码:
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
final double maxHeight = 200;
final double minHeight = 50;
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late AnimationController _ac;
final VelocityTracker _vt = VelocityTracker.withKind(PointerDeviceKind.touch);
@override
void initState() {
super.initState();
_ac = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
}
@override
void dispose() {
_ac.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sliding Box"),
bottom: PreferredSize(
preferredSize: Size.fromHeight(75),
child: Container(
height: 75,
alignment: Alignment.center,
width: double.infinity,
color: Colors.blueGrey,
child: Text("Fixed header"),
),
),
),
body: Column(
children: [
Listener(
onPointerDown: (PointerDownEvent p) => _vt.addPosition(p.timeStamp, p.position),
onPointerMove: (PointerMoveEvent p) {
_vt.addPosition(p.timeStamp, p.position);
_onGestureSlide(p.delta.dy);
},
onPointerUp: (PointerUpEvent p) => _onGestureEnd(_vt.getVelocity()),
child: AnimatedBuilder(
animation: _ac,
builder: (BuildContext context, Widget? child) {
return Container(height: 200 * _ac.value + 26, child: child!);
},
child: Stack(
children: [
_panelBody(),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: _buildSlideIndicator(),
),
],
),
),
),
],
),
);
}
void _onGestureSlide(double dy) {
//向下滚动 dy > 0; 向上滚动 dy < 0
// print('slide: $dy');
_ac.value += dy / (widget.maxHeight - widget.minHeight);
}
void _onGestureEnd(Velocity v) {
print('onGestureEnd: ${v.pixelsPerSecond.dy}');
//如果动画已经运行,则直接返回
if (_ac.isAnimating) return;
double visualVelocity = v.pixelsPerSecond.dy / (widget.maxHeight - widget.minHeight);
print('pixelsPerSecond: ${v.pixelsPerSecond.dy}, visualVelocity: $visualVelocity');
//若当前下拉速度超过阈值,则进行 fling
if (v.pixelsPerSecond.dy.abs() >= 365) {
//velocity 等于 -1 是关闭,1 是打开
//fling,按一秒的时间计算滑过的距离
_ac.fling(velocity: visualVelocity);
return;
}
// 若当前下拉速度未超过阈值
if (_ac.value >= 0.5) {
_ac.fling(velocity: 1);
} else {
_ac.fling(velocity: -1);
}
}
Widget _panelBody() {
return Container(
color: Colors.green,
);
}
Widget _buildSlideIndicator() {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
color: Colors.red,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 30,
height: 5,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.all(Radius.circular(12.0)),
),
),
],
),
);
}
}
标签:ac,return,fling,double,dy,child,滑动,面板,flutter
From: https://www.cnblogs.com/lemos/p/17044951.html