Giter VIP home page Giter VIP logo

flutter_swipable_stack's Introduction

swipable_stack

pub.dev github likes popularity pub points license

A widget for stacking cards, which users can swipe horizontally and vertically with beautiful animations like Tinder UI.

demo

(Sorry, the package name swipable_stack is typo of swipeable stack)

Usage

builder

A SwipableStack uses a builder to display widgets.

SwipableStack(
  builder: (context, properties) {
    return Image.asset(imagePath);
  },
),

onSwipeCompleted

You can get completion event with onSwipeCompleted.

SwipableStack(
  onSwipeCompleted: (index, direction) {
    print('$index, $direction');
  },
)

overlayBuilder

You can show overlay on the front card with overlayBuilder.

SwipableStack(
  overlayBuilder: (context, properties) {
    final opacity = min(properties.swipeProgress, 1.0);
    final isRight = properties.direction == SwipeDirection.right;
    return Opacity(
      opacity: isRight ? opacity : 0,
      child: CardLabel.right(),
    );
  },
)

controller

SwipableStackController allows you to control swipe action & also rewind recent action.

final controller = SwipableStackController();

SwipableStack(
  controller:controller,
  builder: (context, properties) {
    return Image.asset(imagePath);
  },
);
controller.next(
  swipeDirection: SwipeDirection.right,
);
controller.rewind();

SwipableStackController provides to access currentIndex of SwipableStack.

final controller = SwipableStackController();
controller.addListener(() {
  print('${_controller.currentIndex}');
});

onWillMoveNext

You can also restrict user actions according to index or action with onWillMoveNext.

SwipableStack(
  onWillMoveNext: (index, direction) {
    final allowedActions = [
      SwipeDirection.right,
      SwipeDirection.left,
    ];
    return allowedActions.contains(direction);
  },
);

swipeAssistDuration

You can set the speed the user is able to swipe through Widgets with the swipeAssistDuration.

SwipableStack(
  swipeAssistDuration: Duration(milliseconds: 100),
)

The default is 650ms.

stackClipBehaviour

You can set the clipBehaviour of the stack with the stackClipBehaviour.
Change it to Clip.none to exceed the boundaries of parent widget size.

SwipableStack(
  stackClipBehaviour: Clip.none,
)

The default is Clip.hardEdge.

allowVerticalSwipe

Disable vertical swipe with allowVerticalSwipe.
Changing to false disable vertical swipe capabilities

SwipableStack(
  allowVerticalSwipe: false,
)

The default is true.

swipeTopAnchor

Set the swipe anchor with swipeAnchor with the following enum SwipeAnchor.top : card rotation on bottom and anchored on top SwipeAnchor.bottom : card rotation on top and anchored on bottom

SwipableStack(
  swipeAnchor: SwipeAnchor.top,
)

The default is SwipeAnchor.top.

flutter_swipable_stack's People

Contributors

asjadsiddiqui avatar envomer avatar heavenosk avatar kevsjh avatar maeddin avatar rogiervandenberg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

flutter_swipable_stack's Issues

How possible to return back removed widget

Hello, when we swap a widget and this widget removed, is it possible to widget back? like view pager , we can swap to right and see the new widget and after that, we can return to the old widget with a swap to left?
Which mean you see widget 1, 2, 3 by swap to right, Now by swap to left see widget 2

Stuck on Splash Screen When Running in Release

App gets stuck on splash Screen , means just showing a black screen. When added the package
Steps to reproduce

  1. Create a App and add the flutter swipable stack dependencies
  2. Run flutter run --relase It will work for only first time
  3. RUn flutter run --release , it will show blank screen

Not able to swipe any cards if building inside FutureBuilder.

If a build the SwipableStack inside FutureBuilder, I am not able to swipe the stack of individual widgets. The widgets to get rendered on screen but nothing happens if I try to drag them.

Expanded( flex: 15, child: Padding( padding: const EdgeInsets.all(10.0), child: FutureBuilder( future: Provider.of<Property>(context, listen: false) .fetchProperties(), builder: (ctx, snapShot) { if (snapShot.connectionState == ConnectionState.waiting) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const CircularProgressIndicator(), ], ); } else { return Consumer<Property>(builder: (bldctx, data, child) { return SwipableStack( swipeAnchor: SwipeAnchor.bottom, onSwipeCompleted: (index, direction) { print('$index, $direction'); }, stackClipBehaviour: Clip.none, onWillMoveNext: (index, direction) { if (direction == SwipeDirection.up) { showModalBottomSheet( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), context: context, builder: (ctx) { return Container( child: Center( child: Text('Dummy Text'), ), ); }); } final allowedActions = [ SwipeDirection.right, SwipeDirection.left, ]; return allowedActions.contains(direction); }, controller: _controller, itemCount: data.properties.length, builder: (ctxt, props) { return ClipRRect( borderRadius: BorderRadius.circular(8.0), child: data.properties[props.index].thumbnailId != null ? Image.network( '${CommonEndpoints.assetUrl}/${data.properties[props.index].thumbnailId!.files!.elementAt(0)}', fit: BoxFit.cover, ) : null, ); }); }); } }, // child: , ), ), )

The swipeable stack works if use List made of imageUrls, but widgets is undraggable after async call.

Callback for empty stack?

It should have a mechanism to pull more data to fill the stack once the stack is empty.
Like pagination.

Cards rebuilding constantly.

Hey, looks like all cards are rebuilding all the time as the user is dragging/as builder gets called. Seems like all children in the card are getting rebuilt. Can't quite figure it out, is there some magic with keys where all children are not really rebuilding, even though their build method is being called?

Some Improvements

  • Reduce unnecessary state update
  • Improve cancel animation
  • Use StateNotifier instead of ChangeNotifier for SwipableStackController

typo in changelog.md

Hi @HeavenOSK

First of, thanks for the mentioned.

I noticed a typo in the changelog.md that is dropping the package points on pub.dev

image

How to set shouldCallCompletionCallback to false ?

Big thanks for the package. I am learning how to use it. :)

I tried this:
/// You can reject [SwipableStack.onSwipeCompleted] invocation by
/// setting [shouldCallCompletionCallback] to false.

I tried this on line 179 onwards in the example main.dart

_BottomButton(
color: SwipeDirectionColor.up,
onPressed: () {
_controller.next(
swipeDirection: SwipeDirection.up,
shouldCallCompletionCallback: false ,
);
},
child: const Icon(Icons.arrow_upward),
),

However, when I swipe up, the text "UP" appears as desired. Then it ... moves to the next card of the stack. I thought that this property change would keep the same card on a up swipe and just make the label chnage from opacity cannot see to opacity appear. The examples i found where unclear on how to properly set the property shouldCallCompletionCallback to false

Could you provide a code example?
do I understand the expected behavior right?

thanks

onSwipeCompleted not call in Release mode [Android]

Hi,

I used your package and it's amazing. I really appreciate your work.

I face one issue in release mode.
I run app in release mode flutter run --release then onSwipaCompleted method not called so I can't set action on that. but in debug mode this is working fine.

can you please tell me what's wrong?

I used latest version of this package : swipable_stack: ^2.0.0

even I copy whole code from your example then that also face same issue.
In debug work perfect but not work in release mode

Thanks in Advance

How to completely disable manual swipe?

I'd like to completely remove the manual swipe, so I can do it using the controller when the buttons are pressed.
Currently, we can set detectableSwipeDirections with an empty Set, but this still allows to user to initiate the swipe.

How do I reset the stack?

When users have swiped all the cards in stack, I want to let them choose to restart (swipe from the first card). controller has only one method to rewind the last action not all the way back to the first card

Invalid value: Not in inclusive range

Hi,

I recently noticed that the package has a new version (0.8.0) so I decided to update from version 0.7.1 to 0.8.0.

Now I got this error when I swipe first card:

The following RangeError was thrown building LayoutBuilder:
RangeError (index): Invalid value: Not in inclusive range 0..2: 3

The relevant error-causing widget was: 
  SwipableStack-[LabeledGlobalKey<_SwipableStackState>#fa547] file:///[MY_PROJECT]/lib/src/ui/screens/home/home.dart:74:12
When the exception was thrown, this was the stack: 
#0      List.[] (dart:core-patch/growable_array.dart:254:60)
#1      _HomeScreenState._swipeableContent.<anonymous closure> (package:[MY_PROJECT]/src/ui/screens/home/home.dart:81:34)
#2      _SwipableStackState._buildCards.<anonymous closure> (package:swipable_stack/src/swipable_stack.dart:395:37)
#3      new _GrowableList.generate (dart:core-patch/growable_array.dart:133:28)
#4      _SwipableStackState._buildCards (package:swipable_stack/src/swipable_stack.dart:391:19)

I can confirm that with version 0.7.1 the code and package works perfectly :)

PS: I can bring more code or info if needed.

Allow multiple Rewind

Hey there I used the rewind() function to rewind to a previous card but it only goes 1 card back. How can I achieve more rewind. Currently using controller.currentIndex to set to previous card.

Empty placeholder

Hi!
Great package, thanks. would be great, if there would be a property for customization of the empty state, when the stack is empty:
image

Currently by default it shows empty container, a placeholder "Sorry, no more profile for you", or something like that,

Or any workaround?

Grey screen in release

When I run the project in debug mode it works fine but in release mode, it shows a grey screen as it looks in attached image
image

Stack direction

Hi

I can see the cards in the stack painted below the current card. Is there a way to move the back cards to be poking out of the top so the cards are falling down the page?

Aka this part:

image

Draw that along the top and the right, not just the right?

Card swipe going under the container

When there's a container on width 500px, the card swipe going under the container? Probably a zindex issue?

Widget build(BuildContext context) {
    return Scaffold(
      appBar: _buildAppBar(),
      body: Center(
        child: Container(
          constraints: BoxConstraints(
            minWidth: 300,
            maxWidth: 500,
            maxHeight: 730,
          ),
          padding: EdgeInsets.all(10),
          child: SwipeableStack(
            controller: _controller,
            onSwipeCompleted: (index, direction) {
              print('$index, $direction');
            },
            builder: (context, index, constraints) {
              final Post post = posts[index];
              return ProfileCard(
                post: post,
              );
            },
            itemCount: posts.length,
          ),
        ),
      ),
      bottomNavigationBar: _buildBottomBar(),
    );
  }
}

bug_swpe

How to disable repeating stack items?

child: SwipableStack(
detectableSwipeDirections: const {
SwipeDirection.right,
SwipeDirection.left,
SwipeDirection.up,
},
controller: _controller,
stackClipBehaviour: Clip.none,
onSwipeCompleted: (index, direction) {
totalListCount = index;

                            if (direction == SwipeDirection.left) {

                              Provider.of<UserStore>(context, listen: false)
                                  .updateForgroundImage(
                                      imagePath('crossblue'));
                              reaction("dismiss", currentUser, index);
                            }
                            if (direction == SwipeDirection.right) {
                              reaction("like", currentUser, index);
                              Provider.of<UserStore>(context, listen: false)
                                  .updateForgroundImage(
                                      imagePath('heartred'));
                            }
                            if (direction == SwipeDirection.up) {
                              Navigator.push(
                                  context,
                                  MaterialPageRoute(
                                      builder: (context) => UserProfile(
                                            userOrOther: true,
                                            user: currentUser,
                                          )));
                            }
                          },
                          horizontalSwipeThreshold: 0.8,
                          verticalSwipeThreshold: 0.8,
                          builder: (context, properties) {
                            // properties.constraints.
                            final itemIndex =
                                properties.index % matchList.length;
                            listIndex = properties.index % matchList.length;

                            print(
                                'itemCountController::${_controller.currentIndex}');

                            return (matchList.length > 0)
                                ? Stack(
                                    children: [
                                      ExampleCard(
                                        list: matchList,
                                        userData: matchList[itemIndex],
                                        assetPath: matchList[itemIndex]
                                            .profile_picture,
                                        currentUser: currentUser,
                                      ),
                                      // more custom overlay possible than with overlayBuilder
                                      if (properties.stackIndex == 0 &&
                                          properties.direction != null)
                                        CardOverlay(
                                          swipeProgress:
                                              properties.swipeProgress,
                                          direction: properties.direction,
                                        )
                                    ],
                                  )
                                : Container();
                          },
                        ),
                    )

reaction(String reaction, User opponent, int index) async {
print(HelpingMethods().getChannelId(user.id, opponent.id));

bool res = await Provider.of<UserStore>(context, listen: false)
    .sendReaction(context, reaction, opponent.id.toString());

if (res) {
  Provider.of<UserStore>(context, listen: false).removeMatchAt(index);
}

Provider.of<UserStore>(context, listen: false).updateForgroundImage('');

}

Video Card

Hello team, If I placed a short video instead of Image, then when I swipe the video it keeps on playing with sound. That means it is not destroying the video widget. Any workaround?

Widget breaks when card gets dragged to the left: "simulationDuration > Duration.zero is not true"

Whenever I drag a card to the left the entire widget breaks with the following:

I/flutter ( 9115): {exception: _AssertionError, message: 'package:flutter/src/animation/animation_controller.dart': Failed assertion: line 610 pos 12: 'simulationDuration > Duration.zero': is not true.}

Another exception was thrown: 'package:flutter/src/animation/animation_controller.dart': Failed assertion: line 610 pos 12: 'simulationDuration > Duration.zero': is not true.

This doesn't happen in any other direction.

Once it's broken other errors start appearing:

โ•โ•โ•ก EXCEPTION CAUGHT BY RENDERING LIBRARY โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
The following assertion was thrown during performLayout():
'package:flutter/src/rendering/object.dart': Failed assertion: line 1840 pos 12:
'!_debugDoingThisLayout': is not true.

Either the assertion indicates an error in the framework itself, or we should provide substantially
more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.md

The relevant error-causing widget was:
  Stack
  Stack:file:///home/bart/.pub-cache/hosted/pub.dartlang.org/swipable_stack-1.3.0/lib/src/swipable_stack.dart:386:18

Can't import ItemSwipeProperties

The only way I found to import ItemSwipeProperties is by importing it directly from src

import 'package:swipable_stack/src/model/swipe_properties.dart';

SwipableStack(
  builder: (BuildContext context, ItemSwipeProperties properties) {
    ...
  }
}

Problem with end of stack

Hi, I have a problem when end of the stack came. I implemented two ways but I didn't success.

Following this issue #12 I added a listener like you suggested:

    _controller = SwipableStackController()
      ..addListener(() {
        if (_users.length - 1 <= _controller.currentIndex) {
          print('loading more users');
        }
        setState(() {});
      });

But when the last card is being swiped then listener is executed extremely times:

11 I[/flutter]() ( 6322): loading more users
11 I[/flutter]() ( 6322): loading more users
11 I[/flutter]() ( 6322): loading more users
11 I[/flutter]() ( 6322): loading more users

I thought: ok, so when the last card is shown I can use onSwipeCompleted callback to reset currentItem = 0 but didn't work because the library internally execute +1 on currentIndex, then SwipableStack shows again the last card.

Is there a solution for this problem?.

Thank you!!

Add an updateCallback for SwipeableStack

I have a suggestion but first - Thanks for a great component.

Can we add an onSwipeUpdate callback that is passed SwipeDirection and SwipeProgress or else add them to the SwipableStackController ?

These values should be part of the controller so that the controller can be used in other Widgets (I need to provide additionally animation when a card is moved).

Currently the only way to get access to these values is via the OverlayBuilder which causes rebuild issues if animation is triggered from that callback.

Ideally we should have either the SwipableStackController enriched with these values or else provide an onSwipeUpdate(properties) callback.

Change the spread of background cards

Hi, I have a question, is there a way to change the spread of background cards?. I would like to change it to zero. I mean, just one photo on top of stack without using fullscreen image or Positioned.fill .

image

Thank you!

[Swipe Gesture] problem onComplete works but cards do not move

My layout is something like this

selector
_stack
__swipable stack

selector as data load after an api call and is passed to item count parameter

Problem:
sometime swipe has not effect on ui cards do not move
but my onComplete function prints and shows the sipedirection.

and if i hot reload it starts working again

Swipe Animation lagging

Hi! Is there any chance that i can fix the lagging while user swiping? I think it is because of the animation or maybe the perfomance of the lib. Is there any way that i can solve this issue? Because this library is awesome, also unuseable because of the lagging(tearing). Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.