feat: add option to control if the stack should loop

This commit is contained in:
Ricardo Dalarme 2023-02-20 19:55:10 -03:00
parent 4a8ea3afcf
commit 5f71cf9b4d
3 changed files with 26 additions and 14 deletions

View File

@ -105,6 +105,7 @@ class Example extends StatelessWidget {
| isDisabled | false | Set to ```true``` if swiping should be disabled, has no impact when triggered from the outside | false | isDisabled | false | Set to ```true``` if swiping should be disabled, has no impact when triggered from the outside | false
| isHorizontalSwipingEnabled | true | Set to ```false``` if you want your card to move only across the vertical axis when swiping | false | isHorizontalSwipingEnabled | true | Set to ```false``` if you want your card to move only across the vertical axis when swiping | false
| isVerticalSwipingEnabled | true | Set to ```false``` if you want your card to move only across the horizontal axis when swiping | false | isVerticalSwipingEnabled | true | Set to ```false``` if you want your card to move only across the horizontal axis when swiping | false
| isLoop | true | set to ```true``` if the stack should loop | false
| onTapDisabled | - | Function that get triggered when the swiper is disabled | false | onTapDisabled | - | Function that get triggered when the swiper is disabled | false
| onSwipe | - | Called with the new index and detected swipe direction when the user swiped | false | onSwipe | - | Called with the new index and detected swipe direction when the user swiped | false
| onEnd | - | Called when there is no Widget left to be swiped away | false | onEnd | - | Called when there is no Widget left to be swiped away | false

View File

@ -28,7 +28,7 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "1.2.1" version: "2.0.0"
js: js:
dependency: transitive dependency: transitive
description: description:

View File

@ -48,6 +48,9 @@ class CardSwiper<T extends Widget> extends StatefulWidget {
/// set to false if you want your card to move only across the horizontal axis when swiping /// set to false if you want your card to move only across the horizontal axis when swiping
final bool isVerticalSwipingEnabled; final bool isVerticalSwipingEnabled;
/// set to true if the stack should loop
final bool isLoop;
const CardSwiper({ const CardSwiper({
Key? key, Key? key,
required this.cards, required this.cards,
@ -64,6 +67,7 @@ class CardSwiper<T extends Widget> extends StatefulWidget {
this.direction = CardSwiperDirection.right, this.direction = CardSwiperDirection.right,
this.isHorizontalSwipingEnabled = true, this.isHorizontalSwipingEnabled = true,
this.isVerticalSwipingEnabled = true, this.isVerticalSwipingEnabled = true,
this.isLoop = true,
}) : assert( }) : assert(
maxAngle >= 0 && maxAngle <= 360, maxAngle >= 0 && maxAngle <= 360,
'maxAngle must be between 0 and 360', 'maxAngle must be between 0 and 360',
@ -95,8 +99,6 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
late double _scale = widget.scale; late double _scale = widget.scale;
double _difference = 40; double _difference = 40;
int _currentIndex = 0;
SwipeType _swipeType = SwipeType.none; SwipeType _swipeType = SwipeType.none;
bool _tapOnTop = false; //position of starting drag point on card bool _tapOnTop = false; //position of starting drag point on card
@ -106,17 +108,22 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
late Animation<double> _scaleAnimation; late Animation<double> _scaleAnimation;
late Animation<double> _differenceAnimation; late Animation<double> _differenceAnimation;
final List<T> _stack = [];
CardSwiperDirection detectedDirection = CardSwiperDirection.none; CardSwiperDirection detectedDirection = CardSwiperDirection.none;
double get _maxAngle => widget.maxAngle * (pi / 180); double get _maxAngle => widget.maxAngle * (pi / 180);
bool get _isLastCard => _currentIndex == widget.cards.length - 1; int get _currentIndex => _stack.length - 1;
int get _nextCardIndex => _isLastCard ? 0 : _currentIndex + 1; bool get _canSwipe => _stack.isNotEmpty && !widget.isDisabled;
bool get _hasBackItem => _stack.length > 1 || widget.isLoop;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_stack.addAll(widget.cards);
widget.controller?.addListener(_controllerListener); widget.controller?.addListener(_controllerListener);
_animationController = AnimationController( _animationController = AnimationController(
@ -146,8 +153,8 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
clipBehavior: Clip.none, clipBehavior: Clip.none,
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
_backItem(constraints), if (_hasBackItem) _backItem(constraints),
_frontItem(constraints), if (_stack.isNotEmpty) _frontItem(constraints),
], ],
); );
}, },
@ -199,7 +206,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
} }
}, },
onPanEnd: (tapInfo) { onPanEnd: (tapInfo) {
if (!widget.isDisabled) { if (_canSwipe) {
_tapOnTop = false; _tapOnTop = false;
_onEndAnimation(); _onEndAnimation();
_animationController.forward(); _animationController.forward();
@ -217,7 +224,9 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
scale: _scale, scale: _scale,
child: ConstrainedBox( child: ConstrainedBox(
constraints: constraints, constraints: constraints,
child: widget.cards[_nextCardIndex], child: _stack.length <= 1
? widget.cards.last
: widget.cards[_currentIndex - 1],
), ),
), ),
); );
@ -264,12 +273,14 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
setState(() { setState(() {
if (_swipeType == SwipeType.swipe) { if (_swipeType == SwipeType.swipe) {
widget.onSwipe?.call(_currentIndex, detectedDirection); widget.onSwipe?.call(_currentIndex, detectedDirection);
_stack.removeAt(_currentIndex);
if (_isLastCard) { if (_stack.isEmpty) {
widget.onEnd?.call(); widget.onEnd?.call();
_currentIndex = 0;
} else { if (widget.isLoop) {
_currentIndex++; _stack.addAll(widget.cards);
}
} }
} }
_animationController.reset(); _animationController.reset();
@ -316,7 +327,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
} }
void _swipe(BuildContext context, CardSwiperDirection direction) { void _swipe(BuildContext context, CardSwiperDirection direction) {
if (widget.cards.isEmpty) return; if (!_canSwipe) return;
switch (direction) { switch (direction) {
case CardSwiperDirection.left: case CardSwiperDirection.left: