Skip to content

Commit

Permalink
add reverse stack
Browse files Browse the repository at this point in the history
  • Loading branch information
bkoncro committed Sep 23, 2022
1 parent 81aa27f commit cbbf0f6
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 63 deletions.
31 changes: 12 additions & 19 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
version: "2.9.0"
boolean_selector:
dependency: transitive
description:
Expand All @@ -28,21 +28,14 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
version: "1.2.1"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
collection:
dependency: transitive
description:
Expand All @@ -63,7 +56,7 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.3.1"
flutter:
dependency: "direct main"
description: flutter
Expand Down Expand Up @@ -101,28 +94,28 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
version: "0.12.12"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
version: "0.1.5"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
version: "1.8.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
version: "1.8.2"
sky_engine:
dependency: transitive
description: flutter
Expand All @@ -134,7 +127,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
version: "1.9.0"
stack_trace:
dependency: transitive
description:
Expand All @@ -155,21 +148,21 @@ packages:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.9"
version: "0.4.12"
vector_math:
dependency: transitive
description:
Expand Down
39 changes: 30 additions & 9 deletions lib/src/custom_layout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ abstract class _CustomLayoutStateBase<T extends _SubSwiper> extends State<T>
late int _startIndex;
int? _animationCount;
int _currentIndex = 0;
late bool _reversePan;

@override
void initState() {
_currentIndex = widget.index ?? 0;
_reversePan = widget.reversePan;
if (widget.itemWidth == null) {
throw Exception(
'==============\n\nwidget.itemWidth must not be null when use stack layout.\n========\n',
Expand Down Expand Up @@ -214,12 +216,20 @@ abstract class _CustomLayoutStateBase<T extends _SubSwiper> extends State<T>
if (_currentIndex <= 0 && !widget.loop) {
return;
}
_move(1.0, nextIndex: _currentIndex - 1);
if (_reversePan) {
_move(0.0, nextIndex: _currentIndex + 1);
} else {
_move(1.0, nextIndex: _currentIndex - 1);
}
} else if (_animationController.value < 0.25 || velocity < -500.0) {
if (_currentIndex >= widget.itemCount - 1 && !widget.loop) {
return;
}
_move(0.0, nextIndex: _currentIndex + 1);
if (_reversePan) {
_move(1.0, nextIndex: _currentIndex - 1);
} else {
_move(0.0, nextIndex: _currentIndex + 1);
}
} else {
_move(0.5);
}
Expand All @@ -235,13 +245,24 @@ abstract class _CustomLayoutStateBase<T extends _SubSwiper> extends State<T>

void _onPanUpdate(DragUpdateDetails details) {
if (_lockScroll) return;
var value = _currentValue +
((widget.scrollDirection == Axis.horizontal
? details.globalPosition.dx
: details.globalPosition.dy) -
_currentPos) /
_swiperWidth /
2;
late double value;
if (_reversePan) {
value = _currentValue -
((widget.scrollDirection == Axis.horizontal
? details.globalPosition.dx
: details.globalPosition.dy) -
_currentPos) /
_swiperWidth /
2;
} else {
value = _currentValue +
((widget.scrollDirection == Axis.horizontal
? details.globalPosition.dx
: details.globalPosition.dy) -
_currentPos) /
_swiperWidth /
2;
}
// no loop ?
if (!widget.loop) {
if (_currentIndex >= widget.itemCount - 1) {
Expand Down
168 changes: 152 additions & 16 deletions lib/src/swiper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const int kMiddleValue = 1000000000;
enum SwiperLayout {
DEFAULT,
STACK,
STACK_REVERSE,
TINDER,
CUSTOM,
}
Expand Down Expand Up @@ -498,6 +499,21 @@ class _SwiperState extends _SwiperTimerMixin {
scrollDirection: widget.scrollDirection,
axisDirection: widget.axisDirection,
);
} else if (widget.layout == SwiperLayout.STACK_REVERSE) {
return _StackReverseSwiper(
loop: widget.loop,
itemWidth: widget.itemWidth,
itemHeight: widget.itemHeight,
itemCount: widget.itemCount,
itemBuilder: itemBuilder,
index: _activeIndex,
curve: widget.curve,
duration: widget.duration,
onIndexChanged: _onIndexChanged,
controller: _controller,
scrollDirection: widget.scrollDirection,
axisDirection: widget.axisDirection,
);
} else if (_isPageViewLayout()) {
//default
var transformer = widget.transformer;
Expand Down Expand Up @@ -696,22 +712,24 @@ abstract class _SubSwiper extends StatefulWidget {
final bool loop;
final Axis? scrollDirection;
final AxisDirection? axisDirection;

const _SubSwiper({
Key? key,
required this.loop,
this.itemHeight,
this.itemWidth,
this.duration,
required this.curve,
this.itemBuilder,
required this.controller,
this.index,
required this.itemCount,
this.scrollDirection = Axis.horizontal,
this.axisDirection = AxisDirection.left,
this.onIndexChanged,
}) : super(key: key);
final bool reversePan;

const _SubSwiper(
{Key? key,
required this.loop,
this.itemHeight,
this.itemWidth,
this.duration,
required this.curve,
this.itemBuilder,
required this.controller,
this.index,
required this.itemCount,
this.scrollDirection = Axis.horizontal,
this.axisDirection = AxisDirection.left,
this.onIndexChanged,
this.reversePan = false})
: super(key: key);

@override
State<StatefulWidget> createState();
Expand Down Expand Up @@ -796,6 +814,41 @@ class _StackSwiper extends _SubSwiper {
State<StatefulWidget> createState() => _StackViewState();
}

class _StackReverseSwiper extends _SubSwiper {
const _StackReverseSwiper({
Key? key,
required Curve curve,
int? duration,
required SwiperController controller,
ValueChanged<int>? onIndexChanged,
double? itemHeight,
double? itemWidth,
IndexedWidgetBuilder? itemBuilder,
int? index,
required bool loop,
required int itemCount,
Axis? scrollDirection,
AxisDirection? axisDirection,
}) : super(
loop: loop,
key: key,
itemWidth: itemWidth,
itemHeight: itemHeight,
itemBuilder: itemBuilder,
curve: curve,
duration: duration,
controller: controller,
index: index,
onIndexChanged: onIndexChanged,
itemCount: itemCount,
scrollDirection: scrollDirection,
axisDirection: axisDirection,
reversePan: true);

@override
State<StatefulWidget> createState() => _StackReverseViewState();
}

class _TinderState extends _CustomLayoutStateBase<_TinderSwiper> {
late List<double> scales;
late List<double> offsetsX;
Expand Down Expand Up @@ -972,6 +1025,89 @@ class _StackViewState extends _CustomLayoutStateBase<_StackSwiper> {
}
}

class _StackReverseViewState extends _CustomLayoutStateBase<_StackSwiper> {
late List<double> scales;
late List<double> offsets;
late List<double> opacity;

@override
void didChangeDependencies() {
super.didChangeDependencies();
}

void _updateValues() {
if (widget.scrollDirection == Axis.horizontal) {
final space = (_swiperWidth - widget.itemWidth!) / 2;
offsets = widget.axisDirection == AxisDirection.left
? [-space, -space / 3 * 2, -space / 3, 0.0, _swiperWidth]
: [_swiperWidth, 0.0, -space / 3, -space / 3 * 2, -space];
} else {
final space = (_swiperHeight - widget.itemHeight!) / 2;
offsets = [-space, -space / 3 * 2, -space / 2, 0.0, _swiperHeight];
}
}

@override
void didUpdateWidget(_StackSwiper oldWidget) {
_updateValues();
super.didUpdateWidget(oldWidget);
}

@override
void afterRender() {
super.afterRender();
final isRightSide = widget.axisDirection == AxisDirection.right;

//length of the values array below
_animationCount = 5;

//Array below this line, '0' index is 1.0, which is the first item show in swiper.
_startIndex = isRightSide ? -1 : -2;
scales =
isRightSide ? [1.0, 1.0, 0.9, 0.8, 0.7] : [0.7, 0.8, 0.9, 1.0, 1.0];
opacity =
isRightSide ? [1.0, 1.0, 1.0, 0.5, 0.0] : [0.0, 0.5, 1.0, 1.0, 1.0];

_updateValues();
}

@override
Widget _buildItem(int i, int realIndex, double animationValue) {
final s = _getValue(scales, animationValue, i);
final f = _getValue(offsets, animationValue, i);
final o = _getValue(opacity, animationValue, i);

final offset = widget.scrollDirection == Axis.horizontal
? widget.axisDirection == AxisDirection.left
? Offset(f, 0.0)
: Offset(-f, 0.0)
: Offset(0.0, -f);

final alignment = widget.scrollDirection == Axis.horizontal
? widget.axisDirection == AxisDirection.left
? Alignment.centerLeft
: Alignment.centerRight
: Alignment.topCenter;

return Opacity(
opacity: o,
child: Transform.translate(
key: ValueKey<int>(_currentIndex + i),
offset: offset,
child: Transform.scale(
scale: s,
alignment: alignment,
child: SizedBox(
width: widget.itemWidth ?? double.infinity,
height: widget.itemHeight ?? double.infinity,
child: widget.itemBuilder!(context, realIndex),
),
),
),
);
}
}

class ScaleAndFadeTransformer extends PageTransformer {
final double? _scale;
final double? _fade;
Expand Down
Loading

0 comments on commit cbbf0f6

Please sign in to comment.