From af4701484822771e3aa96a6eaa0a9763ab80eb3e Mon Sep 17 00:00:00 2001 From: peterscodee <8vsxdxd@gmail.com> Date: Mon, 3 Aug 2020 10:43:54 +0200 Subject: [PATCH] Version 0.3.0: +ValueListenableBuilder +valueNotifier property --- CHANGELOG.md | 6 ++ lib/miniplayer.dart | 149 +++++++++++++++++++++++--------------------- pubspec.yaml | 2 +- 3 files changed, 84 insertions(+), 73 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cabaf9..b9692a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [0.3.0] + +* Migrated from StreamBuilder to ValueListenableBuilder +* 40% improvement in response time (previous 19.2ms, now 11.5ms) +* Added valueNotifier property + ## [0.2.0] * Added backgroundColor property diff --git a/lib/miniplayer.dart b/lib/miniplayer.dart index 9450508..146744a 100644 --- a/lib/miniplayer.dart +++ b/lib/miniplayer.dart @@ -13,6 +13,7 @@ class Miniplayer extends StatefulWidget { final Curve curve; final double elevation; final Color backgroundColor; + final ValueNotifier valueNotifier; const Miniplayer({ Key key, @@ -22,6 +23,7 @@ class Miniplayer extends StatefulWidget { this.curve = Curves.easeInQuart, this.elevation = 0, this.backgroundColor = const Color(0x70000000), + this.valueNotifier, }) : super(key: key); @override @@ -29,6 +31,8 @@ class Miniplayer extends StatefulWidget { } class _MiniplayerState extends State with TickerProviderStateMixin { + ValueNotifier heightNotifier; + double _height; double _prevHeight; @@ -43,6 +47,11 @@ class _MiniplayerState extends State with TickerProviderStateMixin { @override void initState() { + if (widget.valueNotifier == null) + heightNotifier = ValueNotifier(widget.minHeight); + else + heightNotifier = widget.valueNotifier; + _animationController = AnimationController( vsync: this, duration: Duration( @@ -53,7 +62,7 @@ class _MiniplayerState extends State with TickerProviderStateMixin { _animationController.addStatusListener((status) { if (status == AnimationStatus.completed) { _animationController.reset(); - _heightController.add(_endHeight); + heightNotifier.value = _endHeight; _height = _endHeight; } }); @@ -71,80 +80,76 @@ class _MiniplayerState extends State with TickerProviderStateMixin { @override Widget build(BuildContext context) { - return StreamBuilder( - initialData: widget.minHeight, - stream: _heightController.stream, - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - var _percentage = ((snapshot.data - widget.minHeight)) / - (widget.maxHeight - widget.minHeight); + return ValueListenableBuilder( + builder: (BuildContext context, double value, Widget child) { + var _percentage = ((value - widget.minHeight)) / + (widget.maxHeight - widget.minHeight); - return Stack( - alignment: Alignment.bottomCenter, - children: [ - if (_percentage > 0) - GestureDetector( - onTap: () => animateToHeight(widget.minHeight), - child: Opacity( - opacity: _percentage, - child: Container(color: widget.backgroundColor), - ), - ), - Align( - alignment: Alignment.bottomCenter, - child: SizedBox( - height: snapshot.data, - child: GestureDetector( - child: Material( - elevation: widget.elevation, - child: Container( - constraints: BoxConstraints.expand(), - child: widget.builder(snapshot.data, _percentage), - ), - ), - onTap: () { - bool up = _height != widget.maxHeight; - animateToHeight(up ? widget.maxHeight : widget.minHeight); - }, - onPanEnd: (details) async { - if (_up) - animateToHeight(widget.maxHeight); - else - animateToHeight(widget.minHeight); - }, - onPanUpdate: (details) { - _prevHeight = _height; - - //details.delta.dy < 0 -> -- = + - var h = _height -= details.delta.dy; - - //Makes sure that height !> maxHeight && !< minHeight - if (h > widget.maxHeight) h = widget.maxHeight; - if (h < widget.minHeight) h = widget.minHeight; - - //Makes sure that the widget wont rebuild unnecessarily - if (_prevHeight == h && - (h == widget.minHeight || h == widget.maxHeight)) - return; - - _height = h; - if (_height == widget.maxHeight) - _up = true; - else if (_height == widget.minHeight) - _up = false; - else - _up = _prevHeight < _height; - - _heightController.add(h); - }, - ), + return Stack( + alignment: Alignment.bottomCenter, + children: [ + if (_percentage > 0) + GestureDetector( + onTap: () => animateToHeight(widget.minHeight), + child: Opacity( + opacity: _percentage, + child: Container(color: widget.backgroundColor), ), ), - ], - ); - } else - return Container(); + Align( + alignment: Alignment.bottomCenter, + child: SizedBox( + height: value, + child: GestureDetector( + child: Material( + elevation: widget.elevation, + child: Container( + constraints: BoxConstraints.expand(), + child: widget.builder(value, _percentage), + ), + ), + onTap: () { + bool up = _height != widget.maxHeight; + animateToHeight(up ? widget.maxHeight : widget.minHeight); + }, + onPanEnd: (details) async { + if (_up) + animateToHeight(widget.maxHeight); + else + animateToHeight(widget.minHeight); + }, + onPanUpdate: (details) { + _prevHeight = _height; + + //details.delta.dy < 0 -> -- = + + var h = _height -= details.delta.dy; + + //Makes sure that height !> maxHeight && !< minHeight + if (h > widget.maxHeight) h = widget.maxHeight; + if (h < widget.minHeight) h = widget.minHeight; + + //Makes sure that the widget wont rebuild unnecessarily + if (_prevHeight == h && + (h == widget.minHeight || h == widget.maxHeight)) + return; + + _height = h; + if (_height == widget.maxHeight) + _up = true; + else if (_height == widget.minHeight) + _up = false; + else + _up = _prevHeight < _height; + + heightNotifier.value = h; + }, + ), + ), + ), + ], + ); }, + valueListenable: heightNotifier, ); } @@ -159,7 +164,7 @@ class _MiniplayerState extends State with TickerProviderStateMixin { _sizeAnimation.addListener(() { if (!(_sizeAnimation.value > widget.maxHeight) && !(_sizeAnimation.value < widget.minHeight)) - _heightController.add(_sizeAnimation.value); + heightNotifier.value = _sizeAnimation.value; }); _animationController.forward(); } diff --git a/pubspec.yaml b/pubspec.yaml index 9997b44..b998204 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: miniplayer description: A lightweight flutter package providing a miniplayer widget which resizes according to drag gestures and returns a builder function with the current height and percentage progress. -version: 0.2.0 +version: 0.3.0 homepage: https://www.peterscode.dev repository: https://github.com/peterscodee/miniplayer