Skip to content

Commit

Permalink
first release
Browse files Browse the repository at this point in the history
  • Loading branch information
zhxnlai committed Nov 2, 2014
1 parent 063a2e8 commit 731bd58
Show file tree
Hide file tree
Showing 15 changed files with 636 additions and 55 deletions.
Binary file added Previews/swipe.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Previews/swipeCancel.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Previews/swipeLeft.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions README.md
@@ -1,2 +1,58 @@
ZLSwipeableView
===============
A simple view for building card like interface like Tinder and Potluck.

Preview
---
###Swipe
![swipe](Previews/swipe.gif)
###Swipe Cancel
![cancel](Previews/swipeCancel.gif)
###Swipe Programmatically
![swipeLeft](Previews/swipeLeft.gif)

CocoaPods
---
You can install `ZLSwipeableView` through CocoaPods adding the following to your Podfile:

pod 'ZLSwipeableView'

Usage
---
Check out the demo app for an example.

`ZLSwipeableView` can be added to storyboard or initialized programmatically:
~~~objective-c
ZLSwipeableView *swipeableView = [[ZLSwipeableView alloc] initWithFrame:self.view.frame];
[self.view addSubview:swipeableView];
~~~
A `ZLSwipeableView` **must** have an object that implements `ZLSwipeableViewDelegate` to act as a data source. `ZLSwipeableView` will prefetch **three** views in advance to animate them.
~~~objective-c
self.swipeableView.dataSource = self;
- (UIView *)nextViewForSwipeableView:(ZLSwipeableView *)swipeableView {
return [[UIView alloc] init];
}
~~~

To swipe the top view programmatically:
~~~objective-c
[self.swipeableView swipeTopViewToLeft];
[self.swipeableView swipeTopViewToRight];
~~~

To discard all views and reload programmatically:
~~~objective-c
[self.swipeableView discardAllSwipeableViews];
[self.swipeableView loadNextSwipeableViewsIfNeeded];
~~~

Requirements
---
- iOS 7 or higher.
- Automatic Reference Counting (ARC).

License
---
ZLSwipeableView is available under MIT license. See the LICENSE file for more info.
File renamed without changes.
File renamed without changes.
@@ -1,5 +1,5 @@
//
// ZLSwipeableContainerView.h
// ZLSwipeableView.h
// ZLSwipeableViewDemo
//
// Created by Zhixuan Lai on 11/1/14.
Expand All @@ -8,26 +8,26 @@

#import <UIKit/UIKit.h>

@class ZLSwipeableContainterView;
@class ZLSwipeableView;

// Delegate
@protocol ZLSwipeableContainerViewDelegate <NSObject>
@optional

- (void)containerView: (ZLSwipeableContainterView *)containerView didSwipeLeft:(UIView *)view;
- (void)containerView: (ZLSwipeableContainterView *)containerView didSwipeRight:(UIView *)view;
- (void)swipeableView: (ZLSwipeableView *)swipeableView didSwipeLeft:(UIView *)view;
- (void)swipeableView: (ZLSwipeableView *)swipeableView didSwipeRight:(UIView *)view;

@end


// DataSource
@protocol ZLSwipeableContainerViewDataSource <NSObject>
@protocol ZLSwipeableViewDataSource <NSObject>
@required
- (UIView *)nextSwipeableViewForContainerView:(ZLSwipeableContainterView *)containerView;
- (UIView *)nextViewForSwipeableView:(ZLSwipeableView *)swipeableView;
@end

@interface ZLSwipeableContainterView : UIView
@property (nonatomic, weak) id <ZLSwipeableContainerViewDataSource> dataSource;
@interface ZLSwipeableView : UIView
@property (nonatomic, weak) id <ZLSwipeableViewDataSource> dataSource;
@property (nonatomic, weak) id <ZLSwipeableContainerViewDelegate> delegate;

/**
Expand Down Expand Up @@ -72,9 +72,13 @@
* Load up to 3 swipeable views.
*/
-(void)loadNextSwipeableViewsIfNeeded;


/**
* Swipe top view to the left programmatically
*/
-(void)swipeTopViewToLeft;
/**
* Swipe top view to the right programmatically
*/
-(void)swipeTopViewToRight;

@end
@@ -1,33 +1,33 @@
//
// ZLSwipeableContainerView.m
// ZLSwipeableView.m
// ZLSwipeableViewDemo
//
// Created by Zhixuan Lai on 11/1/14.
// Copyright (c) 2014 Zhixuan Lai. All rights reserved.
//

#import "ZLSwipeableContainterView.h"
#import "ZLSwipeableView.h"
#import "ZLPanGestureRecognizer.h"

static const int numPrefetchedViews = 3;

@interface ZLSwipeableContainterView () <UICollisionBehaviorDelegate, UIDynamicAnimatorDelegate>
@interface ZLSwipeableView () <UICollisionBehaviorDelegate, UIDynamicAnimatorDelegate>

// UIDynamicAnimators
@property (strong, nonatomic) UIDynamicAnimator *animator;
@property (nonatomic, strong) UISnapBehavior *swipeableViewSnapBehavior;
@property (strong, nonatomic) UIAttachmentBehavior *swipeableViewAttachmentBehavior;
@property (strong, nonatomic) UIAttachmentBehavior *anchorViewAttachmentBehavior;
//AnchorView
// AnchorView
@property (strong, nonatomic) UIView *anchorContainerView;
@property (strong, nonatomic) UIView *anchorView;
@property (nonatomic) BOOL isAnchorViewVisiable;

// ContainerView
@property (strong, nonatomic) UIView *reuseCoverContainerView;
@property (strong, nonatomic) UIView *containerView;

@end
@implementation ZLSwipeableContainterView
@implementation ZLSwipeableView

#pragma mark - Init
- (id)initWithFrame:(CGRect)frame {
Expand Down Expand Up @@ -83,7 +83,7 @@ -(void)setSwipeableViewsCenter:(CGPoint)swipeableViewsCenter {
[self animateSwipeableViewsIfNeeded];
}
#pragma mark - Properties
- (void)setDataSource:(id<ZLSwipeableContainerViewDataSource>)dataSource {
- (void)setDataSource:(id<ZLSwipeableViewDataSource>)dataSource {
_dataSource = dataSource;
[self loadNextSwipeableViewsIfNeeded:NO];
}
Expand All @@ -103,10 +103,12 @@ - (void)loadNextSwipeableViewsIfNeeded:(BOOL)animated {
NSMutableSet *newViews = [NSMutableSet set];
for (NSInteger i=numViews; i<numPrefetchedViews; i++) {
UIView *nextView = [self nextSwipeableView];
[self.containerView addSubview:nextView];
[self.containerView sendSubviewToBack:nextView];
nextView.center = self.swipeableViewsCenter;
[newViews addObject:nextView];
if (nextView) {
[self.containerView addSubview:nextView];
[self.containerView sendSubviewToBack:nextView];
nextView.center = self.swipeableViewsCenter;
[newViews addObject:nextView];
}
}
if (animated) {
NSTimeInterval maxDelay = 0.3;
Expand Down Expand Up @@ -296,12 +298,12 @@ - (void)createAnchorViewForCover:(UIView *)swipeableView atLocation: (CGPoint)lo
}
- (void)pushAnchorViewForCover:(UIView *)swipeableView inDirection:(CGVector)direction andCollideInRect: (CGRect) collisionRect {
if (direction.dx>0) {
if (self.delegate && [self.delegate respondsToSelector:@selector(containerView:didSwipeRight:)]) {
[self.delegate containerView:self didSwipeRight:swipeableView];
if (self.delegate && [self.delegate respondsToSelector:@selector(swipeableView:didSwipeRight:)]) {
[self.delegate swipeableView:self didSwipeRight:swipeableView];
}
} else {
if (self.delegate && [self.delegate respondsToSelector:@selector(containerView:didSwipeLeft:)]) {
[self.delegate containerView:self didSwipeLeft:swipeableView];
if (self.delegate && [self.delegate respondsToSelector:@selector(swipeableView:didSwipeLeft:)]) {
[self.delegate swipeableView:self didSwipeLeft:swipeableView];
}
}
// NSLog(@"pushing cover to direction: %f, %f", direction.dx, direction.dy);
Expand Down Expand Up @@ -381,8 +383,8 @@ - (CGRect)defaultCollisionRect {
}
- (UIView *)nextSwipeableView {
UIView *nextView = nil;
if (self.dataSource && [self.dataSource respondsToSelector:@selector(nextSwipeableViewForContainerView:)]) {
nextView = [self.dataSource nextSwipeableViewForContainerView:self];
if (self.dataSource && [self.dataSource respondsToSelector:@selector(nextViewForSwipeableView:)]) {
nextView = [self.dataSource nextViewForSwipeableView:self];
}
if (nextView) {
[nextView addGestureRecognizer:[[ZLPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]];
Expand Down
30 changes: 15 additions & 15 deletions ZLSwipeableViewDemo/ZLSwipeableViewDemo.xcodeproj/project.pbxproj
Expand Up @@ -14,10 +14,10 @@
092F0F3F1A05B474007CDDCC /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 092F0F3E1A05B474007CDDCC /* Images.xcassets */; };
092F0F421A05B474007CDDCC /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 092F0F401A05B474007CDDCC /* LaunchScreen.xib */; };
092F0F4E1A05B474007CDDCC /* ZLSwipeableViewDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 092F0F4D1A05B474007CDDCC /* ZLSwipeableViewDemoTests.m */; };
092F0F591A05B4AF007CDDCC /* ZLSwipeableContainterView.m in Sources */ = {isa = PBXBuildFile; fileRef = 092F0F581A05B4AF007CDDCC /* ZLSwipeableContainterView.m */; };
092F0F621A05BFA7007CDDCC /* ZLPanGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 092F0F611A05BFA7007CDDCC /* ZLPanGestureRecognizer.m */; };
092F0F661A05C9CA007CDDCC /* UIColor+FlatColors.m in Sources */ = {isa = PBXBuildFile; fileRef = 092F0F651A05C9CA007CDDCC /* UIColor+FlatColors.m */; };
092F0F691A05DAF9007CDDCC /* CardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 092F0F681A05DAF8007CDDCC /* CardView.m */; };
092F0F701A05F8B3007CDDCC /* ZLPanGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 092F0F6D1A05F8B3007CDDCC /* ZLPanGestureRecognizer.m */; };
092F0F711A05F8B3007CDDCC /* ZLSwipeableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 092F0F6F1A05F8B3007CDDCC /* ZLSwipeableView.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -44,14 +44,14 @@
092F0F471A05B474007CDDCC /* ZLSwipeableViewDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ZLSwipeableViewDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
092F0F4C1A05B474007CDDCC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
092F0F4D1A05B474007CDDCC /* ZLSwipeableViewDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZLSwipeableViewDemoTests.m; sourceTree = "<group>"; };
092F0F571A05B4AF007CDDCC /* ZLSwipeableContainterView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZLSwipeableContainterView.h; sourceTree = "<group>"; };
092F0F581A05B4AF007CDDCC /* ZLSwipeableContainterView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZLSwipeableContainterView.m; sourceTree = "<group>"; };
092F0F601A05BFA7007CDDCC /* ZLPanGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZLPanGestureRecognizer.h; sourceTree = "<group>"; };
092F0F611A05BFA7007CDDCC /* ZLPanGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZLPanGestureRecognizer.m; sourceTree = "<group>"; };
092F0F641A05C9CA007CDDCC /* UIColor+FlatColors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+FlatColors.h"; sourceTree = "<group>"; };
092F0F651A05C9CA007CDDCC /* UIColor+FlatColors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+FlatColors.m"; sourceTree = "<group>"; };
092F0F671A05DAF8007CDDCC /* CardView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CardView.h; sourceTree = "<group>"; };
092F0F681A05DAF8007CDDCC /* CardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CardView.m; sourceTree = "<group>"; };
092F0F6C1A05F8B3007CDDCC /* ZLPanGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZLPanGestureRecognizer.h; sourceTree = "<group>"; };
092F0F6D1A05F8B3007CDDCC /* ZLPanGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZLPanGestureRecognizer.m; sourceTree = "<group>"; };
092F0F6E1A05F8B3007CDDCC /* ZLSwipeableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZLSwipeableView.h; sourceTree = "<group>"; };
092F0F6F1A05F8B3007CDDCC /* ZLSwipeableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZLSwipeableView.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -94,7 +94,7 @@
isa = PBXGroup;
children = (
092F0F631A05C9CA007CDDCC /* UIColor+FlatColors */,
092F0F6A1A05F812007CDDCC /* ZLSwipeableView */,
092F0F6B1A05F8B3007CDDCC /* ZLSwipeableView */,
092F0F351A05B474007CDDCC /* AppDelegate.h */,
092F0F361A05B474007CDDCC /* AppDelegate.m */,
092F0F381A05B474007CDDCC /* ViewController.h */,
Expand Down Expand Up @@ -144,15 +144,15 @@
path = "UIColor+FlatColors";
sourceTree = "<group>";
};
092F0F6A1A05F812007CDDCC /* ZLSwipeableView */ = {
092F0F6B1A05F8B3007CDDCC /* ZLSwipeableView */ = {
isa = PBXGroup;
children = (
092F0F571A05B4AF007CDDCC /* ZLSwipeableContainterView.h */,
092F0F581A05B4AF007CDDCC /* ZLSwipeableContainterView.m */,
092F0F601A05BFA7007CDDCC /* ZLPanGestureRecognizer.h */,
092F0F611A05BFA7007CDDCC /* ZLPanGestureRecognizer.m */,
092F0F6C1A05F8B3007CDDCC /* ZLPanGestureRecognizer.h */,
092F0F6D1A05F8B3007CDDCC /* ZLPanGestureRecognizer.m */,
092F0F6E1A05F8B3007CDDCC /* ZLSwipeableView.h */,
092F0F6F1A05F8B3007CDDCC /* ZLSwipeableView.m */,
);
name = ZLSwipeableView;
path = ZLSwipeableView;
sourceTree = "<group>";
};
/* End PBXGroup section */
Expand Down Expand Up @@ -256,12 +256,12 @@
buildActionMask = 2147483647;
files = (
092F0F3A1A05B474007CDDCC /* ViewController.m in Sources */,
092F0F591A05B4AF007CDDCC /* ZLSwipeableContainterView.m in Sources */,
092F0F711A05F8B3007CDDCC /* ZLSwipeableView.m in Sources */,
092F0F661A05C9CA007CDDCC /* UIColor+FlatColors.m in Sources */,
092F0F621A05BFA7007CDDCC /* ZLPanGestureRecognizer.m in Sources */,
092F0F371A05B474007CDDCC /* AppDelegate.m in Sources */,
092F0F341A05B474007CDDCC /* main.m in Sources */,
092F0F691A05DAF9007CDDCC /* CardView.m in Sources */,
092F0F701A05F8B3007CDDCC /* ZLPanGestureRecognizer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Expand Up @@ -44,7 +44,7 @@
<action selector="swipeRightButtonAction:" destination="vXZ-lx-hvc" eventType="touchUpInside" id="tZK-sW-KTp"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="C0K-0Y-C7k" userLabel="SwipeableContainerView" customClass="ZLSwipeableContainterView">
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="C0K-0Y-C7k" userLabel="SwipeableContainerView" customClass="ZLSwipeableView">
<rect key="frame" x="36" y="60" width="528" height="442"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
Expand Down
24 changes: 12 additions & 12 deletions ZLSwipeableViewDemo/ZLSwipeableViewDemo/ViewController.m
Expand Up @@ -7,12 +7,12 @@
//

#import "ViewController.h"
#import "ZLSwipeableContainterView.h"
#import "ZLSwipeableView.h"
#import "UIColor+FlatColors.h"
#import "CardView.h"

@interface ViewController () <ZLSwipeableContainerViewDataSource>
@property (weak, nonatomic) IBOutlet ZLSwipeableContainterView *containerView;
@interface ViewController () <ZLSwipeableViewDataSource>
@property (weak, nonatomic) IBOutlet ZLSwipeableView *swipeableView;

@property (nonatomic, strong) NSArray *colors;
@property (nonatomic) NSUInteger colorIndex;
Expand Down Expand Up @@ -50,25 +50,25 @@ - (void)viewDidLoad {
// ZLSwipeableContainterView *container = [[ZLSwipeableContainterView alloc] initWithFrame:self.view.frame];
// [self.view addSubview:container];

[self.containerView setNeedsLayout];
[self.containerView layoutIfNeeded];
self.containerView.dataSource = self;
[self.swipeableView setNeedsLayout];
[self.swipeableView layoutIfNeeded];
self.swipeableView.dataSource = self;
}
- (IBAction)swipeLeftButtonAction:(UIButton *)sender {
[self.containerView swipeTopViewToLeft];
[self.swipeableView swipeTopViewToLeft];
}
- (IBAction)swipeRightButtonAction:(UIButton *)sender {
[self.containerView swipeTopViewToRight];
[self.swipeableView swipeTopViewToRight];
}
- (IBAction)reloadButtonAction:(UIButton *)sender {
self.colorIndex = 0;
[self.containerView discardAllSwipeableViews];
[self.containerView loadNextSwipeableViewsIfNeeded];
[self.swipeableView discardAllSwipeableViews];
[self.swipeableView loadNextSwipeableViewsIfNeeded];
}

- (UIView *)nextSwipeableViewForContainerView:(ZLSwipeableContainterView *)containerView {
- (UIView *)nextViewForSwipeableView:(ZLSwipeableView *)swipeableView {
if (self.colorIndex<self.colors.count) {
CardView *view = [[CardView alloc] initWithFrame:containerView.bounds];
CardView *view = [[CardView alloc] initWithFrame:swipeableView.bounds];
view.cardColor = [self colorForName:self.colors[self.colorIndex]];
self.colorIndex++;
return view;
Expand Down
@@ -0,0 +1,13 @@
//
// ZLPanGestureRecognizer.h
// ZLSwipeableViewDemo
//
// Created by Zhixuan Lai on 11/1/14.
// Copyright (c) 2014 Zhixuan Lai. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface ZLPanGestureRecognizer : UIPanGestureRecognizer

@end
@@ -0,0 +1,13 @@
//
// ZLPanGestureRecognizer.m
// ZLSwipeableViewDemo
//
// Created by Zhixuan Lai on 11/1/14.
// Copyright (c) 2014 Zhixuan Lai. All rights reserved.
//

#import "ZLPanGestureRecognizer.h"

@implementation ZLPanGestureRecognizer

@end

0 comments on commit 731bd58

Please sign in to comment.