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**:
|
||||
- `isHorizontalSwipingEnabled` and `isVerticalSwipingEnabled` have been removed. Use `allowedSwipeDirection` instead.
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class Example extends StatelessWidget {
|
|||
body: Flexible(
|
||||
child: CardSwiper(
|
||||
cardsCount: cards.length,
|
||||
cardBuilder: (context, index) => cards[index],
|
||||
cardBuilder: (context, index, percentThresholdX, percentThresholdY) => cards[index],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -97,7 +97,7 @@ class Example extends StatelessWidget {
|
|||
#### Basic
|
||||
|
||||
| Parameter | Default | Description | Required |
|
||||
|-------------------------------------------| :------------------------------------------------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------| :------: |
|
||||
|-------------------------------------------|:---------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------| :------: |
|
||||
| cardBuilder | - | Widget builder for rendering cards | true |
|
||||
| cardsCount | - | Number of cards | true |
|
||||
| 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 |
|
||||
| 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 |
|
||||
|
||||
| onSwipeDirectionChange | - | A callback containing the horizontal and vertical swipe direction | false |
|
||||
#### 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.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,13 @@ class _ExamplePageState extends State<Example> {
|
|||
numberOfCardsDisplayed: 3,
|
||||
backCardOffset: const Offset(40, 40),
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
cardBuilder: (context, index) => cards[index],
|
||||
cardBuilder: (
|
||||
context,
|
||||
index,
|
||||
horizontalThresholdPercentage,
|
||||
verticalThresholdPercentage,
|
||||
) =>
|
||||
cards[index],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ class CardAnimation {
|
|||
this.isHorizontalSwipingEnabled = true,
|
||||
this.isVerticalSwipingEnabled = true,
|
||||
this.allowedSwipeDirection = const AllowedSwipeDirection.all(),
|
||||
this.onSwipeDirectionChanged,
|
||||
}) : scale = initialScale;
|
||||
|
||||
final double maxAngle;
|
||||
|
|
@ -22,6 +23,7 @@ class CardAnimation {
|
|||
final bool isHorizontalSwipingEnabled;
|
||||
final bool isVerticalSwipingEnabled;
|
||||
final AllowedSwipeDirection allowedSwipeDirection;
|
||||
final ValueChanged<CardSwiperDirection>? onSwipeDirectionChanged;
|
||||
|
||||
double left = 0;
|
||||
double top = 0;
|
||||
|
|
@ -56,19 +58,41 @@ class CardAnimation {
|
|||
|
||||
void update(double dx, double dy, bool inverseAngle) {
|
||||
if (allowedSwipeDirection.right && allowedSwipeDirection.left) {
|
||||
if (left > 0) {
|
||||
onSwipeDirectionChanged?.call(CardSwiperDirection.right);
|
||||
} else if (left < 0) {
|
||||
onSwipeDirectionChanged?.call(CardSwiperDirection.left);
|
||||
}
|
||||
left += dx;
|
||||
} else if (allowedSwipeDirection.right) {
|
||||
if (left >= 0) left += dx;
|
||||
if (left >= 0) {
|
||||
onSwipeDirectionChanged?.call(CardSwiperDirection.right);
|
||||
left += dx;
|
||||
}
|
||||
} else if (allowedSwipeDirection.left) {
|
||||
if (left <= 0) left += dx;
|
||||
if (left <= 0) {
|
||||
onSwipeDirectionChanged?.call(CardSwiperDirection.left);
|
||||
left += dx;
|
||||
}
|
||||
}
|
||||
|
||||
if (allowedSwipeDirection.up && allowedSwipeDirection.down) {
|
||||
if (top > 0) {
|
||||
onSwipeDirectionChanged?.call(CardSwiperDirection.bottom);
|
||||
} else if (top < 0) {
|
||||
onSwipeDirectionChanged?.call(CardSwiperDirection.top);
|
||||
}
|
||||
top += dy;
|
||||
} else if (allowedSwipeDirection.up) {
|
||||
if (top <= 0) top += dy;
|
||||
if (top <= 0) {
|
||||
onSwipeDirectionChanged?.call(CardSwiperDirection.top);
|
||||
top += dy;
|
||||
}
|
||||
} else if (allowedSwipeDirection.down) {
|
||||
if (top >= 0) top += dy;
|
||||
if (top >= 0) {
|
||||
onSwipeDirectionChanged?.call(CardSwiperDirection.bottom);
|
||||
top += dy;
|
||||
}
|
||||
}
|
||||
|
||||
total = left + top;
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ import 'package:flutter_card_swiper/src/undoable.dart';
|
|||
class CardSwiper extends StatefulWidget {
|
||||
/// Function that builds each card in the stack.
|
||||
///
|
||||
/// The [int] parameter specifies the index of the card to build, and the [BuildContext]
|
||||
/// parameter provides the build context. The function should return a widget that represents
|
||||
/// the card at the given index. It can return `null`, which will result in an
|
||||
/// empty card being displayed.
|
||||
final NullableIndexedWidgetBuilder cardBuilder;
|
||||
/// The function is called with the index of the card to be built, the build context, the ratio
|
||||
/// of vertical drag to [threshold] as a percentage, and the ratio of horizontal drag to [threshold]
|
||||
/// as a percentage. The function should return a widget that represents the card at the given index.
|
||||
/// It can return `null`, which will result in an empty card being displayed.
|
||||
final NullableCardBuilder cardBuilder;
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
///
|
||||
/// In order to keep the back card position same after changing the [backCardOffset],
|
||||
|
|
@ -137,6 +142,7 @@ class CardSwiper extends StatefulWidget {
|
|||
this.onSwipe,
|
||||
this.onEnd,
|
||||
this.direction = CardSwiperDirection.right,
|
||||
this.onSwipeDirectionChange,
|
||||
this.allowedSwipeDirection = const AllowedSwipeDirection.all(),
|
||||
this.isLoop = true,
|
||||
this.numberOfCardsDisplayed = 2,
|
||||
|
|
@ -179,6 +185,8 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
|
||||
SwipeType _swipeType = SwipeType.none;
|
||||
CardSwiperDirection _detectedDirection = CardSwiperDirection.none;
|
||||
CardSwiperDirection _detectedHorizontalDirection = CardSwiperDirection.none;
|
||||
CardSwiperDirection _detectedVerticalDirection = CardSwiperDirection.none;
|
||||
bool _tappedOnTop = false;
|
||||
|
||||
final _undoableIndex = Undoable<int?>(null);
|
||||
|
|
@ -211,9 +219,33 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
initialScale: widget.scale,
|
||||
allowedSwipeDirection: widget.allowedSwipeDirection,
|
||||
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
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
|
|
@ -234,7 +266,6 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
fit: StackFit.expand,
|
||||
children: List.generate(numberOfCardsOnScreen(), (index) {
|
||||
if (index == 0) return _frontItem(constraints);
|
||||
|
||||
return _backItem(constraints, index);
|
||||
}).reversed.toList(),
|
||||
);
|
||||
|
|
@ -254,7 +285,12 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
angle: _cardAnimation.angle,
|
||||
child: ConstrainedBox(
|
||||
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 {
|
||||
|
|
@ -299,7 +335,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
scale: _cardAnimation.scale - ((1 - widget.scale) * (index - 1)),
|
||||
child: ConstrainedBox(
|
||||
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() {
|
||||
onSwipeDirectionChanged(CardSwiperDirection.none);
|
||||
_detectedDirection = CardSwiperDirection.none;
|
||||
setState(() {
|
||||
_animationController.reset();
|
||||
_cardAnimation.reset();
|
||||
|
|
@ -402,7 +440,6 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
|
||||
void _swipe(CardSwiperDirection direction) {
|
||||
if (_currentIndex == null) return;
|
||||
|
||||
_swipeType = SwipeType.swipe;
|
||||
_detectedDirection = direction;
|
||||
_cardAnimation.animate(context, direction);
|
||||
|
|
@ -410,7 +447,6 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper>
|
|||
|
||||
void _goBack() {
|
||||
_swipeType = SwipeType.back;
|
||||
_detectedDirection = CardSwiperDirection.none;
|
||||
_cardAnimation.animateBack(context);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_card_swiper/src/enums.dart';
|
||||
|
||||
typedef CardSwiperOnSwipe = FutureOr<bool> Function(
|
||||
|
|
@ -8,6 +9,23 @@ typedef CardSwiperOnSwipe = FutureOr<bool> Function(
|
|||
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 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.
|
||||
homepage: https://github.com/ricardodalarme/flutter_card_swiper
|
||||
issue_tracker: https://github.com/ricardodalarme/flutter_card_swiper/issues
|
||||
version: 5.1.0
|
||||
version: 6.0.0
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <4.0.0"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
Widget? genericBuilder(BuildContext context, int index) {
|
||||
Widget? genericBuilder(
|
||||
BuildContext context,
|
||||
int index,
|
||||
int horizontalPercentage,
|
||||
int verticalPercentage,
|
||||
) {
|
||||
return Container(
|
||||
width: 200,
|
||||
height: 200,
|
||||
|
|
|
|||
Loading…
Reference in New Issue