Improve player animation.

This commit is contained in:
stonegate 2020-07-09 03:48:41 +08:00
parent a7d2a95f02
commit cc0a3e639d
1 changed files with 82 additions and 42 deletions

View File

@ -1,31 +1,46 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
enum SlideDirection { up, down }
class AudioPanel extends StatefulWidget { class AudioPanel extends StatefulWidget {
final Widget miniPanel; final Widget miniPanel;
final Widget expandedPanel; final Widget expandedPanel;
AudioPanel({this.miniPanel, this.expandedPanel, Key key}) : super(key: key); final double minHeight;
final double maxHeight;
AudioPanel(
{@required this.miniPanel,
@required this.expandedPanel,
this.minHeight = 60,
this.maxHeight = 300,
Key key})
: super(key: key);
@override @override
_AudioPanelState createState() => _AudioPanelState(); _AudioPanelState createState() => _AudioPanelState();
} }
class _AudioPanelState extends State<AudioPanel> class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
with SingleTickerProviderStateMixin {
double initSize; double initSize;
final double minSize = 60;
final double maxSize = 300;
double _startdy; double _startdy;
double _move = 0; double _move = 0;
AnimationController _controller; AnimationController _controller;
AnimationController _slowController;
Animation _animation; Animation _animation;
SlideDirection _slideDirection;
@override @override
void initState() { void initState() {
initSize = minSize; initSize = widget.minHeight;
_slideDirection = SlideDirection.up;
_controller = _controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 50)) AnimationController(vsync: this, duration: Duration(milliseconds: 50))
..addListener(() { ..addListener(() {
setState(() {}); setState(() {});
}); });
_slowController =
AnimationController(vsync: this, duration: Duration(milliseconds: 200))
..addListener(() {
setState(() {});
});
_animation = _animation =
Tween<double>(begin: initSize, end: initSize).animate(_controller); Tween<double>(begin: initSize, end: initSize).animate(_controller);
super.initState(); super.initState();
@ -34,6 +49,7 @@ class _AudioPanelState extends State<AudioPanel>
@override @override
void dispose() { void dispose() {
_controller.dispose(); _controller.dispose();
_slowController.dispose();
super.dispose(); super.dispose();
} }
@ -41,7 +57,7 @@ class _AudioPanelState extends State<AudioPanel>
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack(children: <Widget>[ return Stack(children: <Widget>[
Container( Container(
child: (_animation.value > minSize + 30) child: (_animation.value > widget.minHeight + 30)
? Positioned.fill( ? Positioned.fill(
child: GestureDetector( child: GestureDetector(
onTap: () => _backToMini(), onTap: () => _backToMini(),
@ -61,15 +77,17 @@ class _AudioPanelState extends State<AudioPanel>
onVerticalDragUpdate: (event) => _update(event), onVerticalDragUpdate: (event) => _update(event),
onVerticalDragEnd: (event) => _end(), onVerticalDragEnd: (event) => _end(),
child: Container( child: Container(
height: (_animation.value >= maxSize) height: (_animation.value >= widget.maxHeight)
? maxSize ? widget.maxHeight
: (_animation.value <= minSize) ? minSize : _animation.value, : (_animation.value <= widget.minHeight)
child: _animation.value < minSize + 30 ? widget.minHeight
: _animation.value,
child: _animation.value < widget.minHeight + 30
? Container( ? Container(
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
child: Opacity( child: Opacity(
opacity: _animation.value > minSize opacity: _animation.value > widget.minHeight
? (minSize + 30 - _animation.value) / 40 ? (widget.minHeight + 30 - _animation.value) / 40
: 1, : 1,
child: Container( child: Container(
child: widget.miniPanel, child: widget.miniPanel,
@ -91,13 +109,14 @@ class _AudioPanelState extends State<AudioPanel>
], ],
), ),
child: SingleChildScrollView( child: SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Opacity( child: Opacity(
opacity: _animation.value < (maxSize - 50) opacity: _animation.value < (widget.maxHeight - 50)
? (_animation.value - minSize) / ? (_animation.value - widget.minHeight) /
(maxSize - minSize - 50) (widget.maxHeight - widget.minHeight - 50)
: 1, : 1,
child: Container( child: Container(
height: maxSize, height: widget.maxHeight,
child: widget.expandedPanel, child: widget.expandedPanel,
), ),
), ),
@ -111,11 +130,11 @@ class _AudioPanelState extends State<AudioPanel>
_backToMini() { _backToMini() {
setState(() { setState(() {
_animation = _animation = Tween<double>(begin: initSize, end: widget.minHeight)
Tween<double>(begin: initSize, end: minSize).animate(_controller); .animate(_slowController);
initSize = minSize; initSize = widget.minHeight;
}); });
_controller.forward(); _slowController.forward();
} }
_start(DragStartDetails event) { _start(DragStartDetails event) {
@ -132,35 +151,56 @@ class _AudioPanelState extends State<AudioPanel>
_move = _startdy - event.localPosition.dy; _move = _startdy - event.localPosition.dy;
_animation = Tween<double>(begin: initSize, end: initSize + _move) _animation = Tween<double>(begin: initSize, end: initSize + _move)
.animate(_controller); .animate(_controller);
_slideDirection = _move > 0 ? SlideDirection.up : SlideDirection.down;
}); });
_controller.forward(); _controller.forward();
} }
_end() { _end() {
if (_animation.value >= (maxSize + minSize) / 4 && if (_slideDirection == SlideDirection.up) {
_animation.value < maxSize || if (_move > 20) {
(_move - _startdy > 20)) { setState(() {
_animation =
Tween<double>(begin: _animation.value, end: widget.maxHeight)
.animate(_slowController);
initSize = widget.maxHeight;
});
_slowController.forward();
} else {
setState(() {
_animation =
Tween<double>(begin: _animation.value, end: widget.minHeight)
.animate(_controller);
initSize = widget.minHeight;
});
_controller.forward();
}
} else if (_slideDirection == SlideDirection.down) {
if (_move > -50) {
setState(() {
_animation =
Tween<double>(begin: _animation.value, end: widget.maxHeight)
.animate(_slowController);
initSize = widget.maxHeight;
});
_slowController.forward();
} else {
setState(() {
_animation =
Tween<double>(begin: _animation.value, end: widget.minHeight)
.animate(_controller);
initSize = widget.minHeight;
});
_controller.forward();
}
}
if (_animation.value >= widget.maxHeight) {
setState(() { setState(() {
_animation = Tween<double>(begin: _animation.value, end: maxSize) initSize = widget.maxHeight;
.animate(_controller);
initSize = maxSize;
}); });
_controller.forward(); } else if (_animation.value < widget.minHeight) {
} else if (_animation.value < (maxSize + minSize) / 4 &&
_animation.value > minSize) {
setState(() { setState(() {
_animation = Tween<double>(begin: _animation.value, end: minSize) initSize = widget.minHeight;
.animate(_controller);
initSize = minSize;
});
_controller.forward();
} else if (_animation.value >= maxSize) {
setState(() {
initSize = maxSize;
});
} else if (_animation.value < minSize) {
setState(() {
initSize = minSize;
}); });
} }
} }