feat(cards): render the items through a builder callback
This commit is contained in:
parent
5edd21e371
commit
db500bf458
|
|
@ -1,7 +1,8 @@
|
|||
## NEXT
|
||||
## [3.0.0]
|
||||
|
||||
- **BREAKING CHANGES**:
|
||||
- Add currentIndex and previousIndex to the onSwipe callback
|
||||
- Render the items through a builder function
|
||||
|
||||
## [2.1.0]
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@ class Example extends StatelessWidget {
|
|||
return Scaffold(
|
||||
body: Flexible(
|
||||
child: CardSwiper(
|
||||
cards: cards,
|
||||
cardsCount: cards.length,
|
||||
cardBuilder: (context, index) => cards[index],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -92,10 +93,10 @@ class Example extends StatelessWidget {
|
|||
## Constructor
|
||||
#### Basic
|
||||
|
||||
|
||||
| Parameter | Default | Description | Required |
|
||||
| ------------- |:-------------|:-----|:-----:|
|
||||
| cards | - | List of Widgets for the swiper | true
|
||||
| cardBuilder | - | Widget builder for rendering cards | true
|
||||
| cardsCount | - | Cards count | true
|
||||
| controller | - | Trigger swipe | false
|
||||
| padding | EdgeInsets.symmetric(horizontal: 20, vertical: 25) | Control swiper padding | false
|
||||
| duration | 200 milliseconds | The duration that every animation should last | false
|
||||
|
|
|
|||
|
|
@ -35,10 +35,11 @@ class _ExamplePageState extends State<Example> {
|
|||
Flexible(
|
||||
child: CardSwiper(
|
||||
controller: controller,
|
||||
cards: cards,
|
||||
cardsCount: cards.length,
|
||||
numberOfCardsDisplayed: 3,
|
||||
onSwipe: _swipe,
|
||||
onSwipe: _onSwipe,
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
cardBuilder: (context, index) => cards[index],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
|
|
@ -68,16 +69,16 @@ class _ExamplePageState extends State<Example> {
|
|||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _swipe(
|
||||
int previousIndex,
|
||||
int currentIndex,
|
||||
void _onSwipe(
|
||||
int? previousIndex,
|
||||
int? currentIndex,
|
||||
CardSwiperDirection direction,
|
||||
) {
|
||||
debugPrint(
|
||||
|
|
|
|||
|
|
@ -3,11 +3,15 @@ import 'dart:math';
|
|||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_card_swiper/src/card_swiper_controller.dart';
|
||||
import 'package:flutter_card_swiper/src/enums.dart';
|
||||
import 'package:flutter_card_swiper/src/extensions.dart';
|
||||
import 'package:flutter_card_swiper/src/typedefs.dart';
|
||||
|
||||
class CardSwiper<T extends Widget> extends StatefulWidget {
|
||||
/// list of widgets for the swiper
|
||||
final List<T> cards;
|
||||
/// widget builder for rendering cards
|
||||
final NullableIndexedWidgetBuilder cardBuilder;
|
||||
|
||||
/// cards count
|
||||
final int cardsCount;
|
||||
|
||||
/// controller to trigger actions
|
||||
final CardSwiperController? controller;
|
||||
|
|
@ -56,7 +60,8 @@ class CardSwiper<T extends Widget> extends StatefulWidget {
|
|||
|
||||
const CardSwiper({
|
||||
Key? key,
|
||||
required this.cards,
|
||||
required this.cardBuilder,
|
||||
required this.cardsCount,
|
||||
this.controller,
|
||||
this.padding = const EdgeInsets.symmetric(horizontal: 20, vertical: 25),
|
||||
this.duration = const Duration(milliseconds: 200),
|
||||
|
|
@ -89,7 +94,7 @@ class CardSwiper<T extends Widget> extends StatefulWidget {
|
|||
'scale must be between 0 and 1',
|
||||
),
|
||||
assert(
|
||||
numberOfCardsDisplayed >= 1 && numberOfCardsDisplayed <= cards.length,
|
||||
numberOfCardsDisplayed >= 1 && numberOfCardsDisplayed <= cardsCount,
|
||||
'you must display at least one card, and no more than the length of cards parameter',
|
||||
),
|
||||
super(key: key);
|
||||
|
|
@ -116,21 +121,18 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
|
|||
late Animation<double> _scaleAnimation;
|
||||
late Animation<double> _differenceAnimation;
|
||||
|
||||
final List<T> _stack = [];
|
||||
|
||||
CardSwiperDirection detectedDirection = CardSwiperDirection.none;
|
||||
|
||||
double get _maxAngle => widget.maxAngle * (pi / 180);
|
||||
|
||||
int get _currentIndex => _stack.length - 1;
|
||||
bool get _canSwipe => _stack.isNotEmpty && !widget.isDisabled;
|
||||
int? _currentIndex = 0;
|
||||
int? get _nextIndex => getValidIndexOffset(1);
|
||||
bool get _canSwipe => _currentIndex != null && !widget.isDisabled;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_stack.addAll(widget.cards);
|
||||
|
||||
widget.controller?.addListener(_controllerListener);
|
||||
|
||||
_animationController = AnimationController(
|
||||
|
|
@ -176,18 +178,6 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
|
|||
);
|
||||
}
|
||||
|
||||
///the number of cards that are built on the screen
|
||||
int nbOfCardsOnScreen() {
|
||||
return widget.isLoop
|
||||
? widget.numberOfCardsDisplayed
|
||||
: _stack.isNotEmpty
|
||||
? min(
|
||||
widget.numberOfCardsDisplayed,
|
||||
_stack.length,
|
||||
)
|
||||
: 0;
|
||||
}
|
||||
|
||||
/// The card shown at the front of the stack, that can be dragged and swipped
|
||||
Widget _frontItem(BoxConstraints constraints) {
|
||||
return Positioned(
|
||||
|
|
@ -198,7 +188,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
|
|||
angle: _angle,
|
||||
child: ConstrainedBox(
|
||||
constraints: constraints,
|
||||
child: _stack[_currentIndex],
|
||||
child: widget.cardBuilder(context, _currentIndex!),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
|
|
@ -251,10 +241,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
|
|||
scale: _scale,
|
||||
child: ConstrainedBox(
|
||||
constraints: constraints,
|
||||
child: _stack.length <= 1
|
||||
? widget.cards.last
|
||||
: _stack[_currentIndex - 1],
|
||||
//or: widget.cards[(_currentIndex - 1) % widget.cards.length] (same thing)
|
||||
child: widget.cardBuilder(context, _nextIndex!),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -262,7 +249,7 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
|
|||
|
||||
/// if widget.numberOfCardsDisplayed > 2, those cards are built behind the
|
||||
/// _secondItem and can't move at all
|
||||
Widget _backItem(BoxConstraints constraints, int index) {
|
||||
Widget _backItem(BoxConstraints constraints, int offset) {
|
||||
return Positioned(
|
||||
top: 40,
|
||||
left: 0,
|
||||
|
|
@ -270,7 +257,10 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
|
|||
scale: widget.scale,
|
||||
child: ConstrainedBox(
|
||||
constraints: constraints,
|
||||
child: widget.cards[(_currentIndex - index) % widget.cards.length],
|
||||
child: widget.cardBuilder(
|
||||
context,
|
||||
getValidIndexOffset(offset)!,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -317,21 +307,17 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
|
|||
setState(() {
|
||||
if (_swipeType == SwipeType.swipe) {
|
||||
final previousIndex = _currentIndex;
|
||||
_stack.removeAt(_currentIndex);
|
||||
final isLastCard = _currentIndex == widget.cardsCount - 1;
|
||||
|
||||
_currentIndex = _nextIndex;
|
||||
widget.onSwipe?.call(
|
||||
previousIndex,
|
||||
widget.isLoop && _stack.isEmpty
|
||||
? widget.cards.length - 1
|
||||
: _currentIndex,
|
||||
_currentIndex,
|
||||
detectedDirection,
|
||||
);
|
||||
|
||||
if (_stack.isEmpty) {
|
||||
if (isLastCard) {
|
||||
widget.onEnd?.call();
|
||||
|
||||
if (widget.isLoop) {
|
||||
_stack.addAll(widget.cards);
|
||||
}
|
||||
}
|
||||
}
|
||||
_animationController.reset();
|
||||
|
|
@ -486,4 +472,31 @@ class _CardSwiperState<T extends Widget> extends State<CardSwiper<T>>
|
|||
|
||||
_swipeType = SwipeType.back;
|
||||
}
|
||||
|
||||
///the number of cards that are built on the screen
|
||||
int nbOfCardsOnScreen() {
|
||||
if (widget.isLoop) {
|
||||
return widget.numberOfCardsDisplayed;
|
||||
}
|
||||
if (_currentIndex == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return min(
|
||||
widget.numberOfCardsDisplayed,
|
||||
widget.cardsCount - _currentIndex!,
|
||||
);
|
||||
}
|
||||
|
||||
int? getValidIndexOffset(int offset) {
|
||||
if (_currentIndex == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final index = _currentIndex! + offset;
|
||||
if (!widget.isLoop && !index.isBetween(0, widget.cardsCount)) {
|
||||
return null;
|
||||
}
|
||||
return index % widget.cardsCount;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
extension Range on num {
|
||||
bool isBetween(num from, num to) {
|
||||
return from < this && this < to;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter_card_swiper/src/enums.dart';
|
||||
|
||||
typedef CardSwiperOnSwipe = void Function(
|
||||
int previousIndex,
|
||||
int currentIndex,
|
||||
int? previousIndex,
|
||||
int? currentIndex,
|
||||
CardSwiperDirection direction,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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: 2.1.0
|
||||
version: 3.0.0
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
|
|
|||
Loading…
Reference in New Issue