diff --git a/CHANGELOG.md b/CHANGELOG.md index d9b34e0..7a1a8bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ -#ChangeLog - +# ChangeLog + +## 1.5.0-dev.1 +* Making Pages of Type Widget [724dc31b687319f66db362b55e2b7c6c2cabbcd7](https://github.com/iamSahdeep/liquid_swipe_flutter/commit/724dc31b687319f66db362b55e2b7c6c2cabbcd7) +* LiquidController & jump to page + [ed3328ae734b2528f1e02a20b134f7bbcca274ef](https://github.com/iamSahdeep/liquid_swipe_flutter/commit/ed3328ae734b2528f1e02a20b134f7bbcca274ef) +* Animating the Page with Controller + [354825e952186bc84117cba403a33e096fbdf331](https://github.com/iamSahdeep/liquid_swipe_flutter/commit/354825e952186bc84117cba403a33e096fbdf331) +* Get Current Page from Controller [9d9f585ebf6899354ba10eadd88daa35d232f9cf](https://github.com/iamSahdeep/liquid_swipe_flutter/commit/9d9f585ebf6899354ba10eadd88daa35d232f9cf) +* Add support for vertically scrollable childs + [df22e79e525e6b4fb9fdd95e3a61e6c4c394ac25](https://github.com/iamSahdeep/liquid_swipe_flutter/commit/df22e79e525e6b4fb9fdd95e3a61e6c4c394ac25) +* Additional Callback for sliding percentage + [6d5da5d7f52815199bd5263047c252494ed1675f](https://github.com/iamSahdeep/liquid_swipe_flutter/commit/6d5da5d7f52815199bd5263047c252494ed1675f) ## 1.4.3 * Might Fix : https://github.com/iamSahdeep/liquid_swipe_flutter/issues/32 diff --git a/README.md b/README.md index d4e9a67..c124594 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Download sample apk as shown in example from releases. * Add this to your pubspec.yaml ``` dependencies: - liquid_swipe: ^1.4.3 + liquid_swipe: ^1.5.0-dev.1 ``` * Get the package from Pub: @@ -53,7 +53,7 @@ Download sample apk as shown in example from releases. ## Usage - - *`Liquid Swipe`* just requires the list of [`containers`](https://api.flutter.dev/flutter/widgets/Container-class.html). Just to provide flexibity to the developer to design its own view through it. + - *`Liquid Swipe`* just requires the list of [`Widgets like Container`](https://api.flutter.dev/flutter/widgets/Container-class.html). Just to provide flexibity to the developer to design its own view through it. ``` final pages = [ Container(...), @@ -92,12 +92,22 @@ Download sample apk as shown in example from releases. | waveType |`WaveType` | Select the type of reveal you want. | WaveType.liquidReveal | You can use circularReveal, more coming soon. Import Helpers.dart file if Autoimport doesn't work. | | onPageChangeCallback |`CallBack` | Pass your method as a callback, it will return a pageNo. | None | see Example | | currentUpdateTypeCallback |`CallBack` | same Callback but returns an UpdateType | None | see Example | +| slidePercentCallback |`CallBack` | returns SlidePercent both horizontal & vertical | None | see Example | +### Additional + +From v1.5.0-dev.1 we can use LiquidController class to create its instance and use it from controlling pages programmatically. +Features/Methods added but will not be limited to : + - jumpToPage({int page}) : It will jump to the mentioned page but without animation or swipe. + - animateToPage({int page, int duration = 600}) : It will animate to the mentioned page in given time with animation of swipes. + - currentPage : This getter will return the current Page which is being displayed. + +Please look at the Example in this project for detailed usage. # Contributors -Thanks to all these wonderful people and everyone that created issues. +Thanks to all these wonderful people and everyone that created issues or contributed in any way possible. ([emoji key](https://allcontributors.org/docs/en/emoji-key)): diff --git a/example/lib/main.dart b/example/lib/main.dart index 7f75e73..aa98ff7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -22,9 +22,15 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { int page = 0; - + LiquidController liquidController; UpdateType updateType; + @override + void initState() { + liquidController = LiquidController(); + super.initState(); + } + final pages = [ Container( color: Colors.pink, @@ -225,12 +231,12 @@ class _MyAppState extends State { LiquidSwipe( pages: pages, fullTransitionValue: 200, - enableSlideIcon: true, + enableSlideIcon: false, enableLoop: true, - positionSlideIcon: 0.5, onPageChangeCallback: pageChangeCallback, - currentUpdateTypeCallback: updateTypeCallback, waveType: WaveType.liquidReveal, + liquidController: liquidController, + slidePercentCallback: slidePercentCallback, ), Padding( padding: EdgeInsets.all(20), @@ -239,11 +245,39 @@ class _MyAppState extends State { Expanded(child: SizedBox()), Row( mainAxisAlignment: MainAxisAlignment.center, - children: List.generate(5, _buildDot), + children: List.generate(pages.length, _buildDot), ), ], ), ), + Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.all(25.0), + child: FlatButton( + onPressed: () { + liquidController.animateToPage( + page: pages.length - 1, duration: 500); + }, + child: Text("Skip to End"), + color: Colors.white.withOpacity(0.1), + ), + ), + ), + Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.all(25.0), + child: FlatButton( + onPressed: () { + liquidController.jumpToPage( + page: liquidController.currentPage + 1); + }, + child: Text("Next"), + color: Colors.white.withOpacity(0.1), + ), + ), + ) ], ), ), @@ -251,13 +285,13 @@ class _MyAppState extends State { } pageChangeCallback(int lpage) { - print(lpage); + print(liquidController.currentPage); setState(() { page = lpage; }); } - updateTypeCallback(UpdateType updateType) { - print(updateType); + slidePercentCallback(double hor, double ver) { + print(hor.toInt().toString() + " " + ver.toString()); } } diff --git a/example/pubspec.lock b/example/pubspec.lock index e94ba65..dae8e8e 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -87,7 +87,7 @@ packages: path: ".." relative: true source: path - version: "1.4.3" + version: "1.5.0-dev.1" matcher: dependency: transitive description: diff --git a/lib/PageHelpers/LiquidController.dart b/lib/PageHelpers/LiquidController.dart new file mode 100644 index 0000000..18428b0 --- /dev/null +++ b/lib/PageHelpers/LiquidController.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:liquid_swipe/Provider/iamariderprovider.dart'; +import 'package:provider/provider.dart'; + +class LiquidController { + BuildContext context; + + LiquidController(); + + setContext(BuildContext c) { + context = c; + } + + jumpToPage({int page}) { + Provider.of(context, listen: false).jumpToPage(page); + } + + animateToPage({int page, int duration = 600}) { + Provider.of(context, listen: false) + .animateToPage(page, duration); + } + + int get currentPage => + Provider + .of(context, listen: false) + .activePageIndex; +} diff --git a/lib/PageHelpers/page_dragger.dart b/lib/PageHelpers/page_dragger.dart index bb688a9..16f6a15 100644 --- a/lib/PageHelpers/page_dragger.dart +++ b/lib/PageHelpers/page_dragger.dart @@ -60,7 +60,6 @@ class _PageDraggerState extends State { slidePercentVer = (dy / 500).abs().clamp(0.0, 1.25); } - // Adding to slideUpdateStream Provider.of(context, listen: false) .updateSlide(SlideUpdate( slideDirection, @@ -73,7 +72,6 @@ class _PageDraggerState extends State { // This method executes when user ends dragging. onDragEnd(DragEndDetails details) { - // Adding to slideUpdateStream Provider.of(context, listen: false) .updateSlide(SlideUpdate( SlideDirection.none, @@ -91,33 +89,35 @@ class _PageDraggerState extends State { @override Widget build(BuildContext context) { //Gesture Detector for horizontal drag + final model = Provider.of(context, listen: false); + return GestureDetector( behavior: HitTestBehavior.translucent, - onHorizontalDragStart: onDragStart, - onHorizontalDragUpdate: onDragUpdate, - onHorizontalDragEnd: onDragEnd, - onVerticalDragStart: onDragStart, - onVerticalDragEnd: onDragEnd, - onVerticalDragUpdate: onDragUpdate, + onHorizontalDragStart: model.isInProgress ? null : onDragStart, + onHorizontalDragUpdate: model.isInProgress ? null : onDragUpdate, + onHorizontalDragEnd: model.isInProgress ? null : onDragEnd, + //onVerticalDragStart: model.isInProgress ? null : onDragStart, + // onVerticalDragEnd: model.isInProgress ? null : onDragEnd, + // onVerticalDragUpdate: model.isInProgress ? null : onDragUpdate, child: widget.enableSlideIcon ? Align( - alignment: Alignment( - 1 - slidePercentHor + 0.005, - widget.iconPosition + widget.iconPosition / 10, - ), - child: Opacity( - opacity: 1 - slidePercentHor, - child: FloatingActionButton( - onPressed: null, - backgroundColor: Colors.transparent, - elevation: 0.0, - child: slideDirection != SlideDirection.leftToRight - ? widget.slideIconWidget - : null, - foregroundColor: Colors.black, - ), - ), - ) + alignment: Alignment( + 1 - slidePercentHor + 0.005, + widget.iconPosition + widget.iconPosition / 10, + ), + child: Opacity( + opacity: 1 - slidePercentHor, + child: FloatingActionButton( + onPressed: null, + backgroundColor: Colors.transparent, + elevation: 0.0, + child: slideDirection != SlideDirection.leftToRight + ? widget.slideIconWidget + : null, + foregroundColor: Colors.black, + ), + ), + ) : null, ); } diff --git a/lib/Provider/iamariderprovider.dart b/lib/Provider/iamariderprovider.dart index e0bb396..1415a13 100644 --- a/lib/Provider/iamariderprovider.dart +++ b/lib/Provider/iamariderprovider.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/cupertino.dart'; import 'package:liquid_swipe/Helpers/Helpers.dart'; import 'package:liquid_swipe/Helpers/slide_update.dart'; @@ -6,9 +8,7 @@ import 'package:liquid_swipe/liquid_swipe.dart'; class IAmARiderProvider extends ChangeNotifier { SlideUpdate slideUpdate; - AnimatedPageDragger - animatedPageDragger; //When user stops dragging then by using this page automatically drags. - + AnimatedPageDragger animatedPageDragger; int activePageIndex = 0; //active page index int nextPageIndex = 0; //next page index SlideDirection slideDirection = SlideDirection.none; //slide direction @@ -20,16 +20,18 @@ class IAmARiderProvider extends ChangeNotifier { double positionSlideIcon; OnPageChangeCallback _onPageChangeCallback; CurrentUpdateTypeCallback _currentUpdateTypeCallback; + SlidePercentCallback _slidePercentCallback; + bool isInProgress = false; - IAmARiderProvider( - int initialPage, + IAmARiderProvider(int initialPage, bool loop, int length, TickerProviderStateMixin mixin, double slideIcon, OnPageChangeCallback onPageChangeCallback, - CurrentUpdateTypeCallback currentUpdateTypeCallback) { - slidePercentHor = slidePercentVer = 0; + CurrentUpdateTypeCallback currentUpdateTypeCallback, + SlidePercentCallback slidePercentCallback) { + slidePercentHor = slidePercentVer = 0.5; activePageIndex = initialPage; nextPageIndex = initialPage; enableLoop = loop; @@ -38,6 +40,102 @@ class IAmARiderProvider extends ChangeNotifier { positionSlideIcon = slideIcon; _currentUpdateTypeCallback = currentUpdateTypeCallback; _onPageChangeCallback = onPageChangeCallback; + _slidePercentCallback = slidePercentCallback; + } + + /// Animating page to the mentioned page + /// Known Issue : First we have to jump to the previous screen + /// Not using for now + animateDirectlyToPage(int page, int duration) { + if (isInProgress || activePageIndex == page) return; + isInProgress = true; + activePageIndex = page - 1; + nextPageIndex = page; + if (activePageIndex < 0) { + activePageIndex = 0; + jumpToPage(page); + return; + } + new Timer.periodic(const Duration(milliseconds: 1), (t) { + if (t.tick < duration / 2) { + updateSlide(SlideUpdate(SlideDirection.rightToLeft, t.tick / duration, + 1, UpdateType.dragging)); + } else if (t.tick < duration) { + updateSlide(SlideUpdate(SlideDirection.rightToLeft, t.tick / duration, + 1, UpdateType.animating)); + } else { + updateSlide(SlideUpdate( + SlideDirection.rightToLeft, 1, 1, UpdateType.doneAnimating)); + t.cancel(); + isInProgress = false; + } + }); + } + + animateToPage(int page, int duration) { + if (isInProgress || activePageIndex == page) return; + isInProgress = true; + int diff = 0; + if (activePageIndex < page) { + diff = page - activePageIndex; + int newDuration = duration ~/ diff; + new Timer.periodic(Duration(milliseconds: newDuration), (callback) { + new Timer.periodic(const Duration(milliseconds: 1), (t) { + if (t.tick < newDuration / 2) { + updateSlide(SlideUpdate(SlideDirection.rightToLeft, + t.tick / newDuration, 1, UpdateType.dragging)); + } else if (t.tick < newDuration) { + updateSlide(SlideUpdate(SlideDirection.rightToLeft, + t.tick / newDuration, 1, UpdateType.animating)); + } else { + updateSlide(SlideUpdate( + SlideDirection.rightToLeft, 1, 1, UpdateType.doneAnimating)); + t.cancel(); + } + }); + if (callback.tick >= diff) { + callback.cancel(); + isInProgress = false; + } + }); + } else { + diff = activePageIndex - page; + int newDuration = duration ~/ diff; + new Timer.periodic(Duration(milliseconds: newDuration), (callback) { + new Timer.periodic(const Duration(milliseconds: 1), (t) { + if (t.tick < newDuration / 2) { + updateSlide(SlideUpdate(SlideDirection.leftToRight, + t.tick / newDuration, 1, UpdateType.dragging)); + } else if (t.tick < newDuration) { + updateSlide(SlideUpdate(SlideDirection.leftToRight, + t.tick / newDuration, 1, UpdateType.animating)); + } else { + updateSlide(SlideUpdate( + SlideDirection.leftToRight, 1, 1, UpdateType.doneAnimating)); + t.cancel(); + } + }); + if (callback.tick >= diff) { + callback.cancel(); + isInProgress = false; + } + }); + } + } + + ///If no animation is required. + jumpToPage(int page) { + if (page == activePageIndex || isInProgress) return; + if (activePageIndex == pagesLength - 1 && !enableLoop) { + return; + } + isInProgress = true; + activePageIndex = page - 1; + nextPageIndex = page; + if (nextPageIndex >= pagesLength) nextPageIndex = 0; + updateSlide(SlideUpdate( + SlideDirection.rightToLeft, 1, 0.5, UpdateType.doneAnimating)); + isInProgress = false; } updateSlide(SlideUpdate slidUpdate) { @@ -50,6 +148,14 @@ class IAmARiderProvider extends ChangeNotifier { if (prevUpdate != event.updateType && _currentUpdateTypeCallback != null) _currentUpdateTypeCallback(event.updateType); + if (_slidePercentCallback != null && + event.updateType != UpdateType.doneAnimating) { + String hor = (event.slidePercentHor * 100).toStringAsExponential(2); + String ver = (event.slidePercentVer * 100).toStringAsExponential(2); + _slidePercentCallback( + double.parse(hor), (((double.parse(ver)) * 100) / 125)); + } + prevUpdate = event.updateType; //if the user is dragging then @@ -128,7 +234,7 @@ class IAmARiderProvider extends ChangeNotifier { _onPageChangeCallback(activePageIndex); } slideDirection = SlideDirection.none; - slidePercentHor = 0.5; + slidePercentHor = 0.0; slidePercentVer = positionSlideIcon; return; } diff --git a/lib/liquid_swipe.dart b/lib/liquid_swipe.dart index e02a357..df468f0 100644 --- a/lib/liquid_swipe.dart +++ b/lib/liquid_swipe.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:liquid_swipe/Helpers/Helpers.dart'; +import 'package:liquid_swipe/PageHelpers/LiquidController.dart'; import 'package:liquid_swipe/PageHelpers/page.dart'; import 'package:liquid_swipe/PageHelpers/page_dragger.dart'; import 'package:liquid_swipe/PageHelpers/page_reveal.dart'; @@ -8,11 +9,14 @@ import 'package:liquid_swipe/Provider/iamariderprovider.dart'; import 'package:provider/provider.dart'; export 'package:liquid_swipe/Helpers/Helpers.dart'; +export 'package:liquid_swipe/PageHelpers/LiquidController.dart'; final key = new GlobalKey<_LiquidSwipe>(); typedef OnPageChangeCallback = void Function(int activePageIndex); typedef CurrentUpdateTypeCallback = void Function(UpdateType updateType); +typedef SlidePercentCallback = void Function( + double slidePercentHorizontal, double slidePercetnVertical); class LiquidSwipe extends StatefulWidget { final List pages; @@ -22,12 +26,13 @@ class LiquidSwipe extends StatefulWidget { final Widget slideIconWidget; final double positionSlideIcon; final bool enableLoop; + final LiquidController liquidController; final WaveType waveType; final OnPageChangeCallback onPageChangeCallback; final CurrentUpdateTypeCallback currentUpdateTypeCallback; + final SlidePercentCallback slidePercentCallback; - const LiquidSwipe({ - Key key, + const LiquidSwipe({Key key, @required this.pages, this.fullTransitionValue = FULL_TARNSITION_PX, this.initialPage = 0, @@ -35,10 +40,12 @@ class LiquidSwipe extends StatefulWidget { this.slideIconWidget = const Icon(Icons.arrow_back_ios), this.positionSlideIcon = 0.54, this.enableLoop = true, + this.liquidController, this.waveType = WaveType.liquidReveal, this.onPageChangeCallback, this.currentUpdateTypeCallback, - }) : assert(pages != null), + this.slidePercentCallback}) + : assert(pages != null), assert(fullTransitionValue != null), assert(initialPage != null && initialPage >= 0 && @@ -51,14 +58,17 @@ class LiquidSwipe extends StatefulWidget { } class _LiquidSwipe extends State with TickerProviderStateMixin { + LiquidController liquidController; + @override void initState() { + liquidController = widget.liquidController ?? LiquidController(); super.initState(); } @override Widget build(BuildContext context) { - List pages = widget.pages; + List pages = widget.pages; return ChangeNotifierProvider( create: (BuildContext context) { return IAmARiderProvider( @@ -68,41 +78,43 @@ class _LiquidSwipe extends State with TickerProviderStateMixin { this, widget.positionSlideIcon, widget.onPageChangeCallback, - widget.currentUpdateTypeCallback); + widget.currentUpdateTypeCallback, + widget.slidePercentCallback); }, - child: Consumer( - builder: (BuildContext context, IAmARiderProvider model, _) => - Stack( - children: [ - CustomPage( - pageView: model.slideDirection == SlideDirection.leftToRight - ? pages[model.activePageIndex] - : pages[model.nextPageIndex], - ), - //Pages - PageReveal( - //next page reveal - revealPercent: model.slidePercentHor, - child: CustomPage( - pageView: model.slideDirection == SlideDirection.leftToRight - ? pages[model.nextPageIndex] - : pages[model.activePageIndex], - ), - slideDirection: model.slideDirection, - iconPosition: widget.positionSlideIcon, - waveType: widget.waveType, - vertReveal: model.slidePercentVer, - ), - PageDragger( - //Used for gesture control - fullTransitionPX: widget.fullTransitionValue, - enableSlideIcon: widget.enableSlideIcon, - slideIconWidget: widget.slideIconWidget, - iconPosition: widget.positionSlideIcon, - ), //PageDragger - ], //Widget//Stack + child: + Consumer(builder: (BuildContext context, IAmARiderProvider model, _) { + liquidController.setContext(context); + return Stack( + children: [ + CustomPage( + pageView: model.slideDirection == SlideDirection.leftToRight + ? pages[model.activePageIndex] + : pages[model.nextPageIndex], + ), + //Pages + PageReveal( + //next page reveal + revealPercent: model.slidePercentHor, + child: CustomPage( + pageView: model.slideDirection == SlideDirection.leftToRight + ? pages[model.nextPageIndex] + : pages[model.activePageIndex], + ), + slideDirection: model.slideDirection, + iconPosition: widget.positionSlideIcon, + waveType: widget.waveType, + vertReveal: model.slidePercentVer, ), - ), + PageDragger( + //Used for gesture control + fullTransitionPX: widget.fullTransitionValue, + enableSlideIcon: widget.enableSlideIcon, + slideIconWidget: widget.slideIconWidget, + iconPosition: widget.positionSlideIcon, + ), //PageDragger + ], //Widget//Stack + ); + }), ); //Scaffold } } diff --git a/pubspec.yaml b/pubspec.yaml index 25b6f88..a741e8f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: liquid_swipe description: A Flutter plugin to implement liquid Swipe effect to provided containers. -version: 1.4.3 +version: 1.5.0-dev.1 homepage: https://github.com/iamSahdeep/liquid_swipe_flutter environment: