From 082a8b5db764cc731de728b2ca3efe226d59e52f Mon Sep 17 00:00:00 2001 From: JZoom Date: Tue, 28 Aug 2018 15:03:54 +0800 Subject: [PATCH] Fix #9 --- CHANGELOG-ZH.md | 5 +- CHANGELOG.md | 5 +- example/lib/main.dart | 14 +- example/lib/src/ExampleCustom.dart | 15 ++- .../lib/src/ExampleSwiperInScrollView.dart | 10 ++ example/pubspec.lock | 9 +- lib/src/custom_layout.dart | 65 +++++++-- lib/src/swiper.dart | 127 +++++++++++++++--- pubspec.yaml | 2 +- 9 files changed, 201 insertions(+), 51 deletions(-) diff --git a/CHANGELOG-ZH.md b/CHANGELOG-ZH.md index a255d7c..99fb8db 100644 --- a/CHANGELOG-ZH.md +++ b/CHANGELOG-ZH.md @@ -51,4 +51,7 @@ * 修复一些错别字,感谢[csharad](https://github.com/csharad) ## [1.0.5] - [2018/08/09] - * viewportFraction<1.0增加fade参数 \ No newline at end of file + * viewportFraction<1.0增加fade参数 + +## [1.0.6] - [2018/08/28] + * `TINDER` 和 `STACK` 这两种布局方式实现垂直滚动, #9 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 761b1c1..3352f9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,4 +57,7 @@ * Fix some typo,thanks to [csharad](https://github.com/csharad) ## [1.0.5] - [2018/08/09] - * Add feature : support fade for `viewportFraction` \ No newline at end of file + * Add feature : support fade for `viewportFraction` + +## [1.0.6] - [2018/08/28] + * Implement vertical scroll direction for `TINDER` and `STACK` layout, see #9 \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index 748a1ae..ddd5d9a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -18,18 +18,12 @@ class MyApp extends StatelessWidget { child: new Column( children: [ new SizedBox( - height: 200.0, + height: 300.0, child: Swiper( - layout: SwiperLayout.DEFAULT, - customLayoutOption: new CustomLayoutOption( - startIndex: -1, stateCount: 3) - .addRotate([-45.0 / 180, 0.0, 45.0 / 180]).addTranslate([ - new Offset(-370.0, -40.0), - new Offset(0.0, 0.0), - new Offset(370.0, -40.0) - ]), + layout: SwiperLayout.TINDER, itemWidth: 300.0, itemHeight: 200.0, + scrollDirection: Axis.vertical, itemBuilder: (context, index) { return new Container( color: Colors.grey, @@ -55,7 +49,7 @@ class MyApp extends StatelessWidget { primarySwatch: Colors.blue, ), home: new MyHomePage(title: 'Flutter Swiper'), - // home: buildHome() , + //home: buildHome() , routes: { '/example01': (BuildContext context) => new ExampleHorizontal(), '/example02': (BuildContext context) => new ExampleVertical(), diff --git a/example/lib/src/ExampleCustom.dart b/example/lib/src/ExampleCustom.dart index 2608a08..869a5c1 100644 --- a/example/lib/src/ExampleCustom.dart +++ b/example/lib/src/ExampleCustom.dart @@ -21,7 +21,6 @@ class _ExampleCustomState extends State { int _autoplayDely; - Axis _axis; double _padding; @@ -37,6 +36,9 @@ class _ExampleCustomState extends State { double _scale; + + Axis _scrollDirection; + Curve _curve; double _fade; @@ -84,9 +86,9 @@ class _ExampleCustomState extends State { _itemCount = 3; _autoplay = false; _autoplayDely = 3000; - _axis = Axis.horizontal; _viewportFraction = 0.8; _outer = false; + _scrollDirection = Axis.horizontal; super.initState(); } @@ -115,6 +117,7 @@ class _ExampleCustomState extends State { _currentIndex = index; }); }, + curve: _curve, scale: _scale, itemWidth: 300.0, @@ -128,7 +131,7 @@ class _ExampleCustomState extends State { autoplay: _autoplay, itemBuilder: _buildItem, itemCount: _itemCount, - scrollDirection: _axis, + scrollDirection: _scrollDirection, pagination: new SwiperPagination(), ); } @@ -178,6 +181,12 @@ class _ExampleCustomState extends State { _layout = value; setState(() {}); })), + new FormWidget( + label: "scrollDirection", + child: new Switch( + value: _scrollDirection == Axis.horizontal, + onChanged: (bool value) => setState(() => _scrollDirection = value ? Axis.horizontal : Axis.vertical)), + ), //Pannel Begin new FormWidget( label: "loop", diff --git a/example/lib/src/ExampleSwiperInScrollView.dart b/example/lib/src/ExampleSwiperInScrollView.dart index 1c6aa76..1749a98 100644 --- a/example/lib/src/ExampleSwiperInScrollView.dart +++ b/example/lib/src/ExampleSwiperInScrollView.dart @@ -23,6 +23,14 @@ class _ExampleState extends State with TickerProvider _ExampleState(); + + @override + void dispose() { + controller.dispose(); + + super.dispose(); + } + @override void initState() { controller = new AnimationController(vsync: this); @@ -34,6 +42,8 @@ class _ExampleState extends State with TickerProvider super.initState(); } + + Widget _buildDynamicCard(){ return new Card( elevation: 2.0, diff --git a/example/pubspec.lock b/example/pubspec.lock index 173bd47..1964fa8 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -82,7 +82,7 @@ packages: path: ".." relative: true source: path - version: "1.0.2" + version: "1.0.6" flutter_test: dependency: "direct dev" description: flutter @@ -214,6 +214,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.5.1" + percent_indicator: + dependency: "direct main" + description: + name: percent_indicator + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.9" plugin: dependency: transitive description: diff --git a/lib/src/custom_layout.dart b/lib/src/custom_layout.dart index 82ce619..cbf708b 100644 --- a/lib/src/custom_layout.dart +++ b/lib/src/custom_layout.dart @@ -5,7 +5,8 @@ part of 'swiper.dart'; abstract class _CustomLayoutStateBase extends State with SingleTickerProviderStateMixin { - double _screenWidth; + double _swiperWidth; + double _swiperHeight; Animation _animation; AnimationController _animationController; int _startIndex; @@ -23,6 +24,8 @@ abstract class _CustomLayoutStateBase extends State super.initState(); } + + void _createAnimationController() { _animationController = new AnimationController(vsync: this, value: 0.5); Tween tween = new Tween(begin: 0.0, end: 1.0); @@ -31,10 +34,30 @@ abstract class _CustomLayoutStateBase extends State @override void didChangeDependencies() { - _screenWidth = MediaQuery.of(context).size.width; + + + WidgetsBinding.instance + .addPostFrameCallback(_getSize); super.didChangeDependencies(); } + void _getSize(_){ + afterRender(); + } + + @mustCallSuper + void afterRender(){ + + RenderObject renderObject = context.findRenderObject(); + Size size = renderObject.paintBounds.size; + _swiperWidth = size.width; + _swiperHeight = size.height; + setState(() { + + + }); + } + @override void didUpdateWidget(T oldWidget) { if (widget.controller != oldWidget.controller) { @@ -75,6 +98,7 @@ abstract class _CustomLayoutStateBase extends State } Widget _buildAnimation(BuildContext context, Widget w) { + List list = []; double animationValue = _animation.value; @@ -94,14 +118,19 @@ abstract class _CustomLayoutStateBase extends State onPanStart: _onPanStart, onPanEnd: _onPanEnd, onPanUpdate: _onPanUpdate, - child: new Center( - child: _buildContainer(list), + child: new ClipRect( + child: new Center( + child: _buildContainer(list), + ), ), ); } @override Widget build(BuildContext context) { + if(_animationCount==null){ + return new Container(); + } return new AnimatedBuilder( animation: _animationController, builder: _buildAnimation); } @@ -176,14 +205,18 @@ abstract class _CustomLayoutStateBase extends State void _onPanEnd(DragEndDetails details) { if (_lockScroll) return; + + double velocity = widget.scrollDirection == Axis.horizontal? + details.velocity.pixelsPerSecond.dx :details.velocity.pixelsPerSecond.dy; + if (_animationController.value >= 0.75 || - details.velocity.pixelsPerSecond.dx > 500.0) { + velocity > 500.0) { if (_currentIndex <= 0 && !widget.loop) { return; } _move(1.0, nextIndex: _currentIndex - 1); } else if (_animationController.value < 0.25 || - details.velocity.pixelsPerSecond.dx < -500.0) { + velocity < -500.0) { if (_currentIndex >= widget.itemCount - 1 && !widget.loop) { return; } @@ -193,10 +226,19 @@ abstract class _CustomLayoutStateBase extends State } } + void _onPanStart(DragStartDetails details) { + if (_lockScroll) return; + _currentValue = _animationController.value ; + _currentPos =widget.scrollDirection == Axis.horizontal ? + details.globalPosition.dx : details.globalPosition.dy; + } + + void _onPanUpdate(DragUpdateDetails details) { if (_lockScroll) return; double value = _currentValue + - (details.globalPosition.dx - _currentPos) / _screenWidth / 2; + ((widget.scrollDirection == Axis.horizontal ? + details.globalPosition.dx : details.globalPosition.dy) - _currentPos) / _swiperWidth / 2; // no loop ? if (!widget.loop) { if (_currentIndex >= widget.itemCount - 1) { @@ -213,11 +255,6 @@ abstract class _CustomLayoutStateBase extends State _animationController.value = value; } - void _onPanStart(DragStartDetails details) { - if (_lockScroll) return; - _currentValue = _animationController.value; - _currentPos = details.globalPosition.dx; - } int _currentIndex = 0; } @@ -357,6 +394,7 @@ class _CustomLayoutSwiper extends _SubSwiper { int duration, int index, int itemCount, + Axis scrollDirection, SwiperController controller}) : assert(option != null), super( @@ -370,7 +408,8 @@ class _CustomLayoutSwiper extends _SubSwiper { duration: duration, index: index, itemCount: itemCount, - controller: controller); + controller: controller, + scrollDirection:scrollDirection); @override State createState() { diff --git a/lib/src/swiper.dart b/lib/src/swiper.dart index 22988fa..efa8176 100644 --- a/lib/src/swiper.dart +++ b/lib/src/swiper.dart @@ -24,10 +24,10 @@ class Swiper extends StatefulWidget { /// If set true , the pagination will display 'outer' of the 'content' container. final bool outer; - /// Inner item height, this property is valid if layout=STACK, + /// Inner item height, this property is valid if layout=STACK or layout=TINDER or LAYOUT=CUSTOM, final double itemHeight; - /// Inner item width, this property is valid if layout=STACK, + /// Inner item width, this property is valid if layout=STACK or layout=TINDER or LAYOUT=CUSTOM, final double itemWidth; // height of the inside container,this property is valid when outer=true,otherwise the inside container size is controlled by parent widget @@ -362,6 +362,7 @@ abstract class _SwiperTimerMixin extends State { class _SwiperState extends _SwiperTimerMixin { int _activeIndex; + Widget _wrapTap(BuildContext context, int index) { return new GestureDetector( behavior: HitTestBehavior.opaque, @@ -376,6 +377,7 @@ class _SwiperState extends _SwiperTimerMixin { void initState() { _activeIndex = widget.index ?? 0; + super.initState(); } @@ -421,6 +423,7 @@ class _SwiperState extends _SwiperTimerMixin { duration: widget.duration, onIndexChanged: _onIndexChanged, controller: _controller, + scrollDirection: widget.scrollDirection, ); } else if (widget.layout == null || widget.layout == SwiperLayout.DEFAULT) { if (widget.loop) { @@ -471,6 +474,7 @@ class _SwiperState extends _SwiperTimerMixin { duration: widget.duration, onIndexChanged: _onIndexChanged, controller: _controller, + scrollDirection: widget.scrollDirection, ); } else if (widget.layout == SwiperLayout.CUSTOM) { return new _CustomLayoutSwiper( @@ -485,6 +489,7 @@ class _SwiperState extends _SwiperTimerMixin { duration: widget.duration, onIndexChanged: _onIndexChanged, controller: _controller, + scrollDirection: widget.scrollDirection, ); } else { return new Container(); @@ -589,6 +594,8 @@ abstract class _SubSwiper extends StatefulWidget { final double itemWidth; final double itemHeight; final bool loop; + final Axis scrollDirection; + _SubSwiper( {Key key, this.loop, @@ -600,8 +607,9 @@ abstract class _SubSwiper extends StatefulWidget { this.controller, this.index, this.itemCount, + this.scrollDirection : Axis.horizontal, this.onIndexChanged}) - : super(key: key); + :super(key: key); @override State createState(); @@ -628,7 +636,9 @@ class _TinderSwiper extends _SubSwiper { IndexedWidgetBuilder itemBuilder, int index, bool loop, - int itemCount}) + int itemCount, + Axis scrollDirection, + }) : assert(itemWidth != null && itemHeight != null), super( loop: loop, @@ -641,7 +651,8 @@ class _TinderSwiper extends _SubSwiper { controller: controller, index: index, onIndexChanged: onIndexChanged, - itemCount: itemCount); + itemCount: itemCount, + scrollDirection:scrollDirection); @override State createState() { @@ -661,7 +672,9 @@ class _StackSwiper extends _SubSwiper { IndexedWidgetBuilder itemBuilder, int index, bool loop, - int itemCount}) + int itemCount, + Axis scrollDirection, + }) : super( loop: loop, key: key, @@ -673,7 +686,8 @@ class _StackSwiper extends _SubSwiper { controller: controller, index: index, onIndexChanged: onIndexChanged, - itemCount: itemCount); + itemCount: itemCount, + scrollDirection:scrollDirection); @override State createState() { @@ -779,22 +793,60 @@ class _TinderState extends _CustomLayoutStateBase<_TinderSwiper> { @override void didChangeDependencies() { super.didChangeDependencies(); + + } + + @override + void didUpdateWidget(_TinderSwiper oldWidget) { + _updateValues(); + super.didUpdateWidget(oldWidget); + } + + @override + void afterRender() { + super.afterRender(); + _startIndex = -3; _animationCount = 5; opacity = [0.0, 0.9, 0.9, 1.0, 0.0, 0.0]; scales = [0.80, 0.80, 0.85, 0.90, 1.0, 1.0, 1.0]; - offsetsX = [0.0, 0.0, 0.0, 0.0, _screenWidth, _screenWidth]; - offsetsY = [ - 0.0, - 0.0, - -5.0, - -10.0, - -15.0, - -20.0, - ]; rotates = [0.0, 0.0, 0.0, 0.0, 20.0, 25.0]; + _updateValues(); + } + + + void _updateValues(){ + if(widget.scrollDirection == Axis.horizontal){ + offsetsX = [0.0, 0.0, 0.0, 0.0, _swiperWidth, _swiperWidth]; + offsetsY = [ + 0.0, + 0.0, + -5.0, + -10.0, + -15.0, + -20.0, + ]; + }else{ + + offsetsX = [ + 0.0, + 0.0, + 5.0, + 10.0, + 15.0, + 20.0, + ]; + + offsetsY = [0.0, 0.0, 0.0, 0.0, _swiperHeight, _swiperHeight]; + + } + } + + + + @override Widget _buildItem(int i, int realIndex, double animationValue) { double s = _getValue(scales, animationValue, i); @@ -803,6 +855,9 @@ class _TinderState extends _CustomLayoutStateBase<_TinderSwiper> { double o = _getValue(opacity, animationValue, i); double a = _getValue(rotates, animationValue, i); + Alignment alignment = widget.scrollDirection == Axis.horizontal? + Alignment.bottomCenter : Alignment.centerLeft; + return new Opacity( opacity: o, child: new Transform.rotate( @@ -812,7 +867,7 @@ class _TinderState extends _CustomLayoutStateBase<_TinderSwiper> { offset: new Offset(f, fy), child: new Transform.scale( scale: s, - alignment: Alignment.bottomCenter, + alignment: alignment, child: new SizedBox( width: widget.itemWidth ?? double.infinity, height: widget.itemHeight ?? double.infinity, @@ -832,7 +887,30 @@ class _StackViewState extends _CustomLayoutStateBase<_StackSwiper> { @override void didChangeDependencies() { super.didChangeDependencies(); - double space = (_screenWidth - widget.itemWidth) / 2; + + + } + + void _updateValues(){ + if(widget.scrollDirection == Axis.horizontal){ + double space = (_swiperWidth - widget.itemWidth) / 2; + offsets = [-space, -space / 3 * 2, -space / 3, 0.0, _swiperWidth]; + }else{ + double space = (_swiperHeight - widget.itemHeight) / 2; + offsets = [-space, -space / 3 * 2, -space / 3, 0.0, _swiperHeight]; + } + } + + @override + void didUpdateWidget(_StackSwiper oldWidget) { + _updateValues(); + super.didUpdateWidget(oldWidget); + } + + @override + void afterRender() { + + super.afterRender(); //length of the values array below _animationCount = 5; @@ -840,8 +918,9 @@ class _StackViewState extends _CustomLayoutStateBase<_StackSwiper> { //Array below this line, '0' index is 1.0 ,witch is the first item show in swiper. _startIndex = -3; scales = [0.7, 0.8, 0.9, 1.0, 1.0]; - offsets = [-space, -space / 3 * 2, -space / 3, 0.0, _screenWidth]; opacity = [0.0, 0.5, 1.0, 1.0, 1.0]; + + _updateValues(); } @override @@ -850,14 +929,20 @@ class _StackViewState extends _CustomLayoutStateBase<_StackSwiper> { double f = _getValue(offsets, animationValue, i); double o = _getValue(opacity, animationValue, i); + Offset offset = widget.scrollDirection == Axis.horizontal ? + new Offset(f, 0.0) : new Offset(0.0, f); + + Alignment alignment = widget.scrollDirection == Axis.horizontal ? + Alignment.centerLeft :Alignment.topCenter; + return new Opacity( opacity: o, child: new Transform.translate( key: new ValueKey(_currentIndex + i), - offset: new Offset(f, 0.0), + offset: offset, child: new Transform.scale( scale: s, - alignment: Alignment.centerLeft, + alignment: alignment, child: new SizedBox( width: widget.itemWidth ?? double.infinity, height: widget.itemHeight ?? double.infinity, diff --git a/pubspec.yaml b/pubspec.yaml index 2eea5ba..920a986 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_swiper description: The best swiper(carousel) for flutter, with multiple layouts, infinite loop. Compatible with Android & iOS. -version: 1.0.5 +version: 1.0.6 author: JZoom homepage: https://github.com/jzoom/flutter_swiper