feat: additional info to cardBuilder (#22)
Additional swiping info to cardBuilder callback Add an additional callback containing the horizontal and vertical swipe direction Co-authored-by: samuel.peirson.knowunity <samuel.peirson@knowunity.com>
This commit is contained in:
parent
f1ab70fd99
commit
1f23f08ea1
|
|
@ -1,5 +1,10 @@
|
||||||
## NEXT
|
|
||||||
|
|
||||||
|
## [6.0.0]
|
||||||
|
|
||||||
|
- Adds `onSwipeDirectionChange` callback containing the horizontal and vertical swipe direction
|
||||||
|
- **BREAKING CHANGE**:
|
||||||
|
- Modifies the `cardBuilder` callback, to include the ratio of horizontal drag to threshold as a percentage
|
||||||
|
and the ratio of vertical drag to threshold as a percentage.
|
||||||
- **BREAKING CHANGE**:
|
- **BREAKING CHANGE**:
|
||||||
- `isHorizontalSwipingEnabled` and `isVerticalSwipingEnabled` have been removed. Use `allowedSwipeDirection` instead.
|
- `isHorizontalSwipingEnabled` and `isVerticalSwipingEnabled` have been removed. Use `allowedSwipeDirection` instead.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ class Example extends StatelessWidget {
|
||||||
body: Flexible(
|
body: Flexible(
|
||||||
child: CardSwiper(
|
child: CardSwiper(
|
||||||
cardsCount: cards.length,
|
cardsCount: cards.length,
|
||||||
cardBuilder: (context, index) => cards[index],
|
cardBuilder: (context, index, percentThresholdX, percentThresholdY) => cards[index],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -97,7 +97,7 @@ class Example extends StatelessWidget {
|
||||||
#### Basic
|
#### Basic
|
||||||
|
|
||||||
| Parameter | Default | Description | Required |
|
| Parameter | Default | Description | Required |
|
||||||
|-------------------------------------------| :------------------------------------------------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------| :------: |
|
|-------------------------------------------|:---------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------| :------: |
|
||||||
| cardBuilder | - | Widget builder for rendering cards | true |
|
| cardBuilder | - | Widget builder for rendering cards | true |
|
||||||
| cardsCount | - | Number of cards | true |
|
| cardsCount | - | Number of cards | true |
|
||||||
| controller | - | Controller to trigger swipe actions | false |
|
| controller | - | Controller to trigger swipe actions | false |
|
||||||
|
|
@ -116,7 +116,7 @@ class Example extends StatelessWidget {
|
||||||
| padding | EdgeInsets.symmetric(horizontal: 20, vertical: 25) | The padding around the swiper | false |
|
| padding | EdgeInsets.symmetric(horizontal: 20, vertical: 25) | The padding around the swiper | false |
|
||||||
| scale | 0.9 | Scale of the card that is behind the front card | false |
|
| scale | 0.9 | Scale of the card that is behind the front card | false |
|
||||||
| threshold | 50 | Threshold from which the card is swiped away | false |
|
| threshold | 50 | Threshold from which the card is swiped away | false |
|
||||||
|
| onSwipeDirectionChange | - | A callback containing the horizontal and vertical swipe direction | false |
|
||||||
#### Controller
|
#### Controller
|
||||||
|
|
||||||
The `Controller` is used to swipe the card from outside of the widget. You can create a controller called `CardSwiperController` and save the instance for further usage. Please have a closer look at our [Example](https://github.com/ricardodalarme/flutter_card_swiper/tree/main/example) for the usage.
|
The `Controller` is used to swipe the card from outside of the widget. You can create a controller called `CardSwiperController` and save the instance for further usage. Please have a closer look at our [Example](https://github.com/ricardodalarme/flutter_card_swiper/tree/main/example) for the usage.
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,13 @@ class _ExamplePageState extends State<Example> {
|
||||||
numberOfCardsDisplayed: 3,
|
numberOfCardsDisplayed: 3,
|
||||||
backCardOffset: const Offset(40, 40),
|
backCardOffset: const Offset(40, 40),
|
||||||
padding: const EdgeInsets.all(24.0),
|
padding: const EdgeInsets.all(24.0),
|
||||||
cardBuilder: (context, index) => cards[index],
|
cardBuilder: (
|
||||||
|
context,
|
||||||
|
index,
|
||||||
|
horizontalThresholdPercentage,
|
||||||
|
verticalThresholdPercentage,
|
||||||
|
) =>
|
||||||
|
cards[index],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ class CardAnimation {
|
||||||
this.isHorizontalSwipingEnabled = true,
|
this.isHorizontalSwipingEnabled = true,
|
||||||
this.isVerticalSwipingEnabled = true,
|
this.isVerticalSwipingEnabled = true,
|
||||||
this.allowedSwipeDirection = const AllowedSwipeDirection.all(),
|
this.allowedSwipeDirection = const AllowedSwipeDirection.all(),
|
||||||
|
this.onSwipeDirectionChanged,
|
||||||
}) : scale = initialScale;
|
}) : scale = initialScale;
|
||||||
|
|
||||||
final double maxAngle;
|
final double maxAngle;
|
||||||
|
|
@ -22,6 +23,7 @@ class CardAnimation {
|
||||||
final bool isHorizontalSwipingEnabled;
|
final bool isHorizontalSwipingEnabled;
|
||||||
final bool isVerticalSwipingEnabled;
|
final bool isVerticalSwipingEnabled;
|
||||||
final AllowedSwipeDirection allowedSwipeDirection;
|
final AllowedSwipeDirection allowedSwipeDirection;
|
||||||
|
final ValueChanged<CardSwiperDirection>? onSwipeDirectionChanged;
|
||||||
|
|
||||||
double left = 0;
|
double left = 0;
|
||||||
double top = 0;
|
double top = 0;
|
||||||
|
|
@ -56,19 +58,41 @@ class CardAnimation {
|
||||||
|
|
||||||
void update(double dx, double dy, bool inverseAngle) {
|
void update(double dx, double dy, bool inverseAngle) {
|
||||||
if (allowedSwipeDirection.right && allowedSwipeDirection.left) {
|
if (allowedSwipeDirection.right && allowedSwipeDirection.left) {
|
||||||
|
if (left > 0) {
|
||||||
|
onSwipeDirectionChanged?.call(CardSwiperDirection.right);
|
||||||
|
} else if (left < 0) {
|
||||||
|
onSwipeDirectionChanged?.call(CardSwiperDirection.left);
|
||||||
|
}
|
||||||
left += dx;
|
left += dx;
|
||||||
} else if (allowedSwipeDirection.right) {
|
} else if (allowedSwipeDirection.right) {
|
||||||
if (left >= 0) left += dx;
|
if (left >= 0) {
|
||||||
|
onSwipeDirectionChanged?.call(CardSwiperDirection.right);
|
||||||
|
left += dx;
|
||||||
|
}
|
||||||
} else if (allowedSwipeDirection.left) {
|
} else if (allowedSwipeDirection.left) {
|
||||||
if (left <= 0) left += dx;
|
if (left <= 0) {
|
||||||
|
onSwipeDirectionChanged?.call(CardSwiperDirection.left);
|
||||||
|
left += dx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowedSwipeDirection.up && allowedSwipeDirection.down) {
|
if (allowedSwipeDirection.up && allowedSwipeDirection.down) {
|
||||||
|
if (top > 0) {
|
||||||
|
onSwipeDirectionChanged?.call(CardSwiperDirection.bottom);
|
||||||
|
} else if (top < 0) {
|
||||||
|
onSwipeDirectionChanged?.call(CardSwiperDirection.top);
|
||||||
|
}
|
||||||
top += dy;
|
top += dy;
|
||||||
} else if (allowedSwipeDirection.up) {
|
} else if (allowedSwipeDirection.up) {
|
||||||
if (top <= 0) top += dy;
|
if (top <= 0) {
|
||||||
|
onSwipeDirectionChanged?.call(CardSwiperDirection.top);
|
||||||
|
top += dy;
|
||||||
|
}
|
||||||
} else if (allowedSwipeDirection.down) {
|
} else if (allowedSwipeDirection.down) {
|
||||||
if (top >= 0) top += dy;
|
if (top >= 0) {
|
||||||
|
onSwipeDirectionChanged?.call(CardSwiperDirection.bottom);
|
||||||
|
top += dy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total = left + top;
|
total = left + top;
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@ import 'package:flutter_card_swiper/src/undoable.dart';
|
||||||
class CardSwiper extends StatefulWidget {
|
class CardSwiper extends StatefulWidget {
|
||||||
/// Function that builds each card in the stack.
|
/// Function that builds each card in the stack.
|
||||||
///
|
///
|
||||||
/// The [int] parameter specifies the index of the card to build, and the [BuildContext]
|
/// The function is called with the index of the card to be built, the build context, the ratio
|
||||||
/// parameter provides the build context. The function should return a widget that represents
|
/// of vertical drag to [threshold] as a percentage, and the ratio of horizontal drag to [threshold]
|
||||||
/// the card at the given index. It can return `null`, which will result in an
|
/// as a percentage. The function should return a widget that represents the card at the given index.
|
||||||
/// empty card being displayed.
|
/// It can return `null`, which will result in an empty card being displayed.
|
||||||
final NullableIndexedWidgetBuilder cardBuilder;
|
final NullableCardBuilder cardBuilder;
|
||||||
|
|
||||||
/// The number of cards in the stack.
|
/// The number of cards in the stack.
|
||||||
///
|
///
|
||||||
|
|
@ -111,6 +111,11 @@ class CardSwiper extends StatefulWidget {
|
||||||
/// on top of the stack. If the function returns `true`, the undo action is performed as expected.
|
/// on top of the stack. If the function returns `true`, the undo action is performed as expected.
|
||||||
final CardSwiperOnUndo? onUndo;
|
final CardSwiperOnUndo? onUndo;
|
||||||
|
|
||||||
|
/// Callback function that is called when a card swipe direction changes.
|
||||||
|
///
|
||||||
|
/// The function is called with the last detected horizontal direction and the last detected vertical direction
|
||||||
|
final CardSwiperDirectionChange? onSwipeDirectionChange;
|
||||||
|
|
||||||
/// The offset of the back card from the front card.
|
/// The offset of the back card from the front card.
|
||||||
///
|
///
|
||||||
/// In order to keep the back card position same after changing the [backCardOffset],
|
/// In order to keep the back card position same after changing the [backCardOffset],
|
||||||
|
|
@ -137,6 +142,7 @@ class CardSwiper extends StatefulWidget {
|
||||||
this.onSwipe,
|
this.onSwipe,
|
||||||
this.onEnd,
|
this.onEnd,
|
||||||
this.direction = CardSwiperDirection.right,
|
this.direction = CardSwiperDirection.right,
|
||||||
|
this.onSwipeDirectionChange,
|
||||||
this.allowedSwipeDirection = const AllowedSwipeDirection.all(),
|
this.allowedSwipeDirection = const AllowedSwipeDirection.all(),
|
||||||
this.isLoop = true,
|
this.isLoop = true,
|
||||||
this.numberOfCardsDisplayed = 2,
|
this.numberOfCardsDisplayed = 2,
|
||||||
|
|
@ -179,6 +185,8 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
||||||
|
|
||||||
SwipeType _swipeType = SwipeType.none;
|
SwipeType _swipeType = SwipeType.none;
|
||||||
CardSwiperDirection _detectedDirection = CardSwiperDirection.none;
|
CardSwiperDirection _detectedDirection = CardSwiperDirection.none;
|
||||||
|
CardSwiperDirection _detectedHorizontalDirection = CardSwiperDirection.none;
|
||||||
|
CardSwiperDirection _detectedVerticalDirection = CardSwiperDirection.none;
|
||||||
bool _tappedOnTop = false;
|
bool _tappedOnTop = false;
|
||||||
|
|
||||||
final _undoableIndex = Undoable<int?>(null);
|
final _undoableIndex = Undoable<int?>(null);
|
||||||
|
|
@ -211,9 +219,33 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
||||||
initialScale: widget.scale,
|
initialScale: widget.scale,
|
||||||
allowedSwipeDirection: widget.allowedSwipeDirection,
|
allowedSwipeDirection: widget.allowedSwipeDirection,
|
||||||
initialOffset: widget.backCardOffset,
|
initialOffset: widget.backCardOffset,
|
||||||
|
onSwipeDirectionChanged: onSwipeDirectionChanged,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onSwipeDirectionChanged(CardSwiperDirection direction) {
|
||||||
|
if (direction == CardSwiperDirection.none) {
|
||||||
|
_detectedVerticalDirection = direction;
|
||||||
|
_detectedHorizontalDirection = direction;
|
||||||
|
widget.onSwipeDirectionChange
|
||||||
|
?.call(_detectedHorizontalDirection, _detectedVerticalDirection);
|
||||||
|
} else if (direction == CardSwiperDirection.right ||
|
||||||
|
direction == CardSwiperDirection.left) {
|
||||||
|
if (_detectedHorizontalDirection != direction) {
|
||||||
|
_detectedHorizontalDirection = direction;
|
||||||
|
widget.onSwipeDirectionChange
|
||||||
|
?.call(_detectedHorizontalDirection, _detectedVerticalDirection);
|
||||||
|
}
|
||||||
|
} else if (direction == CardSwiperDirection.top ||
|
||||||
|
direction == CardSwiperDirection.bottom) {
|
||||||
|
if (_detectedVerticalDirection != direction) {
|
||||||
|
_detectedVerticalDirection = direction;
|
||||||
|
widget.onSwipeDirectionChange
|
||||||
|
?.call(_detectedHorizontalDirection, _detectedVerticalDirection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
|
@ -234,7 +266,6 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
children: List.generate(numberOfCardsOnScreen(), (index) {
|
children: List.generate(numberOfCardsOnScreen(), (index) {
|
||||||
if (index == 0) return _frontItem(constraints);
|
if (index == 0) return _frontItem(constraints);
|
||||||
|
|
||||||
return _backItem(constraints, index);
|
return _backItem(constraints, index);
|
||||||
}).reversed.toList(),
|
}).reversed.toList(),
|
||||||
);
|
);
|
||||||
|
|
@ -254,7 +285,12 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
||||||
angle: _cardAnimation.angle,
|
angle: _cardAnimation.angle,
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: constraints,
|
constraints: constraints,
|
||||||
child: widget.cardBuilder(context, _currentIndex!),
|
child: widget.cardBuilder(
|
||||||
|
context,
|
||||||
|
_currentIndex!,
|
||||||
|
(100 * _cardAnimation.left / widget.threshold).ceil(),
|
||||||
|
(100 * _cardAnimation.top / widget.threshold).ceil(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
|
@ -299,7 +335,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
||||||
scale: _cardAnimation.scale - ((1 - widget.scale) * (index - 1)),
|
scale: _cardAnimation.scale - ((1 - widget.scale) * (index - 1)),
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: constraints,
|
constraints: constraints,
|
||||||
child: widget.cardBuilder(context, getValidIndexOffset(index)!),
|
child: widget.cardBuilder(context, getValidIndexOffset(index)!, 0, 0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -363,6 +399,8 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
||||||
}
|
}
|
||||||
|
|
||||||
void _reset() {
|
void _reset() {
|
||||||
|
onSwipeDirectionChanged(CardSwiperDirection.none);
|
||||||
|
_detectedDirection = CardSwiperDirection.none;
|
||||||
setState(() {
|
setState(() {
|
||||||
_animationController.reset();
|
_animationController.reset();
|
||||||
_cardAnimation.reset();
|
_cardAnimation.reset();
|
||||||
|
|
@ -402,7 +440,6 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
||||||
|
|
||||||
void _swipe(CardSwiperDirection direction) {
|
void _swipe(CardSwiperDirection direction) {
|
||||||
if (_currentIndex == null) return;
|
if (_currentIndex == null) return;
|
||||||
|
|
||||||
_swipeType = SwipeType.swipe;
|
_swipeType = SwipeType.swipe;
|
||||||
_detectedDirection = direction;
|
_detectedDirection = direction;
|
||||||
_cardAnimation.animate(context, direction);
|
_cardAnimation.animate(context, direction);
|
||||||
|
|
@ -410,7 +447,6 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
||||||
|
|
||||||
void _goBack() {
|
void _goBack() {
|
||||||
_swipeType = SwipeType.back;
|
_swipeType = SwipeType.back;
|
||||||
_detectedDirection = CardSwiperDirection.none;
|
|
||||||
_cardAnimation.animateBack(context);
|
_cardAnimation.animateBack(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_card_swiper/src/enums.dart';
|
import 'package:flutter_card_swiper/src/enums.dart';
|
||||||
|
|
||||||
typedef CardSwiperOnSwipe = FutureOr<bool> Function(
|
typedef CardSwiperOnSwipe = FutureOr<bool> Function(
|
||||||
|
|
@ -8,6 +9,23 @@ typedef CardSwiperOnSwipe = FutureOr<bool> Function(
|
||||||
CardSwiperDirection direction,
|
CardSwiperDirection direction,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
typedef CardSwiperOnSwipeUpdate = Function(
|
||||||
|
int? currentIndex,
|
||||||
|
CardSwiperDirection direction,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef NullableCardBuilder = Widget? Function(
|
||||||
|
BuildContext context,
|
||||||
|
int index,
|
||||||
|
int horizontalOffsetPercentage,
|
||||||
|
int verticalOffsetPercentage,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef CardSwiperDirectionChange = Function(
|
||||||
|
CardSwiperDirection horizontalDirection,
|
||||||
|
CardSwiperDirection verticalDirection,
|
||||||
|
);
|
||||||
|
|
||||||
typedef CardSwiperOnEnd = FutureOr<void> Function();
|
typedef CardSwiperOnEnd = FutureOr<void> Function();
|
||||||
|
|
||||||
typedef CardSwiperOnTapDisabled = FutureOr<void> Function();
|
typedef CardSwiperOnTapDisabled = FutureOr<void> Function();
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ name: flutter_card_swiper
|
||||||
description: This is a Tinder-like card swiper package. It allows you to swipe left, right, up, and down and define your own business logic for each direction.
|
description: This is a Tinder-like card swiper package. It allows you to swipe left, right, up, and down and define your own business logic for each direction.
|
||||||
homepage: https://github.com/ricardodalarme/flutter_card_swiper
|
homepage: https://github.com/ricardodalarme/flutter_card_swiper
|
||||||
issue_tracker: https://github.com/ricardodalarme/flutter_card_swiper/issues
|
issue_tracker: https://github.com/ricardodalarme/flutter_card_swiper/issues
|
||||||
version: 5.1.0
|
version: 6.0.0
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.12.0 <4.0.0"
|
sdk: ">=2.12.0 <4.0.0"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
Widget? genericBuilder(BuildContext context, int index) {
|
Widget? genericBuilder(
|
||||||
|
BuildContext context,
|
||||||
|
int index,
|
||||||
|
int horizontalPercentage,
|
||||||
|
int verticalPercentage,
|
||||||
|
) {
|
||||||
return Container(
|
return Container(
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue