Giter Site home page Giter Site logo

yalantis / koloda Goto Github PK

View Code? Open in Web Editor NEW
5.3K 143.0 802.0 48.46 MB

KolodaView is a class designed to simplify the implementation of Tinder like cards on iOS.

Home Page: https://yalantis.com

License: MIT License

Swift 98.22% Ruby 1.15% Objective-C 0.62%
ios swift kolodaview animation cocoapods collectionview koloda cards custom-layout yalantis

koloda's Introduction

KolodaView cocoapodsCarthage compatible Swift 5.0

Yalantis

Our designer Dmitry Goncharov decided to create an animation that follows Tinder’s trend. We called our Tinder-style card-based animation Koloda which is a Ukrainian word for the deck (of cards). The component can be used in different local event apps, and even in Tinder if it adds a possibility to choose dating places. The concept created by Dmitriy was implemented by Eugene Andreyev, our iOS developer.

Preview Preview

Purpose

KolodaView is a class designed to simplify the implementation of Tinder like cards on iOS. It adds convenient functionality such as a UITableView-style dataSource/delegate interface for loading views dynamically, and efficient view loading, unloading .

Supported OS & SDK Versions

  • Supported build target - iOS 11.0 (Xcode 9)

ARC Compatibility

KolodaView requires ARC.

Thread Safety

KolodaView is subclassed from UIView and - as with all UIKit components - it should only be accessed from the main thread. You may wish to use threads for loading or updating KolodaView contents or items, but always ensure that once your content has loaded, you switch back to the main thread before updating the KolodaView.

Prototype of Koloda in Pixate

Our designer created the mock-up in Photoshop and used Pixate for prototyping Koloda. The prototype we created reproduced the behavior of cards exactly how we wanted it.

The main Pixate toolset includes layers, an action kit, and animations. After the assets are loaded and located on the artboard, you can start working on layers, and then proceed to reproduce interactions.

At first, we made the cards move horizontally and fly away from the screen once they cross a certain vertical line. The designer also made the cards change their transparency and spin a bit during interactions.

Then, we needed to make a new card appear in a way as if it collects itself from the background, so we had to stretch and scale it. We set a scale for the prototype from 3.5x (the size, when a card is still on the background) to 1x.

Preview

For a better effect, we added a few bounce animations and that was it! The prototype was ready for development.

Building Koloda animation

There are a few ready-made mobile libraries and iOS animation examples out there that an app developer can use.

We wanted the animation to be as simple and convenient as views like UITableView. Therefore, we created a custom component for the animation. It consists of the three main parts:

  1. DraggableCardView – a card that displays content.
  2. OverlayView – a dynamic view that changes depending on where a user drags a card (to the left or to the right).
  3. KolodaView – a view that controls loading and interactions between cards.

DraggableCardView implementation

We implemented DraggableCardView with the help of UIPanGestureRecognizer and CGAffineTransform. See the coding part below:

func panGestureRecognized(gestureRecognizer: UIPanGestureRecognizer) {
    xDistanceFromCenter = gestureRecognizer.translationInView(self).x
    yDistanceFromCenter = gestureRecognizer.translationInView(self).y

    let touchLocation = gestureRecognizer.locationInView(self)
    switch gestureRecognizer.state {
    case .Began:
        originalLocation = center

        animationDirection = touchLocation.y >= frame.size.height / 2 ? -1.0 : 1.0      
        layer.shouldRasterize = true
        break

    case .Changed:

        let rotationStrength = min(xDistanceFromCenter! / self.frame.size.width, rotationMax)
        let rotationAngle = animationDirection! * defaultRotationAngle * rotationStrength
        let scaleStrength = 1 - ((1 - scaleMin) * fabs(rotationStrength))
        let scale = max(scaleStrength, scaleMin)

        layer.rasterizationScale = scale * UIScreen.mainScreen().scale
 
        let transform = CGAffineTransformMakeRotation(rotationAngle)
        let scaleTransform = CGAffineTransformScale(transform, scale, scale)

        self.transform = scaleTransform
        center = CGPoint(x: originalLocation!.x + xDistanceFromCenter!, y: originalLocation!.y + yDistanceFromCenter!)
           
        updateOverlayWithFinishPercent(xDistanceFromCenter! / frame.size.width)
        //100% - for proportion
        delegate?.cardDraggedWithFinishPercent(self, percent: min(fabs(xDistanceFromCenter! * 100 / frame.size.width), 100))

        break
    case .Ended:
        swipeMadeAction()

        layer.shouldRasterize = false
    default:
        break
    }
}

The overlay gets updated with every move. It changes transparency in the process of animation ( 5% – hardly seen, 100% – clearly seen).

In order to avoid a card’s edges becoming sharp during movement, we used the shouldRasterize layer option.

We had to consider a reset situation which happens once a card fails to reach the action margin (ending point) and comes back to the initial state. We used the Facebook Pop framework for this situation, and also for the “undo” action.

OverlayView implementation

OverlayView is a view that is added on top of a card during animation. It has only one variable called overlayState with two options: when a user drags a card to the left, the overlayState adds a red hue to the card, and when a card is moved to the right, the variable uses the other option to make the UI become green.

To implement custom actions for the overlay, we should inherit from OverlayView, and reload the operation didSet in the overlayState:

public enum OverlayMode{
   case None
   case Left
   case Right
}

public class OverlayView: UIView {
    public var overlayState:OverlayMode = OverlayMode.None
}

class ExampleOverlayView: OverlayView {
override var overlayState:OverlayMode  {
    didSet {
        switch overlayState {
           case .Left :
               overlayImageView.image = UIImage(named: overlayLeftImageName)
           case .Right :
               overlayImageView.image = UIImage(named: overlayRightImageName)
           default:
               overlayImageView.image = nil
           }          

       }

   }

}

KolodaView implementation

The KolodaView class does a card loading and card management job. You can either implement it in the code or in the Interface Builder. Then, you should specify a data source and add a delegate (optional). After that, you should implement the following methods of the KolodaViewDataSource protocol in the data source-class:

func kolodaNumberOfCards(koloda: KolodaView) -> UInt
    func kolodaViewForCardAtIndex(koloda: KolodaView, index: UInt) -> UIView
    func kolodaViewForCardOverlayAtIndex(koloda: KolodaView, index: UInt) -> OverlayView?

KolodaView had to display a correct number of cards below the top card and make them occupy the right positions when the animation starts. To make it possible, we had to calculate frames for all the cards by adding the corresponding indexes to each element. For example, the first card has an [i] index, the second one would have an [i+1] index, the third – [i+2], and so on:

private func frameForCardAtIndex(index: UInt) -> CGRect {
    let bottomOffset:CGFloat = 0
    let topOffset = backgroundCardsTopMargin * CGFloat(self.countOfVisibleCards - 1)
    let xOffset = backgroundCardsLeftMargin * CGFloat(index)
    let scalePercent = backgroundCardsScalePercent
    let width = CGRectGetWidth(self.frame) * pow(scalePercent, CGFloat(index))
    let height = (CGRectGetHeight(self.frame) - bottomOffset - topOffset) * pow(scalePercent, CGFloat(index))
    let multiplier: CGFloat = index > 0 ? 1.0 : 0.0
    let previousCardFrame = index > 0 ? frameForCardAtIndex(max(index - 1, 0)) : CGRectZero
    let yOffset = (CGRectGetHeight(previousCardFrame) - height + previousCardFrame.origin.y + backgroundCardsTopMargin) * multiplier
    let frame = CGRect(x: xOffset, y: yOffset, width: width, height: height)     

    return frame
}

Now, since we know the indexes, card frames, and also the percent at which the animation ends (from the DraggableCardView), we can easily find out where the cards below will go once an upper card is swiped. After that, we can implement PercentDrivenAnimation.

Building Koloda v.2

The main difference between the first and second versions of the Koloda animation is in the cards’ layout. The front card in the new version is placed in the middle of the screen and the back card is stretched on the background. In addition, the back card does not respond to the movement of the front card and arrives with a bounce effect after the front card is swiped.

Also, the second version of Koloda was easier to build thanks to the prototype of it in Pixate.

Preview

Implementation of KolodaView v.2

To implement KolodaView v.2, we had to place the cards differently, so we put the method frameForCardAtIndex in the public interface.

In KolodaView inheritor we overrode the method and put the cards in the following order:

override func frameForCardAtIndex(index: UInt) -> CGRect {
    if index == 0 {
        let bottomOffset:CGFloat = defaultBottomOffset
        let topOffset:CGFloat = defaultTopOffset
        let xOffset:CGFloat = defaultHorizontalOffset
        let width = CGRectGetWidth(self.frame ) - 2 * defaultHorizontalOffset
        let height = width * defaultHeightRatio
        let yOffset:CGFloat = topOffset
        let frame = CGRect(x: xOffset, y: yOffset, width: width, height: height)
        return frame
    } else if index == 1 {
        let horizontalMargin = -self.bounds.width * backgroundCardHorizontalMarginMultiplier
        let width = self.bounds.width * backgroundCardScalePercent
        let height = width * defaultHeightRatio
        return CGRect(x: horizontalMargin, y: 0, width: width, height: height)
    }
    return CGRectZero
}

We place frontCard in the middle of KolodaView, and stretch the background card with a scalePercent that equals 1.5.

Preview

Bounce animation for the background card

Since the background card arrives with a bounce effect and changes its transparency while moving, we created a new delegate method:

KolodaView - func kolodaBackgroundCardAnimation(koloda: KolodaView) -> POPPropertyAnimation?

In this method, POPAnimation is created and passed to Koloda. Then, Koloda uses it for animating frame changes after a user swipes a card. If the delegate returns nil, it means that Koloda uses default animation.

Below you can see the implementation of this method in the delegate:

func kolodaBackgroundCardAnimation(koloda: KolodaView) -> POPPropertyAnimation? {
    let animation = POPSpringAnimation(propertyNamed: kPOPViewFrame)
    animation.springBounciness = frameAnimationSpringBounciness
    animation.springSpeed = frameAnimationSpringSpeed
    return animation
}

Installation

To install via CocoaPods add this lines to your Podfile. You need CocoaPods v. 1.1 or higher

use_frameworks!
pod "Koloda"

To install via Carthage add this lines to your Cartfile

github "Yalantis/Koloda"

To install manually the KolodaView class in an app, just drag the KolodaView, DraggableCardView, OverlayView class files (demo files and assets are not needed) into your project. Also you need to install facebook-pop. Or add bridging header if you are using CocoaPods.

Usage

  1. Import Koloda module to your MyKolodaViewController class

    import Koloda
  2. Add KolodaView to MyKolodaViewController, then set dataSource and delegate for it

    class MyKolodaViewController: UIViewController {
        @IBOutlet weak var kolodaView: KolodaView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            kolodaView.dataSource = self
            kolodaView.delegate = self
        }
    }
  3. Conform your MyKolodaViewController to KolodaViewDelegate protocol and override some methods if you need, e.g.

    extension MyKolodaViewController: KolodaViewDelegate {
        func kolodaDidRunOutOfCards(_ koloda: KolodaView) {
            koloda.reloadData()
        }
    
        func koloda(_ koloda: KolodaView, didSelectCardAt index: Int) {
            UIApplication.shared.openURL(URL(string: "https://yalantis.com/")!)
        }
    }
  4. Conform MyKolodaViewController to KolodaViewDataSource protocol and implement all the methods , e.g.

    extension MyKolodaViewController: KolodaViewDataSource {
    
        func kolodaNumberOfCards(_ koloda:KolodaView) -> Int {
            return images.count
        }
    
        func kolodaSpeedThatCardShouldDrag(_ koloda: KolodaView) -> DragSpeed {
            return .fast
        }
    
        func koloda(_ koloda: KolodaView, viewForCardAt index: Int) -> UIView {
            return UIImageView(image: images[index])
        }
    
        func koloda(_ koloda: KolodaView, viewForCardOverlayAt index: Int) -> OverlayView? {
            return Bundle.main.loadNibNamed("OverlayView", owner: self, options: nil)[0] as? OverlayView
        }
    }
  5. KolodaView works with default implementation. Override it to customize its behavior

Also check out an example project with carthage.

Properties

The KolodaView has the following properties:

weak var dataSource: KolodaViewDataSource?

An object that supports the KolodaViewDataSource protocol and can provide views to populate the KolodaView.

weak var delegate: KolodaViewDelegate?

An object that supports the KolodaViewDelegate protocol and can respond to KolodaView events.

private(set) public var currentCardIndex

The index of front card in the KolodaView (read only).

private(set) public var countOfCards

The count of cards in the KolodaView (read only). To set this, implement the kolodaNumberOfCards: dataSource method.

public var countOfVisibleCards

The count of displayed cards in the KolodaView.

Methods

The KolodaView class has the following methods:

public func reloadData()

This method reloads all KolodaView item views from the dataSource and refreshes the display.

public func resetCurrentCardIndex()

This method resets currentCardIndex and calls reloadData, so KolodaView loads from the beginning.

public func revertAction()

Applies undo animation and decrement currentCardIndex.

public func applyAppearAnimationIfNeeded()

Applies appear animation if needed.

public func swipe(_ direction: SwipeResultDirection, force: Bool = false)

Applies swipe animation and action, increment currentCardIndex.

open func frameForCard(at index: Int) -> CGRect

Calculates frames for cards. Useful for overriding. See example to learn more about it.

Protocols

The KolodaView follows the Apple convention for data-driven views by providing two protocol interfaces, KolodaViewDataSource and KolodaViewDelegate.

The KolodaViewDataSource protocol has the following methods:

func koloda(_ kolodaNumberOfCards koloda: KolodaView) -> Int

Return the number of items (views) in the KolodaView.

func koloda(_ koloda: KolodaView, viewForCardAt index: Int) -> UIView

Return a view to be displayed at the specified index in the KolodaView.

func koloda(_ koloda: KolodaView, viewForCardOverlayAt index: Int) -> OverlayView?

Return a view for card overlay at the specified index. For setting custom overlay action on swiping(left/right), you should override didSet of overlayState property in OverlayView. (See Example)

func kolodaSpeedThatCardShouldDrag(_ koloda: KolodaView) -> DragSpeed

Allow management of the swipe animation duration

The KolodaViewDelegate protocol has the following methods:

func koloda(_ koloda: KolodaView, allowedDirectionsForIndex index: Int) -> [SwipeResultDirection]

Return the allowed directions for a given card, defaults to [.left, .right]

func koloda(_ koloda: KolodaView, shouldSwipeCardAt index: Int, in direction: SwipeResultDirection) -> Bool

This method is called before the KolodaView swipes card. Return true or false to allow or deny the swipe.

func koloda(_ koloda: KolodaView, didSwipeCardAt index: Int, in direction: SwipeResultDirection)

This method is called whenever the KolodaView swipes card. It is called regardless of whether the card was swiped programatically or through user interaction.

func kolodaDidRunOutOfCards(_ koloda: KolodaView)

This method is called when the KolodaView has no cards to display.

func koloda(_ koloda: KolodaView, didSelectCardAt index: Int)

This method is called when one of cards is tapped.

func kolodaShouldApplyAppearAnimation(_ koloda: KolodaView) -> Bool

This method is fired on reload, when any cards are displayed. If you return YES from the method or don't implement it, the koloda will apply appear animation.

func kolodaShouldMoveBackgroundCard(_ koloda: KolodaView) -> Bool

This method is fired on start of front card swipping. If you return YES from the method or don't implement it, the koloda will move background card with dragging of front card.

func kolodaShouldTransparentizeNextCard(_ koloda: KolodaView) -> Bool

This method is fired on koloda's layout and after swiping. If you return YES from the method or don't implement it, the koloda will transparentize next card below front card.

func koloda(_ koloda: KolodaView, draggedCardWithPercentage finishPercentage: CGFloat, in direction: SwipeResultDirection)

This method is called whenever the KolodaView recognizes card dragging event.

func kolodaSwipeThresholdRatioMargin(_ koloda: KolodaView) -> CGFloat?

Return the percentage of the distance between the center of the card and the edge at the drag direction that needs to be dragged in order to trigger a swipe. The default behavior (or returning NIL) will set this threshold to half of the distance

func kolodaDidResetCard(_ koloda: KolodaView)

This method is fired after resetting the card.

func koloda(_ koloda: KolodaView, didShowCardAt index: Int)

This method is called after a card has been shown, after animation is complete

func koloda(_ koloda: KolodaView, didRewindTo index: Int)

This method is called after a card was rewound, after animation is complete

func koloda(_ koloda: KolodaView, shouldDragCardAt index: Int) -> Bool

This method is called when the card is beginning to be dragged. If you return YES from the method or don't implement it, the card will move in the direction of the drag. If you return NO the card will not move.

Release Notes

Version 5.0.1

  • added posibility to determine index of rewound card
  • fixed crash after drugging card

Version 5.0

Version 4.7

  • fixed a bug with card responding during swiping via @lixiang1994
  • fixed a bug with inappropriate layouting via @soundsmitten

Version 4.6

Version 4.5

Version 4.4

Version 4.3

  • Swift 4 support
  • iOS 11 frame bugfix

Version 4.0

  • Swift 3 support
  • Get rid of UInt
  • Common bugfix

Version 3.1

  • Multiple Direction Support
  • Delegate methods for swipe disabling

Version 3.0

  • Ability to dynamically insert/delete/reload specific cards
  • External animator
  • Major refactoring. More information
  • Swift 2.2 support

Version 2.0

  • Swift 2.0 support

Version 1.1

  • New delegate methods
  • Fixed minor issues

Version 1.0

  • Release version.

Apps using KolodaView

Preview

Let us know!

We’d be really happy if you sent us links to your projects where you use our component. Just send an email to [email protected] And do let us know if you have any questions or suggestion regarding the animation.

P.S. We’re going to publish more awesomeness wrapped in code and a tutorial on how to make UI for iOS (Android) better than better. Stay tuned!

License

The MIT License (MIT)

Copyright © 2019 Yalantis

Permission is hereby granted free of charge to any person obtaining a copy of this software and associated documentation files (the "Software") to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

koloda's People

Contributors

aeugene avatar alarin avatar andrewios avatar briansunter avatar brownsoo avatar carbocation avatar edbaev avatar felix-dumit avatar iosyalantislushchan avatar krjackso avatar lasha-ring avatar lixiang1994 avatar lukaszielinski1234 avatar maximletushov avatar maxxfrazer avatar naoyashiga avatar noordawod avatar pravdaevgen avatar readmecritic avatar rishabhtayal avatar rnkyr avatar sebastianludwig avatar sebastianosinski avatar serejahh avatar sergey-prikhodko avatar shytyk avatar sjoness avatar tykhonkov avatar vodolazkyi avatar vvit 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  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

koloda's Issues

Cannot load underlying module for 'Koloda'

Hello, I'm new to ios dev but everytime I try the import Koloda statement I get this. I'm testing on xcode 7.1 and used the suggested line for cocoapods, actually I figured it out

Feature Request: kolodaViewCard:isDraggingInDirection:

Love the framework. My only suggestion is, there should be a way to know which way a card is being dragged. This would allow greater integration in a UI, i,e: I can show specific UI elements based on if the user is dragging to the left as opposed to the right. If someone could implement that and do a pull request would be great.

Suggestion

I would suggest to add resetCurrentCardNumber() to reloadData() or at least leave a line of explanation of that in the documentation. Great library by the way.

Allow Going "Backwards"

I have a use case where I am using Koloda to show a series of graphs. In this instance we would like swiping right to go to the "next" graph and swiping left to go to the "previous" graph. The current behavior is that swiping in either direction goes to the next graph. Is there a current workaround?

Card resizes in a strange way on pan

When I pan out a card, the size of the whole card decreases. The problem i'm having is the size of the card is increasing / decreasing not in proportion with the view inside.

The easiest way to show is to checkout a test repo I made. Ignore the first 3 cards as they are not the correct size. This branch was taken from master and i've just changed the DataSource method kolodaViewForCardAtIndex to display a view and removed the buttons from the story board.

https://github.com/lunswor/test_koloda

When swiping (swipe left shows this best) you can see the red view separates from the blue view and the width of the blue view increases too. This causes a strange appearance within my app.

Maybe i'm just doing something wrong?

Adding multiple @IBActions to Card View

AS of now DidSelectCardAtIndex function fires if anywhere on view is tapped, however I want add couple of buttons on the cardview that if tapped take the data at the current index and save it to the cloud using a function. how can I achieve the IBaction objects?

I essentially want to add two UIimage views that are clickable. I tried to add clear view with UItapgesture in the background view but blocks the swipe action.

I hope my question made sense.

Errors when trying to run

Hi. I tried to run this code on my own project and I got these 2 errors. I've linked up the outlets as per the example project but i'm not able to get it to work

2015-10-05 18:51:25.093 JobHunt[10995:5221329] Unknown class _TtC14Koloda_Example18ExampleOverlayView in Interface Builder file.
2015-10-05 18:51:25.152 JobHunt[10995:5221329] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIView 0x7fe47b637900> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key overlayImageView.'

Animate transparency of background card

I would suggest to enhance the appearance in case that fun kolodaShouldMoveBackgroundCard(koloda: KolodaView) -> Bool and fun kolodaShouldTransparentizeNextCard(koloda: KolodaView) -> Bool both return true.

The appearance of the background card should receive opacity of 1.0 dependent on the "percentage" of the current swipe.

fatal error: unexpectedly found nil while unwrapping an Optional value

when compiler execute this function which is called in viewDidLoad() before Koloda dataSource and delegate have their values
it crashes and shows me the message above

the function loads the new users from Parse
the decleration of the function is :

func loadNewUser()
{

    let query = PFQuery(className: "_User")

    switch (query)
    {
    case query.whereKey("verifiedToLogin", notEqualTo: true):
        fallthrough
    case query.whereKey("verifiedToLogin", notEqualTo: false):
        fallthrough
    default:
        arr = NSArray(array: query.findObjects()!)
       numberOfCards = UInt(arr.count)
        break
    }
    print("Array has \(arr.count) elements")
    kolodaView.reloadData()
}

I tried to set "numberOfCards = UInt(arr.count)" as a comment but it still crashes
& shows me that message

Card unresponsive when it is animating back to the center

Currently, when the user drags a card a short way and releases, the card animates back to the center. During this reset animation, the user cannot interact with the card. This can be frustrating to the user because the app feels (and, in fact, is) unresponsive during this time.

Due to this, I have created a proposed change ( #33 ) that allows users to interact with the card as soon as it is released, even if it is still animating. There may be better approaches, however.

EXC_BAD_ACCESS on Swift 2.0

Dear Yalantis,

I'm using Swift 2.0 + Xcode 7.0 GM seed, with the swift2.0 branch of Koloda.
I get an EXC_BAD_ACCESS error for:
self.kolodaView.dataSource = self
self.kolodaView.delegate = self

Here is a screenshot:
screen shot 2015-09-16 at 4 07 55 pm

Thanks!

Erik

Include of non-modular header inside framework module

This error seems to have popped up again. Cocoapods is up to date, and this is an attempt to compile the included Example from a fresh download of the Koloda Master.

untitled

Strangely, this error does not occur when compiling in Xcode 7.1 Beta 3 (7B60), only in Xcode 7.1 Stable (7B91b).

Is there any way to know if dragging action is reset?

Reading the code in DraggableCardView, there is a method "swipeMadeAction" which call "resetViewPositionAndTransformations" when the dragging action is reset (i.e. it isn't completed) and call delegate method "cardWasReset".
This delegate is implemented on Koloda class. Is possibile to know if dragging actions is reset?

I didn't find any Koloda delegate's method to achieve it. Thanks

this is a question, as a Newbie.

I wanted to try using this with data from parse.com, I'm familiar with pulling data in tableview controller using cellforrowatindexpath and updating tableview cell, is there something similar way to achieve that with Koloda. The example uses static images, but i want to populate a view from data from parse.com and update each card accoringly (label, uiimageview) .

Background cards are misplaced

In some situations the background cards don't follow a vanishing line. This can be caused by non-rectangular cards or off-centered placement of the koloda view (IIRC). Anyway, the easiest step to reproduce is to set the backgroundCardsScalePercent to 0.9.

Expected

screen shot 2015-10-26 at 15 27 43

Actual

screen shot 2015-10-26 at 15 25 37

How to hide elements for background animation

I have been looking at the demo application and their you animate the next card into the background. I was wondering if it's possible to do this but in the meantime hide some elements of this card while this animation happens.

I am having a card similar to one in your demo. Only I am having some text in the top left corner of the card which is now being shown in the background. I prefer to hide all the textual elements and only show the background image.

What's the easiest approach to do this?

Currently visible card never has correct frame height

First off, just wanted to say thanks for putting this awesome repo together. I'm using the defaults that come with KolodaView and one thing I've noticed is that if backgroundCardsTopMargin is set to anything other than zero, then the visible card never has the correct frame.

When using the backgroundCardsTopMargin default of 4 that comes with KolodaView, my card has a height of 307 instead of the correct value I have set which is 315.

I love the visual effect that you can achieve by using backgroundCardsTopMargin, it's really cool being able to see a little bit of the cards that are behind the currently visible one, but at the same time we cannot allow this to actually modify the visible card's frame height.

Can we try and find a way to still allow for the same visual effect but keep the correct frame height for the visible card?

change background cards alpha value

I want to decrease the transparent(increase alpha value to 0.8) of cards which are in the backgrounds behind the first card?
their alpha values become less when I swipe to anywhere or clicked on any button
I want to make them like the first card (explained in the first photo below)!

So, how to...please???

simulator screen shot dhu l-q 7 1436 ah 12 17 35 am
simulator screen shot dhu l-q 7 1436 ah 12 17 40 am

Error with cocoapods

I cannot fix this issue! I'me getting this error

`s/Mako/Pods/pop/pop/POP.h:27:9: Include of non-modular header inside framework module 'pop.POP'``
image

Swipe Down on a card

Hello,

I shall really appreciate if you can just guide me a little on how can I modify the code in DraggableCardView.swift to add a downwards swipe also.. with all delegate callbacks and overlay etc?

Thanks

Never mind. I actually figured it out myself. Wish I could delete an issue.

Work with Objective-C?

I'd like to use this library in a project that's currently mostly Objective-C.

I integrate the project with Cocoapods, and the umbrella header seems to be empty, so none of the classes seem to be available to the Objective-C app. Would it be possible to annotate it in a way that allows for interoperability between the two languages?

It looks great, thanks a lot!

Calling revertAction() inside kolodaDidSwipe causes bug

Hi, thank you for this awesome view.

I’m working on a project that requires to push cardViewController after selecting a card (swiping to right)

However user should be able to see selected card after popped cardViewController from navigation stack. Therefore I’ve added “revertAction()” inside “didSwipedCard()” delegate.

Here we go with an example;

  • dataSource.count=2 and visibleCards=1 (one card swiped, so last card is visible)
  • Swipe the last card to right
kolodaDidSwipedCard() {
    if direction == .Right {
        // Breakpoint
        kolodaView.revertAction()
        performSegue()
    }
}
  • Let’s look before breakpoint;
swipedAction() got called and processed this lines {
    animating = true
    visibleCards.removeAtIndex(0) // -> visibleCards.count = 0

    // -> visibleCards.isEmpty = true
    if !visibleCards.isEmpty {
        <# code #>
    } else {
        delegate?.kolodaDidSwipedCardAtIndex(self, index: UInt(currentCardNumber - 1), direction: direction)
        animating = false
        self.delegate?.kolodaDidRunOutOfCards(self)
    }
}

so at this point kolodaView.animating = true

  • After breakpoint
revertAction got called {
    // animating = true -> revertAction doesn’t work
    if currentCardNumber > 0 && animating == false {
        <# revertAction code #>
    }
}

Because of revertAction didn't work, selected card hasn't showed up, kolodaView has no visible cards.

  • Solution

Change order of the lines at swipedAction()

swipedAction() {
    
    if !visibleCards.isEmpty {
        <# code #>
    } else {
        animating = false // before delegate method
        delegate?.kolodaDidSwipedCardAtIndex(self, index: UInt(currentCardNumber - 1), direction: direction)

        // Check if visibleCards is still empty after delegate method
        if visibleCards.isEmpty {
            delegate?.kolodaDidRunOutOfCards(self)
        }
    }
}

Again, thanks for your hard work.

Duplicate calls when swiping quick

When loading cards with data (i'm loading around 50 at a time), if you swipe quickly through them, i am getting duplicate calls to kolodaDidSwipedCardAtIndex with the same index which then ends up freezing the app. I then end up seeing the top two cards with a slight transparency to see the card underneath.

Possible to add 'didShowCardAtIndex' method of some sort to properly get currentCardNumber?

I am trying to update a label to show the user the current index they are at, i.e. "5 of 10", and am having trouble pinpointing the proper places to make this update.

I tried adding my label update to both 'kolodaDidSwipedCardAtIndex' and 'kolodaDraggedCard' but they don't always get hit, especially when using 'revertAction' to display the last card.

I can easily just update the label in both 'kolodaDidSwipedCardAtIndex' and after I manually call 'revertAction', but it would be nice to either:

A) Add the delegate call for 'kolodaDidSwipedCardAtIndex' to the 'revertAction' method so it gets hit when a user brings back the previous card.
B) Create a new delegate method to notify the user that the index of the current card has changed for any reason (i.e. swipes, programmatic calls to advance/revert, etc.)

Jumping to a specific card

Dear Yalantis

First thanks for this beautiful control.

I have a minor question. Would it be possible to make the currentCardNumber settable, so I can jump to a specific card. e.g public var currentCardNumber = 0.

This seems to work if I set it and then call reload data.

Kind Regards
Graham

Error with Cocoapods

Hi, I am getting this error. This happened to me after updating to Xcode 7.1

Right now I have the latest of everything, Xcode, OS X El Capitan and Cocoapods..
All of them are latest. What is the reason behind this? and how to fix it?

eba21578-62c2-11e5-8783-55e0793604cb

Programmatically create KolodaView

My team is trying to use the library and having trouble creating the required views programmatically (we try to avoid using the storyboard). However, we are having trouble calling the designated initializers of our KolodaView subclass. Is the normal workflow to have your views pre-made in storyboard or nib?

    override init(frame: CGRect) {
        super.init(frame)
    }

^Gives an compile error.

Command failed due to signal: Segmentation fault: 11

After doing

pod update

I get this error when I try to build the project:

Command failed due to signal: Segmentation fault: 11

So I tried to downgrade to Koloda => 2.0.4 and it all worked fine, can anybody tell what's causing this problem?

Doesn't work with these constraints...

When I remove the bottom layout constraint and specify some specific Height for the Koloda View it works fine. But then it doesn't look good on all screen sizes. Can anybody suggest what the problem is?

Problem is with the swiping.. The cards show up but doesn't respond to any swipes

screen shot 2015-09-21 at 12 57 32 pm

EXC_BAD_INSTRUCTION (Xcode 6.4, El Capitan)

Dear Yalantis,

I'm using Xcode 6.4.
I get an EXC_BAD_INSTRUCTION error for:
self.kolodaView.dataSource = self
self.kolodaView.delegate = self

Here is a screenshot:

screen shot 2015-09-21 at 8 34 37 am

Thanks!
Rayan

kolodaBackgroundCardAnimation is mandatory

If kolodaBackgroundCardAnimation is not implemented, building fails and Xcode complains about your controller not conforming to the KolodaViewDelegate protocol. However, the docs claim that this method is optional: "This method is fired on swipping, when any cards are displayed. _If you don't return frame animation, or don't implement it, the koloda will apply default animation._"

Should this be marked optional, or is it mandatory?

Custom card view drawRect never fires

Hi,

Instead of returning UIImageView to DraggableCardView contentView, I've added a custom UIView and this seems working fine. However I've added drawRect() in my custom UIView Class, and set background color as clearColor in XIB:

override func drawRect(rect: CGRect) {
        // shaping for rounded corner
        var path = UIBezierPath(roundedRect: rect, byRoundingCorners: UIRectCorner.AllCorners, cornerRadii: CGSize(width: 6.0, height: 6.0))
        UIColor.whiteColor().setFill()
        path.fill()
    }

I saw this works fine for first 3 cards (white background color with rounded shape), but any cards after first 3 count is coming with clear background, I notice drawRect() never fires for those views. I've tried call the method someway, but failed.

Can you suggest a way out?

Thanks!

Why networking_example project can't be compiled

First, I want to thank you very much for this great library. Actually Yalantis has only great and fancy libraries in Github. Keep going on and keep sharing with us please.

I want to try the networking example project but it does not compile with xcode 7.0.0 iOS9 maybe it's because of swift 2 ?

Also is there any chance that somebody can share an example with Parse.com and Facebook login ?

First card redrawn differently from rest of deck on device rotation. Make layoutDeck() public?

This issue appears for me in both versions 1.0.4 and 1.1.0 (other versions not tried).

When the device is rotated, I trigger a reload of the deck so the deck fits on the new screen dimensions correctly:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

        coordinator.animateAlongsideTransition(nil){
            _ in

            self.kolodaView.reloadData()
        }
    }

When I have not yet swiped any card, the transition works as expected for all cards in the stack:

Before rotation:

image

After rotation (actual and expected):

image

However, after I have swiped at least once, if I once again try to rotate my device, the deck does not reset the card size and positioning until after I have swiped through the current top card:

Before rotation

image

After rotation, actual:

image

After rotation, expected:

image

After I swipe through the top mis-layed-out card, however, the rest of the deck is repositioned correctly.

Setting breakpoints in KolodaView, it ultimately appears to be the case that my redraw works the first time because layoutDeck() gets called as many times as the device is rotated when currentCardNumber == 0:

public func reloadData() {
        // (Truncated)

            if !visibleCards.isEmpty {
                loadMissingCards(missingCards)
            } else {
                setupDeck()
                layoutDeck()
            }

//(Truncated)

So, after all of this digging, it seems that what I actually need is for layoutDeck() to be a public method so I can call that upon rotation rather than reloadData(). In my own fork where I have done this, this approach works flawlessly. Any possibility this could be included?

Custom Views in cards

What do I need to do to get a custom view in the right dimensions of each card?

    func kolodaViewForCardAtIndex(koloda: KolodaView, index: UInt) -> UIView {
        let vc:KolodaViewController = self.storyboard?.instantiateViewControllerWithIdentifier("kolodaviewcontroller") as! KolodaViewController

        let tmpUser:user = users[Int(index)]
        vc.profileImageURL = tmpUser.imageURL
        vc.name = tmpUser.name
        vc.bio = tmpUser.bio
        url = tmpUser.trackURL

        //return UIImageView(image: nil)
        return vc.view
    }

I created a view controller with some elements arranged the way I'd like to see it in the card.
b9638a9b-8822-4f31-abee-48d2ad4bc181

Running the code presents the following.

223a9843-84ca-46be-b7e5-390aacff5dcd

When new cards are dynamically added to an exhausted deck, old cards get shown

To reproduce, do the following:

  1. Load 3 cards into your delegate (number is arbitrary, must be > 0 for this example to make sense).
  2. Swipe through these cards until you have exhausted your deck.
  3. Add a few more cards and trigger reloadData()

Expected:
You see the fourth card (card index 3)

Actual:
You see the first card (card index 0)

The issue is that in setupDeck, currentCardNumber is ignored and the index starts at 0.

Am working on a pull request with a fix.

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.