├── Demo ├── en.lproj │ └── InfoPlist.strings ├── Classes │ ├── DemoViewController.h │ ├── Helpers │ │ ├── CenteredTableViewController.h │ │ ├── DemoAppDelegate.h │ │ ├── UIView+JMNoise.h │ │ ├── DemoAppDelegate.m │ │ ├── CenteredTableViewController.m │ │ └── UIView+JMNoise.m │ └── DemoViewController.m ├── main.m ├── Demo-Prefix.pch └── Demo-Info.plist ├── JMSlider.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── project.pbxproj ├── JMSlider ├── Internal │ ├── JMSliderTrack.h │ ├── JMSideView.h │ ├── JMSliderComponent.h │ ├── JMCenterView.h │ ├── JMSliderComponent.m │ ├── JMSliderConstants.h │ ├── JMSideView.m │ ├── JMSliderTrack.m │ └── JMCenterView.m ├── Categories │ ├── UIView+Positioning.h │ ├── UIView+Size.h │ ├── UIView+Positioning.m │ └── UIView+Size.m ├── JMSlider.h └── JMSlider.m ├── .gitignore ├── LICENSE └── readme.md /Demo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Demo/Classes/DemoViewController.h: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import 4 | #import "JMSlider.h" 5 | 6 | @interface DemoViewController : UIViewController 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /JMSlider.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JMSlider/Internal/JMSliderTrack.h: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import 4 | #import "JMSliderComponent.h" 5 | 6 | @class JMSlider; 7 | 8 | @interface JMSliderTrack : JMSliderComponent 9 | 10 | + (JMSliderTrack *)sliderTrackForSlider:(JMSlider *)slider; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # xcode noise 2 | *.mode1v3 3 | *.pbxuser 4 | *.perspective 5 | *.perspectivev3 6 | *.pyc 7 | *~.nib/ 8 | build/* 9 | 10 | *.xcuserdatad 11 | 12 | 13 | # Textmate - if you build your xcode projects with it 14 | *.tm_build_errors 15 | 16 | # old skool 17 | .svn 18 | 19 | # osx noise 20 | .DS_Store 21 | profile 22 | 23 | -------------------------------------------------------------------------------- /Demo/main.m: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 8 | int retVal = UIApplicationMain(argc, argv, nil, @"DemoAppDelegate"); 9 | [pool release]; 10 | return retVal; 11 | } 12 | -------------------------------------------------------------------------------- /Demo/Classes/Helpers/CenteredTableViewController.h: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import 4 | 5 | @interface CenteredTableViewController : UITableViewController 6 | 7 | - (id)initWithCenteredView:(UIView *)centeredView; 8 | + (UITableView *) tableViewWithCenteredView:(UIView *)centeredView; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /JMSlider/Internal/JMSideView.h: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import 4 | #import "JMSliderComponent.h" 5 | 6 | @class JMSlider; 7 | 8 | @interface JMSideView : JMSliderComponent 9 | 10 | @property (assign) BOOL active; 11 | - (CGPoint)itemOffset; 12 | + (JMSideView *)sideViewWithTitle:(NSString *)title; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Demo/Demo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Demo' target in the 'Demo' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iPhone SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /Demo/Classes/Helpers/DemoAppDelegate.h: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | @interface DemoAppDelegate : NSObject 4 | { 5 | UIWindow *window_; 6 | UINavigationController *UINavigationController_; 7 | } 8 | 9 | @property (nonatomic, retain) UIWindow *window; 10 | @property (nonatomic, retain) UINavigationController *navigationController; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /JMSlider/Internal/JMSliderComponent.h: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import 4 | 5 | @class JMSlider; 6 | 7 | @interface JMSliderComponent : UIView 8 | 9 | @property (nonatomic, assign) JMSlider * slider; 10 | @property (nonatomic, assign) BOOL highlighted; 11 | @property (nonatomic, retain) NSString * title; 12 | 13 | - (id)initWithFrame:(CGRect)frame forSlider:(JMSlider *)slider; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /JMSlider/Internal/JMCenterView.h: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import 4 | #import "JMSliderComponent.h" 5 | 6 | @class JMSlider; 7 | 8 | @interface JMCenterView : JMSliderComponent 9 | 10 | - (id)initForSlider:(JMSlider *)slider withTitle:(NSString *)title; 11 | + (JMCenterView *)sliderButtonForSlider:(JMSlider *)slider withTitle:(NSString *)title; 12 | 13 | - (void)setLoading:(BOOL)loading; 14 | 15 | // Custom drawing 16 | - (void)drawButtonInRect:(CGRect)rect; 17 | - (CGSize)sizeOfButton; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Demo/Classes/Helpers/UIView+JMNoise.h: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey 2 | 3 | #import 4 | 5 | @interface UIView (JMNoise) 6 | 7 | // Can be used directly on UIView 8 | - (void)applyNoise; 9 | - (void)applyNoiseWithOpacity:(CGFloat)opacity atLayerIndex:(NSUInteger) layerIndex; 10 | - (void)applyNoiseWithOpacity:(CGFloat)opacity; 11 | 12 | // Can be invoked from a drawRect() method 13 | - (void)drawCGNoise; 14 | - (void)drawCGNoiseWithOpacity:(CGFloat)opacity; 15 | - (void)drawCGNoiseWithOpacity:(CGFloat)opacity blendMode:(CGBlendMode)blendMode; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /JMSlider/Internal/JMSliderComponent.m: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import "JMSliderComponent.h" 4 | #import "JMSlider.h" 5 | 6 | @implementation JMSliderComponent 7 | 8 | @synthesize slider = slider_; 9 | @synthesize highlighted = highlighted_; 10 | @synthesize title = title_; 11 | 12 | - (void)dealloc 13 | { 14 | self.slider = nil; 15 | self.title = nil; 16 | [super dealloc]; 17 | } 18 | 19 | - (id)initWithFrame:(CGRect)frame forSlider:(JMSlider *)slider; 20 | { 21 | self = [super initWithFrame:frame]; 22 | if (self) 23 | { 24 | self.slider = slider; 25 | self.backgroundColor = [UIColor clearColor]; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)setHighlighted:(BOOL)highlighted; 31 | { 32 | highlighted_ = highlighted; 33 | [self setNeedsDisplay]; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /JMSlider/Internal/JMSliderConstants.h: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #define kJMSideTitleFont [UIFont fontWithName:@"HelveticaNeue-Bold" size:12.] 4 | #define kJMSideTitleColor [UIColor colorWithWhite:0.76 alpha:1.] 5 | 6 | #define kJMButtonPadding CGSizeMake(34., 8.) 7 | #define kJMButtonFont [UIFont fontWithName:@"HelveticaNeue" size:14.] 8 | #define kJMSliderButtonInvisiblePadding CGSizeMake(40., 30.) 9 | #define kJMButtonColor [UIColor colorWithWhite:0.7 alpha:1.] 10 | #define kJMButtonOutlineColor [UIColor colorWithWhite:0. alpha:0.1] 11 | 12 | #define kJMSliderTrackColor [UIColor colorWithWhite:0. alpha:0.1] 13 | #define kJMSliderTrackEdgeRadius 3. 14 | #define kJMSliderAnimationCenterButton @"kJMSliderAnimationCenterButton" 15 | #define kJMSliderAnimationHighlight @"kJMSliderAnimationHighlight" 16 | #define kJMSliderOptionActivationMargin 0.2 17 | #define kJMSliderMinimumMovementBuffer 0.2 18 | #define kJMSliderMinimumFadeOpacity 0.2 19 | -------------------------------------------------------------------------------- /JMSlider/Internal/JMSideView.m: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import "JMSideView.h" 4 | #import "JMSlider.h" 5 | 6 | @implementation JMSideView 7 | 8 | @synthesize active = active_; 9 | 10 | - (id)initWithFrame:(CGRect)frame 11 | { 12 | self = [super initWithFrame:frame]; 13 | if (self) 14 | { 15 | self.backgroundColor = [UIColor clearColor]; 16 | } 17 | return self; 18 | } 19 | 20 | - (CGSize)sizeThatFits:(CGSize)size; 21 | { 22 | return [self.title sizeWithFont:kJMSideTitleFont]; 23 | } 24 | 25 | - (CGPoint)itemOffset; 26 | { 27 | return CGPointMake(0., 10.); 28 | } 29 | 30 | - (void)drawRect:(CGRect)rect; 31 | { 32 | [kJMSideTitleColor set]; 33 | [self.title drawInRect:rect withFont:kJMSideTitleFont lineBreakMode:UILineBreakModeTailTruncation alignment:UITextAlignmentCenter]; 34 | } 35 | 36 | + (JMSideView *)sideViewWithTitle:(NSString *)title; 37 | { 38 | JMSideView * sideView = [[[[self class] alloc] init] autorelease]; 39 | sideView.title = title; 40 | [sideView sizeToFit]; 41 | return sideView; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Demo/Classes/Helpers/DemoAppDelegate.m: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import "DemoAppDelegate.h" 4 | #import "DemoViewController.h" 5 | 6 | @implementation DemoAppDelegate 7 | 8 | @synthesize window = window_; 9 | @synthesize navigationController = navigationController_; 10 | 11 | #pragma mark - 12 | #pragma mark Application lifecycle 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 15 | { 16 | DemoViewController * demoViewController = [[[DemoViewController alloc] initWithNibName:nil bundle:nil] autorelease]; 17 | self.navigationController = [[[UINavigationController alloc] initWithRootViewController:demoViewController] autorelease]; 18 | [self.navigationController setNavigationBarHidden:YES]; 19 | 20 | self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; 21 | [self.window addSubview:self.navigationController.view]; 22 | [self.window makeKeyAndVisible]; 23 | 24 | return YES; 25 | } 26 | 27 | - (void)dealloc 28 | { 29 | self.navigationController = nil; 30 | self.window = nil; 31 | [super dealloc]; 32 | } 33 | 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Demo/Demo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | com.designshed.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1.0 27 | LSRequiresIPhoneOS 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UIStatusBarStyle 36 | UIStatusBarStyleBlackOpaque 37 | 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Software Copyright License Agreement (BSD License) 2 | 3 | Copyright (c) 2010, Jason Morrissey 4 | All rights reserved. 5 | 6 | Redistribution and use of this software in source and binary forms, 7 | with or without modification, are permitted provided that the following 8 | conditions are met: 9 | 10 | * Redistributions of source code must retain the above 11 | copyright notice, this list of conditions and the 12 | following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above 15 | copyright notice, this list of conditions and the 16 | following disclaimer in the documentation and/or other 17 | materials provided with the distribution. 18 | 19 | * Neither the name of Jason Morrissey nor the names of 20 | contributors may be used to endorse or promote products 21 | derived from this software without specific prior 22 | written permission of Jason Morrissey. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /JMSlider/Internal/JMSliderTrack.m: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import "JMSliderTrack.h" 4 | #import "JMSlider.h" 5 | 6 | @implementation JMSliderTrack 7 | 8 | - (void)dealloc; 9 | { 10 | [super dealloc]; 11 | } 12 | 13 | - (void)drawRect:(CGRect)rect; 14 | { 15 | [kJMSliderTrackColor set]; 16 | 17 | CGFloat trackSize = 1.; 18 | CGFloat buttonWidth = [self.slider centerViewWidth]; 19 | CGFloat lowCenter = [self.slider trackLowCenter]; 20 | 21 | CGRect trackRect = CGRectInset(rect, lowCenter + kJMSliderTrackEdgeRadius - (buttonWidth / 4.), (rect.size.height - trackSize) / 2); 22 | UIBezierPath * trackPath = [UIBezierPath bezierPathWithRoundedRect:trackRect cornerRadius:2.]; 23 | [trackPath fill]; 24 | 25 | if (self.highlighted) 26 | { 27 | CGRect leftEdgeRect = CGRectMake(CGRectGetMinX(trackRect) - kJMSliderTrackEdgeRadius, CGRectGetMidY(trackRect) - 0.5, 1., 1.); 28 | UIBezierPath * leftEdgePath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(leftEdgeRect, -1. * kJMSliderTrackEdgeRadius, -1. * kJMSliderTrackEdgeRadius)]; 29 | [leftEdgePath fill]; 30 | 31 | CGRect rightEdgeRect = CGRectMake(CGRectGetMaxX(trackRect) + kJMSliderTrackEdgeRadius, CGRectGetMidY(trackRect) - 0.5, 1., 1.); 32 | UIBezierPath * rightEdgePath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(rightEdgeRect, -1. * kJMSliderTrackEdgeRadius, -1. * kJMSliderTrackEdgeRadius)]; 33 | [rightEdgePath fill]; 34 | } 35 | } 36 | 37 | + (JMSliderTrack *)sliderTrackForSlider:(JMSlider *)slider; 38 | { 39 | JMSliderTrack * sliderTrack = [[[[self class] alloc] initWithFrame:slider.bounds forSlider:slider] autorelease]; 40 | sliderTrack.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 41 | return sliderTrack; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Demo/Classes/DemoViewController.m: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import "DemoViewController.h" 4 | #import "CenteredTableViewController.h" 5 | 6 | @interface DemoViewController() 7 | @property (nonatomic,retain) JMSlider * slider; 8 | @end 9 | 10 | @implementation DemoViewController 11 | 12 | @synthesize slider = slider_; 13 | 14 | - (void)dealloc; 15 | { 16 | self.slider = nil; 17 | [super dealloc]; 18 | } 19 | 20 | - (void)loadView; 21 | { 22 | CGRect sliderFrame = CGRectMake(0., 0., 320., 90.); 23 | self.slider = [JMSlider sliderWithFrame:sliderFrame centerTitle:@"more" leftTitle:@"hide read" rightTitle:@"hide all" delegate:self]; 24 | 25 | UITableView * tableView = [CenteredTableViewController tableViewWithCenteredView:self.slider]; 26 | 27 | // Important: When including the slider in tableViews or scrollViews, I highly recommend 28 | // that you set canCancelContentTouches to NO so that the table/scrollView doesn't scroll 29 | // while the user is toggling the slider. 30 | [tableView setCanCancelContentTouches:NO]; 31 | 32 | self.view = tableView; 33 | } 34 | 35 | - (void) stopSimulatedLoading; 36 | { 37 | [self.slider setLoading:NO]; 38 | } 39 | 40 | 41 | #pragma Mark - 42 | #pragma Mark - JMSliderDelegate Methods 43 | 44 | -(void)slider:(JMSlider *)slider didSelect:(JMSliderSelection)selection; 45 | { 46 | [slider setLoading:YES]; 47 | 48 | switch (selection) 49 | { 50 | case JMSliderSelectionLeft: 51 | NSLog(@"invoked: left"); 52 | break; 53 | 54 | case JMSliderSelectionCenter: 55 | NSLog(@"invoked: center"); 56 | break; 57 | 58 | case JMSliderSelectionRight: 59 | NSLog(@"invoked: right"); 60 | break; 61 | 62 | default: 63 | break; 64 | } 65 | 66 | [self performSelector:@selector(stopSimulatedLoading) withObject:nil afterDelay:2.]; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /JMSlider/Categories/UIView+Positioning.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, Kevin O'Neill 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // * Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // * Neither the name UsefulBits nor the names of its contributors may be used 15 | // to endorse or promote products derived from this software without specific 16 | // prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | #import 30 | 31 | @interface UIView (Positioning) 32 | 33 | - (void)centerInRect:(CGRect)rect; 34 | - (void)centerVerticallyInRect:(CGRect)rect; 35 | - (void)centerHorizontallyInRect:(CGRect)rect; 36 | 37 | - (void)centerInSuperView; 38 | - (void)centerVerticallyInSuperView; 39 | - (void)centerHorizontallyInSuperView; 40 | 41 | - (void)centerHorizontallyBelow:(UIView *)view padding:(CGFloat)padding; 42 | - (void)centerHorizontallyBelow:(UIView *)view; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /JMSlider/JMSlider.h: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import 4 | #import "JMSliderConstants.h" 5 | 6 | @class JMSlider; 7 | @class JMCenterView; 8 | @class JMSideView; 9 | @class JMSliderTrack; 10 | 11 | typedef enum JMSliderSelection { 12 | JMSliderSelectionLeft, 13 | JMSliderSelectionCenter, 14 | JMSliderSelectionRight 15 | } JMSliderSelection; 16 | 17 | #if NS_BLOCKS_AVAILABLE 18 | typedef void(^JMSliderExecutionBlock)(void); 19 | #endif 20 | 21 | #pragma Mark - 22 | #pragma Mark - JMSliderDelegate 23 | 24 | @protocol JMSliderDelegate 25 | @optional 26 | -(void)slider:(JMSlider *)slider didSelect:(JMSliderSelection)selection; 27 | -(JMCenterView *)sliderCenterViewForSlider:(JMSlider *)slider; 28 | -(JMSideView *)sliderLeftViewForSlider:(JMSlider *)slider; 29 | -(JMSideView *)sliderRightViewForSlider:(JMSlider *)slider; 30 | -(JMSliderTrack *)sliderTrackViewForSlider:(JMSlider *)slider; 31 | 32 | @end 33 | 34 | #pragma Mark - 35 | #pragma Mark - JMSlider 36 | 37 | @interface JMSlider : UIView 38 | 39 | #if NS_BLOCKS_AVAILABLE 40 | @property (nonatomic,copy) JMSliderExecutionBlock leftExecuteBlock; 41 | @property (nonatomic,copy) JMSliderExecutionBlock centerExecuteBlock; 42 | @property (nonatomic,copy) JMSliderExecutionBlock rightExecuteBlock; 43 | #endif 44 | 45 | #pragma Mark - Internal 46 | 47 | // Accessors for subviews 48 | - (CGFloat)trackLowCenter; 49 | - (CGFloat)trackHighCenter; 50 | - (CGFloat)centerViewWidth; 51 | - (CGFloat)slideRatio; 52 | 53 | // Method calls from subviews 54 | - (void)updateWithSlideRatio:(CGFloat)slideRatio; 55 | - (void)setButtonCenterPosition:(CGPoint)centerPoint animated:(BOOL)animated; 56 | - (void)setHighlightSlider:(BOOL)highlighted; 57 | - (void)releaseDragShouldCancel:(BOOL)cancelled; 58 | - (void)tappedCenterView; 59 | 60 | #pragma Mark - External API 61 | 62 | + (JMSlider *) sliderWithFrame:(CGRect)frame centerTitle:(NSString *)centerTitle leftTitle:(NSString *)leftTitle rightTitle:(NSString *)rightTitle delegate:(id)delegate; 63 | + (JMSlider *) sliderWithFrame:(CGRect)frame delegate:(id)delegate; 64 | 65 | - (void)setLoading:(BOOL)loading; 66 | 67 | @end 68 | 69 | -------------------------------------------------------------------------------- /JMSlider/Categories/UIView+Size.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, Kevin O'Neill 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // * Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // * Neither the name UsefulBits nor the names of its contributors may be used 15 | // to endorse or promote products derived from this software without specific 16 | // prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | #import 30 | 31 | @interface UIView (Size) 32 | 33 | @property (nonatomic, assign) CGSize size; 34 | 35 | @property (nonatomic, assign) CGFloat left; 36 | @property (nonatomic, assign) CGFloat right; 37 | @property (nonatomic, assign) CGFloat top; 38 | @property (nonatomic, assign) CGFloat bottom; 39 | 40 | @property (nonatomic, assign) CGFloat centerX; 41 | @property (nonatomic, assign) CGFloat centerY; 42 | 43 | @property (nonatomic, assign) CGFloat width; 44 | @property (nonatomic, assign) CGFloat height; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## JMSlider 2 | 3 | JMSlider is a sliding component that can be used to toggle three actions with a single button. For example, it can be used to allow for multiple actions at the end of lists/tables while keeping visual clutter to a minimum. The component is rendered entirely using **Core Graphics** so it does not require any additional images to be used in your projects. 4 | 5 | ## How it looks 6 | 7 | This is what JMSlider looks like out of the box, (or a [video](http://youtu.be/GV40mAwcCrI?hd=1) if you prefer): 8 | 9 | 10 | 11 | ## Usage 12 | 13 | A demo project is included in the repository so that you can give it a test drive. In brief, this is all you need to create the slider: 14 | 15 | `JMSlider *slider = [JMSlider sliderWithFrame:sliderFrame centerTitle:@"more" leftTitle:@"hide read" rightTitle:@"hide all" delegate:self];` 16 | 17 | By implementing the `slider:didSelect:` method, you will receive a callback when the tab selection changes. 18 | 19 | ## Flexibility 20 | 21 | JMSlider also supports the execution of blocks so that you can embed your logic inline, like this: 22 | 23 | `[slider setLeftExecuteBlock:^{ 24 | // do stuff after left option has been selected 25 | }];` 26 | 27 | ## Loading Indicator 28 | 29 | The slider has a built-in activity indicator for convenience. To turn the activity indicator on: 30 | 31 | `[slider setLoading:YES];` 32 | 33 | The Demo project included also demonstrates how this can be used in your code. 34 | 35 | ## Embedding in Table/ScrollViews 36 | 37 | If you embed the slider in a tableView (e.g. in a UITableViewCell) be sure to call: 38 | 39 | `[tableView setCanCancelContentTouches:NO];` 40 | 41 | This will prevent the table/scrollView from scrolling vertically while the user is pressing down on the slider, which leads to a much better user experience. 42 | 43 | ## Customisation 44 | 45 | You can subclass any of the slider's internal components, and then implement any/all of the following methods in your delegate: 46 | 47 | `-(JMCenterView *)sliderCenterViewForSlider:(JMSlider *)slider` 48 | 49 | `-(JMSideView *)sliderLeftViewForSlider:(JMSlider *)slider` 50 | 51 | `-(JMSideView *)sliderRightViewForSlider:(JMSlider *)slider` 52 | 53 | `-(JMSliderTrack *)sliderTrackViewForSlider:(JMSlider *)slider` 54 | 55 | For example, Alien Blue subclasses JMCenterView to draw a dark version of the toggle in Night Mode. 56 | 57 | ## Acknowledgements 58 | 59 | This project uses the UIView+Positioning and UIView+Size categories developed by the very talented [Kevin O'Neill](https://github.com/kevinoneill/Useful-Bits). 60 | 61 | ## License 62 | 63 | JMSlider is BSD licensed, so you can freely use it in commercial applications. 64 | -------------------------------------------------------------------------------- /Demo/Classes/Helpers/CenteredTableViewController.m: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import "CenteredTableViewController.h" 4 | #import "UIView+Positioning.h" 5 | #import "UIView+JMNoise.h" 6 | 7 | @interface CenteredTableViewController() 8 | @property (nonatomic,retain) UIView * viewForDemo; 9 | @end 10 | 11 | @implementation CenteredTableViewController 12 | 13 | @synthesize viewForDemo = viewForDemo_; 14 | 15 | - (void)dealloc; 16 | { 17 | self.viewForDemo = nil; 18 | [super dealloc]; 19 | } 20 | 21 | - (void)loadView; 22 | { 23 | [super loadView]; 24 | 25 | UIView * tableBackgroundView = [[[UIView alloc] initWithFrame:self.tableView.bounds] autorelease]; 26 | [tableBackgroundView applyNoiseWithOpacity:0.2]; 27 | self.tableView.backgroundView = tableBackgroundView; 28 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 29 | 30 | UIView * tableHeader = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, self.tableView.bounds.size.height / 2 - (self.viewForDemo.frame.size.height / 2))] autorelease]; 31 | tableHeader.backgroundColor = [UIColor clearColor]; 32 | [self.tableView setTableHeaderView:tableHeader]; 33 | } 34 | 35 | - (UITableViewCell *)demoCell; 36 | { 37 | UITableViewCell * cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"DemoCell"] autorelease]; 38 | [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; 39 | 40 | UIView * viewForDemo = [self viewForDemo]; 41 | viewForDemo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; 42 | [cell addSubview:viewForDemo]; 43 | [viewForDemo centerInSuperView]; 44 | 45 | return cell; 46 | } 47 | 48 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 49 | { 50 | return 1; 51 | } 52 | 53 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 54 | { 55 | return 1; 56 | } 57 | 58 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; 59 | { 60 | return self.viewForDemo.frame.size.height; 61 | } 62 | 63 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 64 | { 65 | return [self demoCell]; 66 | } 67 | 68 | - (id)initWithCenteredView:(UIView *)centeredView; 69 | { 70 | self = [super initWithStyle:UITableViewStylePlain]; 71 | if (self) 72 | { 73 | self.viewForDemo = centeredView; 74 | } 75 | return self; 76 | } 77 | 78 | + (UITableView *) tableViewWithCenteredView:(UIView *)centeredView; 79 | { 80 | CenteredTableViewController * viewController = [[[CenteredTableViewController alloc] initWithCenteredView:centeredView] autorelease]; 81 | return viewController.tableView; 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /JMSlider/Categories/UIView+Positioning.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, Kevin O'Neill 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // * Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // * Neither the name UsefulBits nor the names of its contributors may be used 15 | // to endorse or promote products derived from this software without specific 16 | // prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | #import "UIView+Positioning.h" 30 | #import "UIView+Size.h" 31 | 32 | @implementation UIView (Positioning) 33 | 34 | - (void)centerInRect:(CGRect)rect; 35 | { 36 | [self setCenter:CGPointMake(floorf(CGRectGetMidX(rect)) + ((int)floorf([self width]) % 2 ? .5 : 0) , floorf(CGRectGetMidY(rect)) + ((int)floorf([self height]) % 2 ? .5 : 0))]; 37 | } 38 | 39 | - (void)centerVerticallyInRect:(CGRect)rect; 40 | { 41 | [self setCenter:CGPointMake([self center].x, floorf(CGRectGetMidY(rect)) + ((int)floorf([self height]) % 2 ? .5 : 0))]; 42 | } 43 | 44 | - (void)centerHorizontallyInRect:(CGRect)rect; 45 | { 46 | [self setCenter:CGPointMake(floorf(CGRectGetMidX(rect)) + ((int)floorf([self width]) % 2 ? .5 : 0), [self center].y)]; 47 | } 48 | 49 | - (void)centerInSuperView; 50 | { 51 | [self centerInRect:[[self superview] bounds]]; 52 | } 53 | - (void)centerVerticallyInSuperView; 54 | { 55 | [self centerVerticallyInRect:[[self superview] bounds]]; 56 | } 57 | - (void)centerHorizontallyInSuperView; 58 | { 59 | [self centerHorizontallyInRect:[[self superview] bounds]]; 60 | } 61 | 62 | - (void)centerHorizontallyBelow:(UIView *)view padding:(CGFloat)padding; 63 | { 64 | // for now, could use screen relative positions. 65 | NSAssert([self superview] == [view superview], @"views must have the same parent"); 66 | 67 | [self setCenter:CGPointMake([view center].x, 68 | floorf(padding + CGRectGetMaxY([view frame]) + ([self height] / 2)))]; 69 | } 70 | 71 | - (void)centerHorizontallyBelow:(UIView *)view; 72 | { 73 | [self centerHorizontallyBelow:view padding:0]; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /JMSlider/Categories/UIView+Size.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011, Kevin O'Neill 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // * Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // * Neither the name UsefulBits nor the names of its contributors may be used 15 | // to endorse or promote products derived from this software without specific 16 | // prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | #import "UIView+Size.h" 30 | 31 | @implementation UIView (Size) 32 | 33 | - (void)setSize:(CGSize)size; 34 | { 35 | CGPoint origin = [self frame].origin; 36 | 37 | [self setFrame:CGRectMake(origin.x, origin.y, size.width, size.height)]; 38 | } 39 | 40 | - (CGSize)size; 41 | { 42 | return [self frame].size; 43 | } 44 | 45 | - (CGFloat)left; 46 | { 47 | return CGRectGetMinX([self frame]); 48 | } 49 | 50 | - (void)setLeft:(CGFloat)x; 51 | { 52 | CGRect frame = [self frame]; 53 | frame.origin.x = x; 54 | [self setFrame:frame]; 55 | } 56 | 57 | - (CGFloat)top; 58 | { 59 | return CGRectGetMinY([self frame]); 60 | } 61 | 62 | - (void)setTop:(CGFloat)y; 63 | { 64 | CGRect frame = [self frame]; 65 | frame.origin.y = y; 66 | [self setFrame:frame]; 67 | } 68 | 69 | - (CGFloat)right; 70 | { 71 | return CGRectGetMaxX([self frame]); 72 | } 73 | 74 | - (void)setRight:(CGFloat)right; 75 | { 76 | CGRect frame = [self frame]; 77 | frame.origin.x = right - frame.size.width; 78 | 79 | [self setFrame:frame]; 80 | } 81 | 82 | - (CGFloat)bottom; 83 | { 84 | return CGRectGetMaxY([self frame]); 85 | } 86 | 87 | - (void)setBottom:(CGFloat)bottom; 88 | { 89 | CGRect frame = [self frame]; 90 | frame.origin.y = bottom - frame.size.height; 91 | 92 | [self setFrame:frame]; 93 | } 94 | 95 | - (CGFloat)centerX; 96 | { 97 | return [self center].x; 98 | } 99 | 100 | - (void)setCenterX:(CGFloat)centerX; 101 | { 102 | [self setCenter:CGPointMake(centerX, self.center.y)]; 103 | } 104 | 105 | - (CGFloat)centerY; 106 | { 107 | return [self center].y; 108 | } 109 | 110 | - (void)setCenterY:(CGFloat)centerY; 111 | { 112 | [self setCenter:CGPointMake(self.center.x, centerY)]; 113 | } 114 | 115 | - (CGFloat)width; 116 | { 117 | return CGRectGetWidth([self frame]); 118 | } 119 | 120 | - (void)setWidth:(CGFloat)width; 121 | { 122 | CGRect frame = [self frame]; 123 | frame.size.width = width; 124 | 125 | [self setFrame:CGRectStandardize(frame)]; 126 | } 127 | 128 | - (CGFloat)height; 129 | { 130 | return CGRectGetHeight([self frame]); 131 | } 132 | 133 | - (void)setHeight:(CGFloat)height; 134 | { 135 | CGRect frame = [self frame]; 136 | frame.size.height = height; 137 | 138 | [self setFrame:CGRectStandardize(frame)]; 139 | } 140 | 141 | @end 142 | -------------------------------------------------------------------------------- /Demo/Classes/Helpers/UIView+JMNoise.m: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey 2 | 3 | #import 4 | #import "UIView+JMNoise.h" 5 | #include 6 | 7 | #define kNoiseTileDimension 50 8 | #define kNoiseIntensity 250 9 | #define kNoiseDefaultOpacity 0.4 10 | #define kNoisePixelWidth 0.3 11 | 12 | #define JM_SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) 13 | 14 | #pragma Mark - 15 | #pragma Mark - Noise Layer 16 | 17 | @interface NoiseLayer : CALayer 18 | + (UIImage *)noiseTileImage; 19 | + (void)drawPixelInContext:(CGContextRef)context point:(CGPoint)point width:(CGFloat)width opacity:(CGFloat)opacity whiteLevel:(CGFloat)whiteLevel; 20 | @end 21 | 22 | @implementation NoiseLayer 23 | 24 | static UIImage * JMNoiseImage; 25 | 26 | - (void)setFrame:(CGRect)frame; 27 | { 28 | [super setFrame:frame]; 29 | [self setNeedsDisplay]; 30 | } 31 | 32 | + (void)drawPixelInContext:(CGContextRef)context point:(CGPoint)point width:(CGFloat)width opacity:(CGFloat)opacity whiteLevel:(CGFloat)whiteLevel; 33 | { 34 | CGColorRef fillColor = [UIColor colorWithWhite:whiteLevel alpha:opacity].CGColor; 35 | CGContextSetFillColor(context, CGColorGetComponents(fillColor)); 36 | CGRect pointRect = CGRectMake(point.x - (width/2), point.y - (width/2), width, width); 37 | CGContextFillEllipseInRect(context, pointRect); 38 | } 39 | 40 | + (UIImage *)noiseTileImage; 41 | { 42 | if (!JMNoiseImage) 43 | { 44 | #ifndef __clang_analyzer__ 45 | CGFloat imageScale; 46 | 47 | if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) 48 | { 49 | imageScale = [[UIScreen mainScreen] scale]; 50 | } 51 | else 52 | { 53 | imageScale = 1; 54 | } 55 | 56 | NSUInteger imageDimension = imageScale * kNoiseTileDimension; 57 | 58 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 59 | CGContextRef context = CGBitmapContextCreate(nil,imageDimension,imageDimension,8,0, 60 | colorSpace,kCGImageAlphaPremultipliedLast); 61 | CFRelease(colorSpace); 62 | 63 | for (int i=0; i<(kNoiseTileDimension * kNoiseIntensity); i++) 64 | { 65 | int x = arc4random() % (imageDimension + 1); 66 | int y = arc4random() % (imageDimension + 1); 67 | int opacity = arc4random() % 100; 68 | CGFloat whiteLevel = arc4random() % 100; 69 | [NoiseLayer drawPixelInContext:context point:CGPointMake(x, y) width:(kNoisePixelWidth * imageScale) opacity:(opacity) whiteLevel:(whiteLevel / 100.)]; 70 | } 71 | 72 | CGImageRef imageRef = CGBitmapContextCreateImage(context); 73 | CGContextRelease(context); 74 | if (JM_SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"4.0")) 75 | { 76 | JMNoiseImage = [[UIImage alloc] initWithCGImage:imageRef scale:imageScale orientation:UIImageOrientationUp]; 77 | } 78 | else 79 | { 80 | JMNoiseImage = [[UIImage alloc] initWithCGImage:imageRef]; 81 | } 82 | #endif 83 | } 84 | return JMNoiseImage; 85 | } 86 | 87 | - (void)drawInContext:(CGContextRef)ctx; 88 | { 89 | UIGraphicsPushContext(ctx); 90 | [[NoiseLayer noiseTileImage] drawAsPatternInRect:self.bounds]; 91 | UIGraphicsPopContext(); 92 | } 93 | 94 | @end 95 | 96 | #pragma Mark - 97 | #pragma Mark - UIView implementations 98 | 99 | @implementation UIView (JMNoise) 100 | 101 | - (void)applyNoise; 102 | { 103 | [self applyNoiseWithOpacity:kNoiseDefaultOpacity]; 104 | } 105 | 106 | - (void)applyNoiseWithOpacity:(CGFloat)opacity atLayerIndex:(NSUInteger) layerIndex; 107 | { 108 | NoiseLayer * noiseLayer = [[[NoiseLayer alloc] init] autorelease]; 109 | [noiseLayer setFrame:self.bounds]; 110 | noiseLayer.masksToBounds = YES; 111 | noiseLayer.opacity = opacity; 112 | [self.layer insertSublayer:noiseLayer atIndex:layerIndex]; 113 | } 114 | 115 | - (void)applyNoiseWithOpacity:(CGFloat)opacity; 116 | { 117 | [self applyNoiseWithOpacity:opacity atLayerIndex:0]; 118 | } 119 | 120 | - (void)drawCGNoise; 121 | { 122 | [self drawCGNoiseWithOpacity:kNoiseDefaultOpacity]; 123 | } 124 | 125 | - (void)drawCGNoiseWithOpacity:(CGFloat)opacity; 126 | { 127 | [self drawCGNoiseWithOpacity:opacity blendMode:kCGBlendModeNormal]; 128 | } 129 | 130 | - (void)drawCGNoiseWithOpacity:(CGFloat)opacity blendMode:(CGBlendMode)blendMode; 131 | { 132 | CGContextRef context = UIGraphicsGetCurrentContext(); 133 | CGContextSaveGState(context); 134 | UIBezierPath * path = [UIBezierPath bezierPathWithRect:self.bounds]; 135 | CGContextAddPath(context, [path CGPath]); 136 | CGContextClip(context); 137 | CGContextSetBlendMode(context, blendMode); 138 | CGContextSetAlpha(context, opacity); 139 | [[NoiseLayer noiseTileImage] drawAsPatternInRect:self.bounds]; 140 | CGContextRestoreGState(context); 141 | } 142 | 143 | @end 144 | -------------------------------------------------------------------------------- /JMSlider/Internal/JMCenterView.m: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import "JMCenterView.h" 4 | #import "JMSlider.h" 5 | #import "UIView+Positioning.h" 6 | 7 | @interface JMCenterView() 8 | @property (assign) CGPoint touchStartPoint; 9 | @property (nonatomic,retain) UIActivityIndicatorView * activityView; 10 | - (CGPoint)touchPoint:(NSSet *)touches; 11 | - (void)drawButtonInRect:(CGRect)rect; 12 | - (CGSize)sizeOfButton; 13 | @end 14 | 15 | @implementation JMCenterView 16 | 17 | @synthesize touchStartPoint = touchStartPoint_; 18 | @synthesize activityView = activityView_; 19 | 20 | - (void)dealloc; 21 | { 22 | self.activityView = nil; 23 | [super dealloc]; 24 | } 25 | 26 | #pragma Mark - 27 | #pragma Mark - Wrappers for button (including padding) 28 | 29 | - (void)drawRect:(CGRect)rect; 30 | { 31 | CGRect buttonRect = CGRectInset(rect, kJMSliderButtonInvisiblePadding.width, kJMSliderButtonInvisiblePadding.height); 32 | [self drawButtonInRect:buttonRect]; 33 | } 34 | 35 | - (CGSize)sizeThatFits:(CGSize)size; 36 | { 37 | CGSize buttonSize = [self sizeOfButton]; 38 | return CGSizeMake(buttonSize.width + kJMSliderButtonInvisiblePadding.width * 2., buttonSize.height + kJMSliderButtonInvisiblePadding.height * 2.); 39 | } 40 | 41 | #pragma Mark - 42 | #pragma Mark - Button Drawing 43 | 44 | - (void)drawButtonInRect:(CGRect)rect; 45 | { 46 | [kJMButtonColor set]; 47 | UIBezierPath * background = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:20]; 48 | [background fill]; 49 | 50 | if (self.highlighted) 51 | { 52 | [kJMButtonOutlineColor set]; 53 | UIBezierPath * outline = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, -3., -3.) cornerRadius:20]; 54 | [outline stroke]; 55 | } 56 | 57 | if (!activityView_) 58 | { 59 | CGFloat textOpacity = 1. - fabs([self.slider slideRatio]); 60 | [[UIColor colorWithWhite:1. alpha:textOpacity] set]; 61 | [self.title drawInRect:CGRectOffset(rect, 0, kJMButtonPadding.height -1.) withFont:kJMButtonFont lineBreakMode:UILineBreakModeTailTruncation alignment:UITextAlignmentCenter]; 62 | } 63 | } 64 | 65 | - (CGSize)sizeOfButton; 66 | { 67 | CGSize titleSize = [self.title sizeWithFont:kJMButtonFont]; 68 | return CGSizeMake(titleSize.width + 2 * kJMButtonPadding.width, titleSize.height + 2 * kJMButtonPadding.height); 69 | } 70 | 71 | #pragma Mark - 72 | #pragma Mark - Convenience Methods 73 | 74 | - (CGPoint)touchPoint:(NSSet *)touches; 75 | { 76 | UITouch *touch = [touches anyObject]; 77 | CGPoint touchPoint = [touch locationInView:self.superview]; 78 | return touchPoint; 79 | } 80 | 81 | #pragma Mark - 82 | #pragma Mark - Touch Response 83 | 84 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; 85 | { 86 | [super touchesBegan:touches withEvent:event]; 87 | [self.slider setHighlightSlider:YES]; 88 | [self.slider updateWithSlideRatio:0.]; 89 | touchStartPoint_ = [[touches anyObject] locationInView:self]; 90 | } 91 | 92 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 93 | { 94 | [super touchesMoved:touches withEvent:event]; 95 | CGPoint touchPoint = [self touchPoint:touches]; 96 | CGPoint centerPoint = CGPointMake(touchPoint.x - touchStartPoint_.x + (self.bounds.size.width / 2), self.center.y); 97 | [self.slider setButtonCenterPosition:centerPoint animated:NO]; 98 | } 99 | 100 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 101 | { 102 | [super touchesCancelled:touches withEvent:event]; 103 | [self.slider releaseDragShouldCancel:YES]; 104 | } 105 | 106 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; 107 | { 108 | [super touchesEnded:touches withEvent:event]; 109 | [self.slider releaseDragShouldCancel:NO]; 110 | } 111 | 112 | #pragma Mark - 113 | #pragma Mark - Loading State 114 | 115 | - (void)setLoading:(BOOL)loading; 116 | { 117 | [self.activityView removeFromSuperview]; 118 | self.activityView = nil; 119 | 120 | if (loading) 121 | { 122 | self.activityView = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] autorelease]; 123 | self.activityView.autoresizesSubviews = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; 124 | [self.activityView startAnimating]; 125 | [self addSubview:self.activityView]; 126 | [self.activityView centerInSuperView]; 127 | } 128 | [self setNeedsDisplay]; 129 | } 130 | 131 | 132 | #pragma Mark - 133 | #pragma Mark - Factories 134 | 135 | - (id)initForSlider:(JMSlider *)slider withTitle:(NSString *)title; 136 | { 137 | self = [super initWithFrame:CGRectZero forSlider:slider]; 138 | if (self) 139 | { 140 | [self setExclusiveTouch:YES]; 141 | [self setTitle:title]; 142 | [self sizeToFit]; 143 | 144 | UITapGestureRecognizer * tapGesture = [[[UITapGestureRecognizer alloc] initWithTarget:slider action:@selector(tappedCenterView)] autorelease]; 145 | tapGesture.numberOfTapsRequired = 1; 146 | [self addGestureRecognizer:tapGesture]; 147 | } 148 | return self; 149 | } 150 | 151 | + (JMCenterView *)sliderButtonForSlider:(JMSlider *)slider withTitle:(NSString *)title; 152 | { 153 | JMCenterView * centerView = [[[JMCenterView alloc] initForSlider:slider withTitle:title] autorelease]; 154 | return centerView; 155 | } 156 | 157 | @end 158 | -------------------------------------------------------------------------------- /JMSlider/JMSlider.m: -------------------------------------------------------------------------------- 1 | // Created by Jason Morrissey - jasonmorrissey.org 2 | 3 | #import "JMSlider.h" 4 | #import "JMCenterView.h" 5 | #import "JMSliderTrack.h" 6 | #import "JMSideView.h" 7 | #import "UIView+Positioning.h" 8 | #import "UIView+Size.h" 9 | 10 | @interface JMSlider() 11 | 12 | @property (nonatomic,retain) JMCenterView * centerView; 13 | @property (nonatomic,retain) JMSliderTrack * trackView; 14 | @property (nonatomic,retain) JMSideView * leftView; 15 | @property (nonatomic,retain) JMSideView * rightView; 16 | @property (nonatomic,assign) id delegate; 17 | @property (assign) CGFloat currentSlideRatio; 18 | @property (assign) BOOL highlighted; 19 | @property (assign) BOOL suppressCallbacks; 20 | 21 | - (void)updateWithSlideRatio:(CGFloat)slideRatio; 22 | - (void)resetToCenter; 23 | 24 | - (JMCenterView *)generateCenterViewWithDefaultTitle:(NSString *)title; 25 | - (JMSideView *)generateLeftViewWithDefaultTitle:(NSString *)title; 26 | - (JMSideView *)generateRightViewWithDefaultTitle:(NSString *)title; 27 | - (JMSliderTrack *)generateTrackView; 28 | 29 | @end 30 | 31 | @implementation JMSlider 32 | 33 | #if NS_BLOCKS_AVAILABLE 34 | @synthesize leftExecuteBlock = leftExecuteBlock_; 35 | @synthesize centerExecuteBlock = centerExecuteBlock_; 36 | @synthesize rightExecuteBlock = rightExecuteBlock_; 37 | #endif 38 | @synthesize highlighted = highlighted_; 39 | @synthesize trackView = trackView_; 40 | @synthesize centerView = centerView_; 41 | @synthesize leftView = leftView_; 42 | @synthesize rightView = rightView_; 43 | @synthesize currentSlideRatio = currentSlideRatio_; 44 | @synthesize suppressCallbacks = suppressCallbacks_; 45 | @synthesize delegate = delegate_; 46 | 47 | - (void)dealloc; 48 | { 49 | #if NS_BLOCKS_AVAILABLE 50 | self.leftExecuteBlock = nil; 51 | self.centerExecuteBlock = nil; 52 | self.rightExecuteBlock = nil; 53 | #endif 54 | 55 | self.delegate = nil; 56 | self.trackView = nil; 57 | self.centerView = nil; 58 | self.leftView = nil; 59 | self.rightView = nil; 60 | [super dealloc]; 61 | } 62 | 63 | - (id)initWithFrame:(CGRect)frame centerTitle:(NSString *)centerTitle leftTitle:(NSString *)leftTitle rightTitle:(NSString *)rightTitle delegate:(id)delegate; 64 | { 65 | self = [super initWithFrame:frame]; 66 | if (self) 67 | { 68 | self.backgroundColor = [UIColor clearColor]; 69 | 70 | self.delegate = delegate; 71 | 72 | self.centerView = [self generateCenterViewWithDefaultTitle:centerTitle]; 73 | self.leftView = [self generateLeftViewWithDefaultTitle:leftTitle]; 74 | self.rightView = [self generateRightViewWithDefaultTitle:rightTitle]; 75 | self.trackView = [self generateTrackView]; 76 | 77 | [self addSubview:self.trackView]; 78 | [self addSubview:self.centerView]; 79 | [self addSubview:self.leftView]; 80 | [self addSubview:self.rightView]; 81 | 82 | [self.centerView centerInSuperView]; 83 | 84 | [self resetToCenter]; 85 | } 86 | return self; 87 | } 88 | 89 | - (void) layoutSubviews; 90 | { 91 | self.leftView.center = CGPointMake(self.leftView.itemOffset.x + [self trackLowCenter], self.leftView.itemOffset.y); 92 | self.rightView.center = CGPointMake(self.rightView.itemOffset.x + [self trackHighCenter], self.rightView.itemOffset.y); 93 | } 94 | 95 | - (void)resetToCenter; 96 | { 97 | [UIView beginAnimations:kJMSliderAnimationCenterButton context:self.centerView]; 98 | [UIView setAnimationBeginsFromCurrentState:YES]; 99 | [self.centerView centerInSuperView]; 100 | [self updateWithSlideRatio:0.]; 101 | [UIView commitAnimations]; 102 | self.suppressCallbacks = NO; 103 | [self setHighlightSlider:NO]; 104 | } 105 | 106 | - (void)updateWithSlideRatio:(CGFloat)slideRatio; 107 | { 108 | self.currentSlideRatio = slideRatio; 109 | 110 | self.rightView.alpha = self.highlighted ? kJMSliderMinimumFadeOpacity : 0.; 111 | self.leftView.alpha = self.highlighted ? kJMSliderMinimumFadeOpacity : 0.; 112 | 113 | if (slideRatio > kJMSliderMinimumMovementBuffer) 114 | { 115 | self.rightView.alpha = slideRatio; 116 | } 117 | else if (slideRatio < (-1. * kJMSliderMinimumMovementBuffer)) 118 | { 119 | self.leftView.alpha = (slideRatio * -1.); 120 | } 121 | } 122 | 123 | - (void)setButtonCenterPosition:(CGPoint)centerPoint animated:(BOOL)animated; 124 | { 125 | CGFloat trackHighCenter = [self trackHighCenter]; 126 | CGFloat trackLowCenter = [self trackLowCenter]; 127 | if (centerPoint.x > trackHighCenter) return; 128 | if (centerPoint.x < trackLowCenter) return; 129 | 130 | self.centerView.center = centerPoint; 131 | 132 | [self updateWithSlideRatio:((centerPoint.x - trackLowCenter) / (trackHighCenter - trackLowCenter) - 0.5) * 2]; 133 | } 134 | 135 | 136 | 137 | #pragma Mark - 138 | #pragma Mark - Accessors for Subviews 139 | 140 | - (CGFloat)trackLowCenter; 141 | { 142 | return (self.centerView.width / 2.); 143 | } 144 | 145 | - (CGFloat)trackHighCenter; 146 | { 147 | return self.bounds.size.width - (self.centerView.width / 2.); 148 | } 149 | 150 | - (CGFloat)centerViewWidth; 151 | { 152 | return self.centerView.size.width; 153 | } 154 | 155 | - (CGFloat)slideRatio; 156 | { 157 | return self.currentSlideRatio; 158 | } 159 | 160 | #pragma Mark - 161 | #pragma Mark - Co-ordinators for Subviews 162 | 163 | - (void)setHighlightSlider:(BOOL)highlighted; 164 | { 165 | highlighted_ = highlighted; 166 | 167 | self.centerView.highlighted = highlighted; 168 | self.trackView.highlighted = highlighted; 169 | self.leftView.highlighted = highlighted; 170 | self.rightView.highlighted = highlighted; 171 | 172 | [self updateWithSlideRatio:self.currentSlideRatio]; 173 | } 174 | 175 | - (void)releaseDragShouldCancel:(BOOL)cancelled; 176 | { 177 | if (!self.suppressCallbacks && self.slideRatio < (-1. + kJMSliderOptionActivationMargin)) 178 | { 179 | self.suppressCallbacks = YES; 180 | if ([self.delegate respondsToSelector:@selector(slider:didSelect:)]) 181 | { 182 | [self.delegate slider:self didSelect:JMSliderSelectionLeft]; 183 | } 184 | #if NS_BLOCKS_AVAILABLE 185 | if (leftExecuteBlock_) leftExecuteBlock_(); 186 | #endif 187 | [self performSelector:@selector(resetToCenter) withObject:nil afterDelay:0.8]; 188 | } 189 | else if (!self.suppressCallbacks && self.slideRatio > (1. - kJMSliderOptionActivationMargin)) 190 | { 191 | self.suppressCallbacks = YES; 192 | if ([self.delegate respondsToSelector:@selector(slider:didSelect:)]) 193 | { 194 | [self.delegate slider:self didSelect:JMSliderSelectionRight]; 195 | } 196 | #if NS_BLOCKS_AVAILABLE 197 | if (rightExecuteBlock_) rightExecuteBlock_(); 198 | #endif 199 | [self performSelector:@selector(resetToCenter) withObject:nil afterDelay:0.8]; 200 | } 201 | else 202 | { 203 | [self resetToCenter]; 204 | } 205 | [self setHighlightSlider:NO]; 206 | } 207 | 208 | - (void)tappedCenterView; 209 | { 210 | if (fabs(self.slideRatio) < kJMSliderOptionActivationMargin) 211 | { 212 | if ([self.delegate respondsToSelector:@selector(slider:didSelect:)]) 213 | { 214 | [self.delegate slider:self didSelect:JMSliderSelectionCenter]; 215 | } 216 | #if NS_BLOCKS_AVAILABLE 217 | if (centerExecuteBlock_) centerExecuteBlock_(); 218 | #endif 219 | } 220 | } 221 | 222 | - (void)setLoading:(BOOL)loading; 223 | { 224 | [self.centerView setLoading:loading]; 225 | } 226 | 227 | #pragma Mark - 228 | #pragma Mark - Subview Generation 229 | 230 | - (JMCenterView *)generateCenterViewWithDefaultTitle:(NSString *)title; 231 | { 232 | if ([self.delegate respondsToSelector:@selector(sliderCenterViewForSlider:)]) 233 | return [self.delegate sliderCenterViewForSlider:self]; 234 | else 235 | return [JMCenterView sliderButtonForSlider:self withTitle:title]; 236 | } 237 | 238 | - (JMSideView *)generateLeftViewWithDefaultTitle:(NSString *)title; 239 | { 240 | if ([self.delegate respondsToSelector:@selector(sliderLeftViewForSlider:)]) 241 | return [self.delegate sliderLeftViewForSlider:self]; 242 | else 243 | return [JMSideView sideViewWithTitle:title]; 244 | } 245 | 246 | - (JMSideView *)generateRightViewWithDefaultTitle:(NSString *)title; 247 | { 248 | if ([self.delegate respondsToSelector:@selector(sliderRightViewForSlider:)]) 249 | return [self.delegate sliderRightViewForSlider:self]; 250 | else 251 | return [JMSideView sideViewWithTitle:title]; 252 | } 253 | 254 | - (JMSliderTrack *)generateTrackView; 255 | { 256 | if ([self.delegate respondsToSelector:@selector(sliderTrackViewForSlider:)]) 257 | return [self.delegate sliderTrackViewForSlider:self]; 258 | else 259 | return [JMSliderTrack sliderTrackForSlider:self]; 260 | } 261 | 262 | #pragma Mark - 263 | #pragma Mark - Factories 264 | 265 | + (JMSlider *) sliderWithFrame:(CGRect)frame centerTitle:(NSString *)centerTitle leftTitle:(NSString *)leftTitle rightTitle:(NSString *)rightTitle delegate:(id)delegate; 266 | { 267 | JMSlider * slider = [[[JMSlider alloc] initWithFrame:frame centerTitle:centerTitle leftTitle:leftTitle rightTitle:rightTitle delegate:delegate] autorelease]; 268 | return slider; 269 | } 270 | 271 | + (JMSlider *) sliderWithFrame:(CGRect)frame delegate:(id)delegate; 272 | { 273 | return [[self class] sliderWithFrame:frame centerTitle:nil leftTitle:nil rightTitle:nil delegate:delegate]; 274 | } 275 | 276 | @end 277 | -------------------------------------------------------------------------------- /JMSlider.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4719172713A4875400567E9E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4719172513A4875400567E9E /* InfoPlist.strings */; }; 11 | 4719172A13A4875400567E9E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4719172913A4875400567E9E /* main.m */; }; 12 | 4719176B13A490F500567E9E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4719176A13A490F500567E9E /* UIKit.framework */; }; 13 | 4719176D13A490FB00567E9E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4719176C13A490FB00567E9E /* Foundation.framework */; }; 14 | 4719176F13A4910000567E9E /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4719176E13A4910000567E9E /* QuartzCore.framework */; }; 15 | 4719177113A4910600567E9E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4719177013A4910600567E9E /* CoreGraphics.framework */; }; 16 | 4788298413C1CE5A007E0509 /* UIView+Positioning.m in Sources */ = {isa = PBXBuildFile; fileRef = 4788297D13C1CE5A007E0509 /* UIView+Positioning.m */; }; 17 | 4788298513C1CE5A007E0509 /* UIView+Size.m in Sources */ = {isa = PBXBuildFile; fileRef = 4788297F13C1CE5A007E0509 /* UIView+Size.m */; }; 18 | 4788298713C1CE5A007E0509 /* JMCenterView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4788298313C1CE5A007E0509 /* JMCenterView.m */; }; 19 | 4788298913C1CE83007E0509 /* JMSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4788298813C1CE83007E0509 /* JMSlider.m */; }; 20 | 47B98CF013C1E2FF0042592E /* JMSideView.m in Sources */ = {isa = PBXBuildFile; fileRef = 47B98CEF13C1E2FF0042592E /* JMSideView.m */; }; 21 | 47EB6BE113C821E7004D0308 /* CenteredTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 47EB6BDC13C821E7004D0308 /* CenteredTableViewController.m */; }; 22 | 47EB6BE213C821E7004D0308 /* DemoAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 47EB6BDE13C821E7004D0308 /* DemoAppDelegate.m */; }; 23 | 47EB6BE313C821E7004D0308 /* UIView+JMNoise.m in Sources */ = {isa = PBXBuildFile; fileRef = 47EB6BE013C821E7004D0308 /* UIView+JMNoise.m */; }; 24 | 47F343E113A4AF6F00EC49ED /* DemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 47F343DE13A4AF6F00EC49ED /* DemoViewController.m */; }; 25 | 886B464D13C2945500191AD9 /* JMSliderTrack.m in Sources */ = {isa = PBXBuildFile; fileRef = 886B464C13C2945500191AD9 /* JMSliderTrack.m */; }; 26 | 886B465413C29D0100191AD9 /* JMSliderComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 886B465313C29D0100191AD9 /* JMSliderComponent.m */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 4719171D13A4875400567E9E /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 4719172413A4875400567E9E /* Demo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Demo-Info.plist"; sourceTree = ""; }; 32 | 4719172613A4875400567E9E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 33 | 4719172813A4875400567E9E /* Demo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Demo-Prefix.pch"; sourceTree = ""; }; 34 | 4719172913A4875400567E9E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | 4719176A13A490F500567E9E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 36 | 4719176C13A490FB00567E9E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 37 | 4719176E13A4910000567E9E /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 38 | 4719177013A4910600567E9E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 39 | 4788297C13C1CE5A007E0509 /* UIView+Positioning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Positioning.h"; sourceTree = ""; }; 40 | 4788297D13C1CE5A007E0509 /* UIView+Positioning.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Positioning.m"; sourceTree = ""; }; 41 | 4788297E13C1CE5A007E0509 /* UIView+Size.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Size.h"; sourceTree = ""; }; 42 | 4788297F13C1CE5A007E0509 /* UIView+Size.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Size.m"; sourceTree = ""; }; 43 | 4788298213C1CE5A007E0509 /* JMCenterView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMCenterView.h; sourceTree = ""; }; 44 | 4788298313C1CE5A007E0509 /* JMCenterView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JMCenterView.m; sourceTree = ""; }; 45 | 4788298813C1CE83007E0509 /* JMSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JMSlider.m; sourceTree = ""; }; 46 | 47B98CEE13C1E2FF0042592E /* JMSideView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMSideView.h; sourceTree = ""; }; 47 | 47B98CEF13C1E2FF0042592E /* JMSideView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JMSideView.m; sourceTree = ""; }; 48 | 47E1AEEF13C1C7B200269D16 /* JMSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMSlider.h; sourceTree = ""; }; 49 | 47EB6BDB13C821E7004D0308 /* CenteredTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CenteredTableViewController.h; sourceTree = ""; }; 50 | 47EB6BDC13C821E7004D0308 /* CenteredTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CenteredTableViewController.m; sourceTree = ""; }; 51 | 47EB6BDD13C821E7004D0308 /* DemoAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoAppDelegate.h; sourceTree = ""; }; 52 | 47EB6BDE13C821E7004D0308 /* DemoAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoAppDelegate.m; sourceTree = ""; }; 53 | 47EB6BDF13C821E7004D0308 /* UIView+JMNoise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+JMNoise.h"; sourceTree = ""; }; 54 | 47EB6BE013C821E7004D0308 /* UIView+JMNoise.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+JMNoise.m"; sourceTree = ""; }; 55 | 47F343DD13A4AF6F00EC49ED /* DemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoViewController.h; sourceTree = ""; }; 56 | 47F343DE13A4AF6F00EC49ED /* DemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoViewController.m; sourceTree = ""; }; 57 | 886B464B13C2945500191AD9 /* JMSliderTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMSliderTrack.h; sourceTree = ""; }; 58 | 886B464C13C2945500191AD9 /* JMSliderTrack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JMSliderTrack.m; sourceTree = ""; }; 59 | 886B464F13C2956F00191AD9 /* JMSliderConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMSliderConstants.h; sourceTree = ""; }; 60 | 886B465213C29D0000191AD9 /* JMSliderComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMSliderComponent.h; sourceTree = ""; }; 61 | 886B465313C29D0100191AD9 /* JMSliderComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JMSliderComponent.m; sourceTree = ""; }; 62 | /* End PBXFileReference section */ 63 | 64 | /* Begin PBXFrameworksBuildPhase section */ 65 | 4719171A13A4875400567E9E /* Frameworks */ = { 66 | isa = PBXFrameworksBuildPhase; 67 | buildActionMask = 2147483647; 68 | files = ( 69 | 4719177113A4910600567E9E /* CoreGraphics.framework in Frameworks */, 70 | 4719176F13A4910000567E9E /* QuartzCore.framework in Frameworks */, 71 | 4719176D13A490FB00567E9E /* Foundation.framework in Frameworks */, 72 | 4719176B13A490F500567E9E /* UIKit.framework in Frameworks */, 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | /* End PBXFrameworksBuildPhase section */ 77 | 78 | /* Begin PBXGroup section */ 79 | 471916DE13A4833A00567E9E = { 80 | isa = PBXGroup; 81 | children = ( 82 | 471916EE13A4833A00567E9E /* JMSlider */, 83 | 4719172213A4875400567E9E /* Demo */, 84 | 471916EA13A4833A00567E9E /* Products */, 85 | ); 86 | sourceTree = ""; 87 | }; 88 | 471916EA13A4833A00567E9E /* Products */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 4719171D13A4875400567E9E /* Demo.app */, 92 | ); 93 | name = Products; 94 | sourceTree = ""; 95 | }; 96 | 471916EE13A4833A00567E9E /* JMSlider */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 47E1AEEF13C1C7B200269D16 /* JMSlider.h */, 100 | 4788298813C1CE83007E0509 /* JMSlider.m */, 101 | 4788297B13C1CE5A007E0509 /* Categories */, 102 | 4788298013C1CE5A007E0509 /* Internal */, 103 | ); 104 | path = JMSlider; 105 | sourceTree = ""; 106 | }; 107 | 4719172213A4875400567E9E /* Demo */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 47F343DA13A4AF6F00EC49ED /* Classes */, 111 | 47F343DF13A4AF6F00EC49ED /* Resources */, 112 | 4719175413A4902900567E9E /* Frameworks */, 113 | 4719172313A4875400567E9E /* Supporting Files */, 114 | ); 115 | path = Demo; 116 | sourceTree = ""; 117 | }; 118 | 4719172313A4875400567E9E /* Supporting Files */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 4719172413A4875400567E9E /* Demo-Info.plist */, 122 | 4719172513A4875400567E9E /* InfoPlist.strings */, 123 | 4719172813A4875400567E9E /* Demo-Prefix.pch */, 124 | 4719172913A4875400567E9E /* main.m */, 125 | ); 126 | name = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | 4719175413A4902900567E9E /* Frameworks */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 4719177013A4910600567E9E /* CoreGraphics.framework */, 133 | 4719176E13A4910000567E9E /* QuartzCore.framework */, 134 | 4719176C13A490FB00567E9E /* Foundation.framework */, 135 | 4719176A13A490F500567E9E /* UIKit.framework */, 136 | ); 137 | name = Frameworks; 138 | sourceTree = ""; 139 | }; 140 | 4788297B13C1CE5A007E0509 /* Categories */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 4788297C13C1CE5A007E0509 /* UIView+Positioning.h */, 144 | 4788297D13C1CE5A007E0509 /* UIView+Positioning.m */, 145 | 4788297E13C1CE5A007E0509 /* UIView+Size.h */, 146 | 4788297F13C1CE5A007E0509 /* UIView+Size.m */, 147 | ); 148 | path = Categories; 149 | sourceTree = ""; 150 | }; 151 | 4788298013C1CE5A007E0509 /* Internal */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | 886B464F13C2956F00191AD9 /* JMSliderConstants.h */, 155 | 4788298213C1CE5A007E0509 /* JMCenterView.h */, 156 | 4788298313C1CE5A007E0509 /* JMCenterView.m */, 157 | 47B98CEE13C1E2FF0042592E /* JMSideView.h */, 158 | 47B98CEF13C1E2FF0042592E /* JMSideView.m */, 159 | 886B464B13C2945500191AD9 /* JMSliderTrack.h */, 160 | 886B464C13C2945500191AD9 /* JMSliderTrack.m */, 161 | 886B465213C29D0000191AD9 /* JMSliderComponent.h */, 162 | 886B465313C29D0100191AD9 /* JMSliderComponent.m */, 163 | ); 164 | path = Internal; 165 | sourceTree = ""; 166 | }; 167 | 47EB6BDA13C821E7004D0308 /* Helpers */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 47EB6BDB13C821E7004D0308 /* CenteredTableViewController.h */, 171 | 47EB6BDC13C821E7004D0308 /* CenteredTableViewController.m */, 172 | 47EB6BDD13C821E7004D0308 /* DemoAppDelegate.h */, 173 | 47EB6BDE13C821E7004D0308 /* DemoAppDelegate.m */, 174 | 47EB6BDF13C821E7004D0308 /* UIView+JMNoise.h */, 175 | 47EB6BE013C821E7004D0308 /* UIView+JMNoise.m */, 176 | ); 177 | path = Helpers; 178 | sourceTree = ""; 179 | }; 180 | 47F343DA13A4AF6F00EC49ED /* Classes */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | 47EB6BDA13C821E7004D0308 /* Helpers */, 184 | 47F343DD13A4AF6F00EC49ED /* DemoViewController.h */, 185 | 47F343DE13A4AF6F00EC49ED /* DemoViewController.m */, 186 | ); 187 | path = Classes; 188 | sourceTree = ""; 189 | }; 190 | 47F343DF13A4AF6F00EC49ED /* Resources */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | ); 194 | path = Resources; 195 | sourceTree = ""; 196 | }; 197 | /* End PBXGroup section */ 198 | 199 | /* Begin PBXNativeTarget section */ 200 | 4719171C13A4875400567E9E /* Demo */ = { 201 | isa = PBXNativeTarget; 202 | buildConfigurationList = 4719173713A4875400567E9E /* Build configuration list for PBXNativeTarget "Demo" */; 203 | buildPhases = ( 204 | 4719171913A4875400567E9E /* Sources */, 205 | 4719171A13A4875400567E9E /* Frameworks */, 206 | 4719171B13A4875400567E9E /* Resources */, 207 | ); 208 | buildRules = ( 209 | ); 210 | dependencies = ( 211 | ); 212 | name = Demo; 213 | productName = Demo; 214 | productReference = 4719171D13A4875400567E9E /* Demo.app */; 215 | productType = "com.apple.product-type.application"; 216 | }; 217 | /* End PBXNativeTarget section */ 218 | 219 | /* Begin PBXProject section */ 220 | 471916E013A4833A00567E9E /* Project object */ = { 221 | isa = PBXProject; 222 | attributes = { 223 | ORGANIZATIONNAME = "The Design Shed"; 224 | }; 225 | buildConfigurationList = 471916E313A4833A00567E9E /* Build configuration list for PBXProject "JMSlider" */; 226 | compatibilityVersion = "Xcode 3.2"; 227 | developmentRegion = English; 228 | hasScannedForEncodings = 0; 229 | knownRegions = ( 230 | en, 231 | ); 232 | mainGroup = 471916DE13A4833A00567E9E; 233 | productRefGroup = 471916EA13A4833A00567E9E /* Products */; 234 | projectDirPath = ""; 235 | projectRoot = ""; 236 | targets = ( 237 | 4719171C13A4875400567E9E /* Demo */, 238 | ); 239 | }; 240 | /* End PBXProject section */ 241 | 242 | /* Begin PBXResourcesBuildPhase section */ 243 | 4719171B13A4875400567E9E /* Resources */ = { 244 | isa = PBXResourcesBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | 4719172713A4875400567E9E /* InfoPlist.strings in Resources */, 248 | ); 249 | runOnlyForDeploymentPostprocessing = 0; 250 | }; 251 | /* End PBXResourcesBuildPhase section */ 252 | 253 | /* Begin PBXSourcesBuildPhase section */ 254 | 4719171913A4875400567E9E /* Sources */ = { 255 | isa = PBXSourcesBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | 4719172A13A4875400567E9E /* main.m in Sources */, 259 | 47F343E113A4AF6F00EC49ED /* DemoViewController.m in Sources */, 260 | 4788298413C1CE5A007E0509 /* UIView+Positioning.m in Sources */, 261 | 4788298513C1CE5A007E0509 /* UIView+Size.m in Sources */, 262 | 4788298713C1CE5A007E0509 /* JMCenterView.m in Sources */, 263 | 4788298913C1CE83007E0509 /* JMSlider.m in Sources */, 264 | 47B98CF013C1E2FF0042592E /* JMSideView.m in Sources */, 265 | 886B464D13C2945500191AD9 /* JMSliderTrack.m in Sources */, 266 | 886B465413C29D0100191AD9 /* JMSliderComponent.m in Sources */, 267 | 47EB6BE113C821E7004D0308 /* CenteredTableViewController.m in Sources */, 268 | 47EB6BE213C821E7004D0308 /* DemoAppDelegate.m in Sources */, 269 | 47EB6BE313C821E7004D0308 /* UIView+JMNoise.m in Sources */, 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | /* End PBXSourcesBuildPhase section */ 274 | 275 | /* Begin PBXVariantGroup section */ 276 | 4719172513A4875400567E9E /* InfoPlist.strings */ = { 277 | isa = PBXVariantGroup; 278 | children = ( 279 | 4719172613A4875400567E9E /* en */, 280 | ); 281 | name = InfoPlist.strings; 282 | sourceTree = ""; 283 | }; 284 | /* End PBXVariantGroup section */ 285 | 286 | /* Begin XCBuildConfiguration section */ 287 | 471916F113A4833A00567E9E /* Debug */ = { 288 | isa = XCBuildConfiguration; 289 | buildSettings = { 290 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 291 | GCC_C_LANGUAGE_STANDARD = gnu99; 292 | GCC_OPTIMIZATION_LEVEL = 0; 293 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG; 294 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 295 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 296 | GCC_VERSION = com.apple.compilers.llvmgcc42; 297 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 298 | GCC_WARN_UNUSED_VARIABLE = YES; 299 | IPHONEOS_DEPLOYMENT_TARGET = 4.3; 300 | SDKROOT = iphoneos; 301 | }; 302 | name = Debug; 303 | }; 304 | 471916F213A4833A00567E9E /* Release */ = { 305 | isa = XCBuildConfiguration; 306 | buildSettings = { 307 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 308 | GCC_C_LANGUAGE_STANDARD = gnu99; 309 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 310 | GCC_VERSION = com.apple.compilers.llvmgcc42; 311 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 312 | GCC_WARN_UNUSED_VARIABLE = YES; 313 | IPHONEOS_DEPLOYMENT_TARGET = 4.3; 314 | SDKROOT = iphoneos; 315 | }; 316 | name = Release; 317 | }; 318 | 4719173813A4875400567E9E /* Debug */ = { 319 | isa = XCBuildConfiguration; 320 | buildSettings = { 321 | ALWAYS_SEARCH_USER_PATHS = NO; 322 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 323 | COPY_PHASE_STRIP = NO; 324 | FRAMEWORK_SEARCH_PATHS = ( 325 | "$(inherited)", 326 | "\"$(SRCROOT)\"", 327 | ); 328 | GCC_DYNAMIC_NO_PIC = NO; 329 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 330 | GCC_PREFIX_HEADER = "Demo/Demo-Prefix.pch"; 331 | INFOPLIST_FILE = "Demo/Demo-Info.plist"; 332 | IPHONEOS_DEPLOYMENT_TARGET = 4.3; 333 | OTHER_LDFLAGS = ( 334 | "-ObjC", 335 | "-all_load", 336 | ); 337 | PRODUCT_NAME = "$(TARGET_NAME)"; 338 | TARGETED_DEVICE_FAMILY = "1,2"; 339 | WRAPPER_EXTENSION = app; 340 | }; 341 | name = Debug; 342 | }; 343 | 4719173913A4875400567E9E /* Release */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | ALWAYS_SEARCH_USER_PATHS = NO; 347 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 348 | COPY_PHASE_STRIP = YES; 349 | FRAMEWORK_SEARCH_PATHS = ( 350 | "$(inherited)", 351 | "\"$(SRCROOT)\"", 352 | ); 353 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 354 | GCC_PREFIX_HEADER = "Demo/Demo-Prefix.pch"; 355 | INFOPLIST_FILE = "Demo/Demo-Info.plist"; 356 | IPHONEOS_DEPLOYMENT_TARGET = 4.3; 357 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 358 | OTHER_LDFLAGS = ( 359 | "-ObjC", 360 | "-all_load", 361 | ); 362 | PRODUCT_NAME = "$(TARGET_NAME)"; 363 | TARGETED_DEVICE_FAMILY = "1,2"; 364 | VALIDATE_PRODUCT = YES; 365 | WRAPPER_EXTENSION = app; 366 | }; 367 | name = Release; 368 | }; 369 | /* End XCBuildConfiguration section */ 370 | 371 | /* Begin XCConfigurationList section */ 372 | 471916E313A4833A00567E9E /* Build configuration list for PBXProject "JMSlider" */ = { 373 | isa = XCConfigurationList; 374 | buildConfigurations = ( 375 | 471916F113A4833A00567E9E /* Debug */, 376 | 471916F213A4833A00567E9E /* Release */, 377 | ); 378 | defaultConfigurationIsVisible = 0; 379 | defaultConfigurationName = Release; 380 | }; 381 | 4719173713A4875400567E9E /* Build configuration list for PBXNativeTarget "Demo" */ = { 382 | isa = XCConfigurationList; 383 | buildConfigurations = ( 384 | 4719173813A4875400567E9E /* Debug */, 385 | 4719173913A4875400567E9E /* Release */, 386 | ); 387 | defaultConfigurationIsVisible = 0; 388 | defaultConfigurationName = Release; 389 | }; 390 | /* End XCConfigurationList section */ 391 | }; 392 | rootObject = 471916E013A4833A00567E9E /* Project object */; 393 | } 394 | --------------------------------------------------------------------------------