├── .DS_Store ├── Demo ├── .DS_Store ├── JCScrollView │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── jay_2.jpg │ ├── Images.xcassets │ │ ├── 1.imageset │ │ │ ├── bgc2.png │ │ │ └── Contents.json │ │ ├── 4.imageset │ │ │ ├── 背景(1).png │ │ │ └── Contents.json │ │ ├── 3.imageset │ │ │ ├── login_bg.png │ │ │ └── Contents.json │ │ ├── 2.imageset │ │ │ ├── myMission_cell_bg111.png │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── JCViewController.h │ ├── JCAppDelegate.h │ ├── main.m │ ├── JCScrollView-Prefix.pch │ ├── JCScrollView-Info.plist │ ├── JCViewController.m │ ├── JCAppDelegate.m │ ├── JCScrollView.h │ ├── Base.lproj │ │ └── Main.storyboard │ └── JCScrollView.m ├── JCScrollViewTests │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── JCScrollViewTests-Info.plist │ └── JCScrollViewTests.m └── JCScrollView.xcodeproj │ ├── project.xcworkspace │ └── contents.xcworkspacedata │ └── project.pbxproj ├── JCScrollView ├── .DS_Store ├── JCScrollView.h └── JCScrollView.m ├── README.md └── .gitignore /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zys456465111/JCScrollView/HEAD/.DS_Store -------------------------------------------------------------------------------- /Demo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zys456465111/JCScrollView/HEAD/Demo/.DS_Store -------------------------------------------------------------------------------- /Demo/JCScrollView/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Demo/JCScrollViewTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /JCScrollView/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zys456465111/JCScrollView/HEAD/JCScrollView/.DS_Store -------------------------------------------------------------------------------- /Demo/JCScrollView/jay_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zys456465111/JCScrollView/HEAD/Demo/JCScrollView/jay_2.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JCScrollView 2 | ============ 3 | 4 | easiest way to add a scrollView and pagecontrol to your view , you can switch scrollDirection with animation. 5 | -------------------------------------------------------------------------------- /Demo/JCScrollView/Images.xcassets/1.imageset/bgc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zys456465111/JCScrollView/HEAD/Demo/JCScrollView/Images.xcassets/1.imageset/bgc2.png -------------------------------------------------------------------------------- /Demo/JCScrollView/Images.xcassets/4.imageset/背景(1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zys456465111/JCScrollView/HEAD/Demo/JCScrollView/Images.xcassets/4.imageset/背景(1).png -------------------------------------------------------------------------------- /Demo/JCScrollView/Images.xcassets/3.imageset/login_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zys456465111/JCScrollView/HEAD/Demo/JCScrollView/Images.xcassets/3.imageset/login_bg.png -------------------------------------------------------------------------------- /Demo/JCScrollView/Images.xcassets/2.imageset/myMission_cell_bg111.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zys456465111/JCScrollView/HEAD/Demo/JCScrollView/Images.xcassets/2.imageset/myMission_cell_bg111.png -------------------------------------------------------------------------------- /Demo/JCScrollView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/JCScrollView/JCViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JCViewController.h 3 | // JCScrollView 4 | // 5 | // Created by JayChou on 14-10-27. 6 | // Copyright (c) 2014年 zys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JCViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/JCScrollView/JCAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // JCAppDelegate.h 3 | // JCScrollView 4 | // 5 | // Created by JayChou on 14-10-27. 6 | // Copyright (c) 2014年 zys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JCAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Demo/JCScrollView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // JCScrollView 4 | // 5 | // Created by JayChou on 14-10-27. 6 | // Copyright (c) 2014年 zys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "JCAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([JCAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Demo/JCScrollView/Images.xcassets/1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "bgc2.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/JCScrollView/Images.xcassets/4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "背景(1).png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/JCScrollView/Images.xcassets/3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "login_bg.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/JCScrollView/JCScrollView-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Demo/JCScrollView/Images.xcassets/2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "myMission_cell_bg111.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/JCScrollView/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "60x60", 21 | "scale" : "3x" 22 | } 23 | ], 24 | "info" : { 25 | "version" : 1, 26 | "author" : "xcode" 27 | } 28 | } -------------------------------------------------------------------------------- /Demo/JCScrollView/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | -------------------------------------------------------------------------------- /Demo/JCScrollViewTests/JCScrollViewTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.zys.jay.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Demo/JCScrollViewTests/JCScrollViewTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCScrollViewTests.m 3 | // JCScrollViewTests 4 | // 5 | // Created by JayChou on 14-10-27. 6 | // Copyright (c) 2014年 zys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JCScrollViewTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation JCScrollViewTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Demo/JCScrollView/JCScrollView-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.zys.jay.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Demo/JCScrollView/JCViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCViewController.m 3 | // JCScrollView 4 | // 5 | // Created by JayChou on 14-10-27. 6 | // Copyright (c) 2014年 zys. All rights reserved. 7 | // 8 | 9 | #import "JCViewController.h" 10 | #import "JCScrollView.h" 11 | 12 | @interface JCViewController () 13 | @property (nonatomic, weak)IBOutlet JCScrollView *jcSV; 14 | @end 15 | 16 | @implementation JCViewController 17 | 18 | - (void)viewDidLoad 19 | { 20 | [super viewDidLoad]; 21 | 22 | [self.jcSV addImageNames:@[@"1",@"2",@"3",@"4"]]; 23 | // self.jcSV.pageControlEnabled = NO; 24 | self.jcSV.animationDuration = 0.8; 25 | self.jcSV.animationDelegate = self; 26 | self.jcSV.scrollDirection = JCScrollViewScrollDirectionVertical; 27 | } 28 | 29 | int i = 0; 30 | - (IBAction)changeDirection { 31 | i = i == 1 ? 0 : 1; 32 | [self.jcSV setScrollDirection:i animated:YES]; 33 | 34 | } 35 | 36 | int o = 0; 37 | - (IBAction)addImageLast { 38 | 39 | if (o++ == 3) 40 | o = 0; 41 | 42 | NSArray *array = @[@"1",@"2",@"3",@"4"]; 43 | [self.jcSV addImageName:array[o]]; 44 | } 45 | 46 | /** 47 | * insert lots of images 48 | */ 49 | - (void)addImages { 50 | 51 | NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 2)]; 52 | [self.jcSV insertImageNames:@[@"jay_1",@"jay_2.jpg"] atIndex:set]; 53 | } 54 | 55 | - (BOOL)prefersStatusBarHidden { 56 | return YES; 57 | } 58 | 59 | #pragma mark - jcScrollViewDelegate 60 | 61 | /** 62 | * 动画开始就会调用 63 | */ 64 | - (void)scrollViewDidBeginAnimating:(JCScrollView *)scrollView { 65 | NSLog(@"动画开始"); 66 | } 67 | 68 | /** 69 | * 动画结束就会调用 70 | */ 71 | - (void)scrollViewDidEndAnimating:(JCScrollView *)scrollView { 72 | NSLog(@"动画结束"); 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /Demo/JCScrollView/JCAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCAppDelegate.m 3 | // JCScrollView 4 | // 5 | // Created by JayChou on 14-10-27. 6 | // Copyright (c) 2014年 zys. All rights reserved. 7 | // 8 | 9 | #import "JCAppDelegate.h" 10 | 11 | @implementation JCAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /JCScrollView/JCScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JCScrollView.h 3 | // JCScrollView 4 | // 5 | // Created by JayChou on 14-10-27. 6 | // Copyright (c) 2014年 zys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class JCScrollView; 12 | @protocol JCScrollViewDelegate 13 | 14 | /** 15 | * 动画开始就会调用 16 | */ 17 | - (void)scrollViewDidBeginAnimating:(JCScrollView *)scrollView; 18 | 19 | /** 20 | * 动画结束就会调用 21 | */ 22 | - (void)scrollViewDidEndAnimating:(JCScrollView *)scrollView; 23 | 24 | @end 25 | 26 | /** 27 | * 滚动方向 28 | */ 29 | typedef enum { 30 | 31 | JCScrollViewScrollDirectionHorizontal = 0, 32 | 33 | JCScrollViewScrollDirectionVertical 34 | 35 | }JCScrollViewScrollDirection; 36 | 37 | @interface JCScrollView : UIScrollView 38 | 39 | /** 40 | * 动画代理 41 | */ 42 | @property (nonatomic, weak)id animationDelegate; 43 | 44 | /** 45 | * 滚动方向 46 | */ 47 | @property (nonatomic, assign)JCScrollViewScrollDirection scrollDirection; 48 | 49 | /** 50 | * 样式可以拿去设置 51 | */ 52 | @property (nonatomic, strong)UIPageControl *pageControl; 53 | 54 | /** 55 | * pageControl,默认开启 56 | */ 57 | @property (nonatomic, assign, getter = isPageControlEnabled)BOOL pageControlEnabled; 58 | 59 | /** 60 | * 动画执行时间,当你调用这个方法时才用,默认- (void)setScrollDirection:(JCScrollViewScrollDirection)direction animated:(BOOL)animated; 61 | */ 62 | @property (nonatomic, assign)CGFloat animationDuration; 63 | 64 | /** 65 | * 正在动画 66 | */ 67 | @property (nonatomic, assign, readonly, getter = isAnimating)BOOL animating; 68 | /** 69 | * 添加多张图片名称 70 | * 71 | */ 72 | - (void)addImageNames:(NSArray *)names; 73 | 74 | /** 75 | * 添加单张图片名称 76 | * 77 | */ 78 | - (void)addImageName:(NSString *)name; 79 | 80 | /** 81 | * 添加单张图片在指定位置 82 | */ 83 | - (void)insertImageName:(NSString *)name atIndex:(NSUInteger)index; 84 | 85 | /** 86 | * 添加多张图片在指定位置 87 | * 88 | */ 89 | - (void)insertImageNames:(NSArray *)names atIndex:(NSIndexSet *)indexes; 90 | 91 | /** 92 | * 改变滚动方向 93 | * 94 | * @param direction 方向 95 | * @param animated 动画 96 | */ 97 | - (void)setScrollDirection:(JCScrollViewScrollDirection)direction animated:(BOOL)animated; 98 | 99 | /** 100 | * 快速创建 101 | */ 102 | + (instancetype)scrollViewWithFrame:(CGRect)frame andImageNames:(NSArray *)imageNames; 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /Demo/JCScrollView/JCScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JCScrollView.h 3 | // JCScrollView 4 | // 5 | // Created by JayChou on 14-10-27. 6 | // Copyright (c) 2014年 zys. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class JCScrollView; 12 | @protocol JCScrollViewDelegate 13 | 14 | /** 15 | * 动画开始就会调用 16 | */ 17 | - (void)scrollViewDidBeginAnimating:(JCScrollView *)scrollView; 18 | 19 | /** 20 | * 动画结束就会调用 21 | */ 22 | - (void)scrollViewDidEndAnimating:(JCScrollView *)scrollView; 23 | 24 | @end 25 | 26 | /** 27 | * 滚动方向 28 | */ 29 | typedef enum { 30 | 31 | JCScrollViewScrollDirectionHorizontal = 0, 32 | 33 | JCScrollViewScrollDirectionVertical 34 | 35 | }JCScrollViewScrollDirection; 36 | 37 | @interface JCScrollView : UIScrollView 38 | 39 | /** 40 | * 动画代理 41 | */ 42 | @property (nonatomic, weak)id animationDelegate; 43 | 44 | /** 45 | * 滚动方向 46 | */ 47 | @property (nonatomic, assign)JCScrollViewScrollDirection scrollDirection; 48 | 49 | /** 50 | * 样式可以拿去设置 51 | */ 52 | @property (nonatomic, strong)UIPageControl *pageControl; 53 | 54 | /** 55 | * pageControl,默认开启 56 | */ 57 | @property (nonatomic, assign, getter = isPageControlEnabled)BOOL pageControlEnabled; 58 | 59 | /** 60 | * 动画执行时间,当你调用这个方法时才用,默认- (void)setScrollDirection:(JCScrollViewScrollDirection)direction animated:(BOOL)animated; 61 | */ 62 | @property (nonatomic, assign)CGFloat animationDuration; 63 | 64 | /** 65 | * 正在动画 66 | */ 67 | @property (nonatomic, assign, readonly, getter = isAnimating)BOOL animating; 68 | /** 69 | * 添加多张图片名称 70 | * 71 | */ 72 | - (void)addImageNames:(NSArray *)names; 73 | 74 | /** 75 | * 添加单张图片名称 76 | * 77 | */ 78 | - (void)addImageName:(NSString *)name; 79 | 80 | /** 81 | * 添加单张图片在指定位置 82 | */ 83 | - (void)insertImageName:(NSString *)name atIndex:(NSUInteger)index; 84 | 85 | /** 86 | * 添加多张图片在指定位置 87 | * 88 | */ 89 | - (void)insertImageNames:(NSArray *)names atIndex:(NSIndexSet *)indexes; 90 | 91 | /** 92 | * 改变滚动方向 93 | * 94 | * @param direction 方向 95 | * @param animated 动画 96 | */ 97 | - (void)setScrollDirection:(JCScrollViewScrollDirection)direction animated:(BOOL)animated; 98 | 99 | /** 100 | * 快速创建 101 | */ 102 | + (instancetype)scrollViewWithFrame:(CGRect)frame andImageNames:(NSArray *)imageNames; 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /Demo/JCScrollView/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 30 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Demo/JCScrollView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6975725219FF7D6B009754B5 /* jay_2.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 6975725119FF7D6B009754B5 /* jay_2.jpg */; }; 11 | 69DB906319FE07EC00B5F257 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69DB906219FE07EC00B5F257 /* Foundation.framework */; }; 12 | 69DB906519FE07EC00B5F257 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69DB906419FE07EC00B5F257 /* CoreGraphics.framework */; }; 13 | 69DB906719FE07EC00B5F257 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69DB906619FE07EC00B5F257 /* UIKit.framework */; }; 14 | 69DB906D19FE07EC00B5F257 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 69DB906B19FE07EC00B5F257 /* InfoPlist.strings */; }; 15 | 69DB906F19FE07EC00B5F257 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 69DB906E19FE07EC00B5F257 /* main.m */; }; 16 | 69DB907319FE07EC00B5F257 /* JCAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 69DB907219FE07EC00B5F257 /* JCAppDelegate.m */; }; 17 | 69DB907619FE07EC00B5F257 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 69DB907419FE07EC00B5F257 /* Main.storyboard */; }; 18 | 69DB907919FE07EC00B5F257 /* JCViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 69DB907819FE07EC00B5F257 /* JCViewController.m */; }; 19 | 69DB907B19FE07EC00B5F257 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69DB907A19FE07EC00B5F257 /* Images.xcassets */; }; 20 | 69DB908219FE07EC00B5F257 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69DB908119FE07EC00B5F257 /* XCTest.framework */; }; 21 | 69DB908319FE07EC00B5F257 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69DB906219FE07EC00B5F257 /* Foundation.framework */; }; 22 | 69DB908419FE07EC00B5F257 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69DB906619FE07EC00B5F257 /* UIKit.framework */; }; 23 | 69DB908C19FE07EC00B5F257 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 69DB908A19FE07EC00B5F257 /* InfoPlist.strings */; }; 24 | 69DB908E19FE07EC00B5F257 /* JCScrollViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 69DB908D19FE07EC00B5F257 /* JCScrollViewTests.m */; }; 25 | 69DB909919FE080200B5F257 /* JCScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 69DB909819FE080200B5F257 /* JCScrollView.m */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 69DB908519FE07EC00B5F257 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 69DB905719FE07EC00B5F257 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 69DB905E19FE07EC00B5F257; 34 | remoteInfo = JCScrollView; 35 | }; 36 | /* End PBXContainerItemProxy section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 6975725119FF7D6B009754B5 /* jay_2.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = jay_2.jpg; sourceTree = ""; }; 40 | 69DB905F19FE07EC00B5F257 /* JCScrollView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JCScrollView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 69DB906219FE07EC00B5F257 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 42 | 69DB906419FE07EC00B5F257 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 43 | 69DB906619FE07EC00B5F257 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 44 | 69DB906A19FE07EC00B5F257 /* JCScrollView-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "JCScrollView-Info.plist"; sourceTree = ""; }; 45 | 69DB906C19FE07EC00B5F257 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 46 | 69DB906E19FE07EC00B5F257 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | 69DB907019FE07EC00B5F257 /* JCScrollView-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JCScrollView-Prefix.pch"; sourceTree = ""; }; 48 | 69DB907119FE07EC00B5F257 /* JCAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JCAppDelegate.h; sourceTree = ""; }; 49 | 69DB907219FE07EC00B5F257 /* JCAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JCAppDelegate.m; sourceTree = ""; }; 50 | 69DB907519FE07EC00B5F257 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 51 | 69DB907719FE07EC00B5F257 /* JCViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JCViewController.h; sourceTree = ""; }; 52 | 69DB907819FE07EC00B5F257 /* JCViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JCViewController.m; sourceTree = ""; }; 53 | 69DB907A19FE07EC00B5F257 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 54 | 69DB908019FE07EC00B5F257 /* JCScrollViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JCScrollViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 69DB908119FE07EC00B5F257 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 56 | 69DB908919FE07EC00B5F257 /* JCScrollViewTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "JCScrollViewTests-Info.plist"; sourceTree = ""; }; 57 | 69DB908B19FE07EC00B5F257 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 58 | 69DB908D19FE07EC00B5F257 /* JCScrollViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JCScrollViewTests.m; sourceTree = ""; }; 59 | 69DB909719FE080200B5F257 /* JCScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCScrollView.h; sourceTree = ""; }; 60 | 69DB909819FE080200B5F257 /* JCScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCScrollView.m; sourceTree = ""; }; 61 | /* End PBXFileReference section */ 62 | 63 | /* Begin PBXFrameworksBuildPhase section */ 64 | 69DB905C19FE07EC00B5F257 /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | 69DB906519FE07EC00B5F257 /* CoreGraphics.framework in Frameworks */, 69 | 69DB906719FE07EC00B5F257 /* UIKit.framework in Frameworks */, 70 | 69DB906319FE07EC00B5F257 /* Foundation.framework in Frameworks */, 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | 69DB907D19FE07EC00B5F257 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | 69DB908219FE07EC00B5F257 /* XCTest.framework in Frameworks */, 79 | 69DB908419FE07EC00B5F257 /* UIKit.framework in Frameworks */, 80 | 69DB908319FE07EC00B5F257 /* Foundation.framework in Frameworks */, 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXFrameworksBuildPhase section */ 85 | 86 | /* Begin PBXGroup section */ 87 | 69D60C411A2C0AFB0086E0AA /* JCScrollView */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 69DB909719FE080200B5F257 /* JCScrollView.h */, 91 | 69DB909819FE080200B5F257 /* JCScrollView.m */, 92 | ); 93 | name = JCScrollView; 94 | sourceTree = ""; 95 | }; 96 | 69DB905619FE07EC00B5F257 = { 97 | isa = PBXGroup; 98 | children = ( 99 | 69DB906819FE07EC00B5F257 /* JCScrollView */, 100 | 69DB908719FE07EC00B5F257 /* JCScrollViewTests */, 101 | 69DB906119FE07EC00B5F257 /* Frameworks */, 102 | 69DB906019FE07EC00B5F257 /* Products */, 103 | ); 104 | sourceTree = ""; 105 | }; 106 | 69DB906019FE07EC00B5F257 /* Products */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 69DB905F19FE07EC00B5F257 /* JCScrollView.app */, 110 | 69DB908019FE07EC00B5F257 /* JCScrollViewTests.xctest */, 111 | ); 112 | name = Products; 113 | sourceTree = ""; 114 | }; 115 | 69DB906119FE07EC00B5F257 /* Frameworks */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 69DB906219FE07EC00B5F257 /* Foundation.framework */, 119 | 69DB906419FE07EC00B5F257 /* CoreGraphics.framework */, 120 | 69DB906619FE07EC00B5F257 /* UIKit.framework */, 121 | 69DB908119FE07EC00B5F257 /* XCTest.framework */, 122 | ); 123 | name = Frameworks; 124 | sourceTree = ""; 125 | }; 126 | 69DB906819FE07EC00B5F257 /* JCScrollView */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 69DB907119FE07EC00B5F257 /* JCAppDelegate.h */, 130 | 69DB907219FE07EC00B5F257 /* JCAppDelegate.m */, 131 | 69DB907419FE07EC00B5F257 /* Main.storyboard */, 132 | 69DB907719FE07EC00B5F257 /* JCViewController.h */, 133 | 69DB907819FE07EC00B5F257 /* JCViewController.m */, 134 | 69DB907A19FE07EC00B5F257 /* Images.xcassets */, 135 | 69DB906919FE07EC00B5F257 /* Supporting Files */, 136 | 69D60C411A2C0AFB0086E0AA /* JCScrollView */, 137 | ); 138 | path = JCScrollView; 139 | sourceTree = ""; 140 | }; 141 | 69DB906919FE07EC00B5F257 /* Supporting Files */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 6975725119FF7D6B009754B5 /* jay_2.jpg */, 145 | 69DB906A19FE07EC00B5F257 /* JCScrollView-Info.plist */, 146 | 69DB906B19FE07EC00B5F257 /* InfoPlist.strings */, 147 | 69DB906E19FE07EC00B5F257 /* main.m */, 148 | 69DB907019FE07EC00B5F257 /* JCScrollView-Prefix.pch */, 149 | ); 150 | name = "Supporting Files"; 151 | sourceTree = ""; 152 | }; 153 | 69DB908719FE07EC00B5F257 /* JCScrollViewTests */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 69DB908D19FE07EC00B5F257 /* JCScrollViewTests.m */, 157 | 69DB908819FE07EC00B5F257 /* Supporting Files */, 158 | ); 159 | path = JCScrollViewTests; 160 | sourceTree = ""; 161 | }; 162 | 69DB908819FE07EC00B5F257 /* Supporting Files */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 69DB908919FE07EC00B5F257 /* JCScrollViewTests-Info.plist */, 166 | 69DB908A19FE07EC00B5F257 /* InfoPlist.strings */, 167 | ); 168 | name = "Supporting Files"; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXGroup section */ 172 | 173 | /* Begin PBXNativeTarget section */ 174 | 69DB905E19FE07EC00B5F257 /* JCScrollView */ = { 175 | isa = PBXNativeTarget; 176 | buildConfigurationList = 69DB909119FE07EC00B5F257 /* Build configuration list for PBXNativeTarget "JCScrollView" */; 177 | buildPhases = ( 178 | 69DB905B19FE07EC00B5F257 /* Sources */, 179 | 69DB905C19FE07EC00B5F257 /* Frameworks */, 180 | 69DB905D19FE07EC00B5F257 /* Resources */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | ); 186 | name = JCScrollView; 187 | productName = JCScrollView; 188 | productReference = 69DB905F19FE07EC00B5F257 /* JCScrollView.app */; 189 | productType = "com.apple.product-type.application"; 190 | }; 191 | 69DB907F19FE07EC00B5F257 /* JCScrollViewTests */ = { 192 | isa = PBXNativeTarget; 193 | buildConfigurationList = 69DB909419FE07EC00B5F257 /* Build configuration list for PBXNativeTarget "JCScrollViewTests" */; 194 | buildPhases = ( 195 | 69DB907C19FE07EC00B5F257 /* Sources */, 196 | 69DB907D19FE07EC00B5F257 /* Frameworks */, 197 | 69DB907E19FE07EC00B5F257 /* Resources */, 198 | ); 199 | buildRules = ( 200 | ); 201 | dependencies = ( 202 | 69DB908619FE07EC00B5F257 /* PBXTargetDependency */, 203 | ); 204 | name = JCScrollViewTests; 205 | productName = JCScrollViewTests; 206 | productReference = 69DB908019FE07EC00B5F257 /* JCScrollViewTests.xctest */; 207 | productType = "com.apple.product-type.bundle.unit-test"; 208 | }; 209 | /* End PBXNativeTarget section */ 210 | 211 | /* Begin PBXProject section */ 212 | 69DB905719FE07EC00B5F257 /* Project object */ = { 213 | isa = PBXProject; 214 | attributes = { 215 | CLASSPREFIX = JC; 216 | LastUpgradeCheck = 0510; 217 | ORGANIZATIONNAME = zys; 218 | TargetAttributes = { 219 | 69DB907F19FE07EC00B5F257 = { 220 | TestTargetID = 69DB905E19FE07EC00B5F257; 221 | }; 222 | }; 223 | }; 224 | buildConfigurationList = 69DB905A19FE07EC00B5F257 /* Build configuration list for PBXProject "JCScrollView" */; 225 | compatibilityVersion = "Xcode 3.2"; 226 | developmentRegion = English; 227 | hasScannedForEncodings = 0; 228 | knownRegions = ( 229 | en, 230 | Base, 231 | ); 232 | mainGroup = 69DB905619FE07EC00B5F257; 233 | productRefGroup = 69DB906019FE07EC00B5F257 /* Products */; 234 | projectDirPath = ""; 235 | projectRoot = ""; 236 | targets = ( 237 | 69DB905E19FE07EC00B5F257 /* JCScrollView */, 238 | 69DB907F19FE07EC00B5F257 /* JCScrollViewTests */, 239 | ); 240 | }; 241 | /* End PBXProject section */ 242 | 243 | /* Begin PBXResourcesBuildPhase section */ 244 | 69DB905D19FE07EC00B5F257 /* Resources */ = { 245 | isa = PBXResourcesBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | 69DB907B19FE07EC00B5F257 /* Images.xcassets in Resources */, 249 | 6975725219FF7D6B009754B5 /* jay_2.jpg in Resources */, 250 | 69DB906D19FE07EC00B5F257 /* InfoPlist.strings in Resources */, 251 | 69DB907619FE07EC00B5F257 /* Main.storyboard in Resources */, 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | }; 255 | 69DB907E19FE07EC00B5F257 /* Resources */ = { 256 | isa = PBXResourcesBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | 69DB908C19FE07EC00B5F257 /* InfoPlist.strings in Resources */, 260 | ); 261 | runOnlyForDeploymentPostprocessing = 0; 262 | }; 263 | /* End PBXResourcesBuildPhase section */ 264 | 265 | /* Begin PBXSourcesBuildPhase section */ 266 | 69DB905B19FE07EC00B5F257 /* Sources */ = { 267 | isa = PBXSourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | 69DB909919FE080200B5F257 /* JCScrollView.m in Sources */, 271 | 69DB906F19FE07EC00B5F257 /* main.m in Sources */, 272 | 69DB907919FE07EC00B5F257 /* JCViewController.m in Sources */, 273 | 69DB907319FE07EC00B5F257 /* JCAppDelegate.m in Sources */, 274 | ); 275 | runOnlyForDeploymentPostprocessing = 0; 276 | }; 277 | 69DB907C19FE07EC00B5F257 /* Sources */ = { 278 | isa = PBXSourcesBuildPhase; 279 | buildActionMask = 2147483647; 280 | files = ( 281 | 69DB908E19FE07EC00B5F257 /* JCScrollViewTests.m in Sources */, 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | /* End PBXSourcesBuildPhase section */ 286 | 287 | /* Begin PBXTargetDependency section */ 288 | 69DB908619FE07EC00B5F257 /* PBXTargetDependency */ = { 289 | isa = PBXTargetDependency; 290 | target = 69DB905E19FE07EC00B5F257 /* JCScrollView */; 291 | targetProxy = 69DB908519FE07EC00B5F257 /* PBXContainerItemProxy */; 292 | }; 293 | /* End PBXTargetDependency section */ 294 | 295 | /* Begin PBXVariantGroup section */ 296 | 69DB906B19FE07EC00B5F257 /* InfoPlist.strings */ = { 297 | isa = PBXVariantGroup; 298 | children = ( 299 | 69DB906C19FE07EC00B5F257 /* en */, 300 | ); 301 | name = InfoPlist.strings; 302 | sourceTree = ""; 303 | }; 304 | 69DB907419FE07EC00B5F257 /* Main.storyboard */ = { 305 | isa = PBXVariantGroup; 306 | children = ( 307 | 69DB907519FE07EC00B5F257 /* Base */, 308 | ); 309 | name = Main.storyboard; 310 | sourceTree = ""; 311 | }; 312 | 69DB908A19FE07EC00B5F257 /* InfoPlist.strings */ = { 313 | isa = PBXVariantGroup; 314 | children = ( 315 | 69DB908B19FE07EC00B5F257 /* en */, 316 | ); 317 | name = InfoPlist.strings; 318 | sourceTree = ""; 319 | }; 320 | /* End PBXVariantGroup section */ 321 | 322 | /* Begin XCBuildConfiguration section */ 323 | 69DB908F19FE07EC00B5F257 /* Debug */ = { 324 | isa = XCBuildConfiguration; 325 | buildSettings = { 326 | ALWAYS_SEARCH_USER_PATHS = NO; 327 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 328 | CLANG_CXX_LIBRARY = "libc++"; 329 | CLANG_ENABLE_MODULES = YES; 330 | CLANG_ENABLE_OBJC_ARC = YES; 331 | CLANG_WARN_BOOL_CONVERSION = YES; 332 | CLANG_WARN_CONSTANT_CONVERSION = YES; 333 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 334 | CLANG_WARN_EMPTY_BODY = YES; 335 | CLANG_WARN_ENUM_CONVERSION = YES; 336 | CLANG_WARN_INT_CONVERSION = YES; 337 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 338 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 339 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 340 | COPY_PHASE_STRIP = NO; 341 | GCC_C_LANGUAGE_STANDARD = gnu99; 342 | GCC_DYNAMIC_NO_PIC = NO; 343 | GCC_OPTIMIZATION_LEVEL = 0; 344 | GCC_PREPROCESSOR_DEFINITIONS = ( 345 | "DEBUG=1", 346 | "$(inherited)", 347 | ); 348 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 349 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 350 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 351 | GCC_WARN_UNDECLARED_SELECTOR = YES; 352 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 353 | GCC_WARN_UNUSED_FUNCTION = YES; 354 | GCC_WARN_UNUSED_VARIABLE = YES; 355 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 356 | ONLY_ACTIVE_ARCH = YES; 357 | SDKROOT = iphoneos; 358 | }; 359 | name = Debug; 360 | }; 361 | 69DB909019FE07EC00B5F257 /* Release */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | ALWAYS_SEARCH_USER_PATHS = NO; 365 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 366 | CLANG_CXX_LIBRARY = "libc++"; 367 | CLANG_ENABLE_MODULES = YES; 368 | CLANG_ENABLE_OBJC_ARC = YES; 369 | CLANG_WARN_BOOL_CONVERSION = YES; 370 | CLANG_WARN_CONSTANT_CONVERSION = YES; 371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 372 | CLANG_WARN_EMPTY_BODY = YES; 373 | CLANG_WARN_ENUM_CONVERSION = YES; 374 | CLANG_WARN_INT_CONVERSION = YES; 375 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 376 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 377 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 378 | COPY_PHASE_STRIP = YES; 379 | ENABLE_NS_ASSERTIONS = NO; 380 | GCC_C_LANGUAGE_STANDARD = gnu99; 381 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 382 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 383 | GCC_WARN_UNDECLARED_SELECTOR = YES; 384 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 385 | GCC_WARN_UNUSED_FUNCTION = YES; 386 | GCC_WARN_UNUSED_VARIABLE = YES; 387 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 388 | SDKROOT = iphoneos; 389 | VALIDATE_PRODUCT = YES; 390 | }; 391 | name = Release; 392 | }; 393 | 69DB909219FE07EC00B5F257 /* Debug */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 397 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 398 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 399 | GCC_PREFIX_HEADER = "JCScrollView/JCScrollView-Prefix.pch"; 400 | INFOPLIST_FILE = "JCScrollView/JCScrollView-Info.plist"; 401 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 402 | PRODUCT_NAME = "$(TARGET_NAME)"; 403 | TARGETED_DEVICE_FAMILY = 1; 404 | WRAPPER_EXTENSION = app; 405 | }; 406 | name = Debug; 407 | }; 408 | 69DB909319FE07EC00B5F257 /* Release */ = { 409 | isa = XCBuildConfiguration; 410 | buildSettings = { 411 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 412 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 413 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 414 | GCC_PREFIX_HEADER = "JCScrollView/JCScrollView-Prefix.pch"; 415 | INFOPLIST_FILE = "JCScrollView/JCScrollView-Info.plist"; 416 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 417 | PRODUCT_NAME = "$(TARGET_NAME)"; 418 | TARGETED_DEVICE_FAMILY = 1; 419 | WRAPPER_EXTENSION = app; 420 | }; 421 | name = Release; 422 | }; 423 | 69DB909519FE07EC00B5F257 /* Debug */ = { 424 | isa = XCBuildConfiguration; 425 | buildSettings = { 426 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/JCScrollView.app/JCScrollView"; 427 | FRAMEWORK_SEARCH_PATHS = ( 428 | "$(SDKROOT)/Developer/Library/Frameworks", 429 | "$(inherited)", 430 | "$(DEVELOPER_FRAMEWORKS_DIR)", 431 | ); 432 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 433 | GCC_PREFIX_HEADER = "JCScrollView/JCScrollView-Prefix.pch"; 434 | GCC_PREPROCESSOR_DEFINITIONS = ( 435 | "DEBUG=1", 436 | "$(inherited)", 437 | ); 438 | INFOPLIST_FILE = "JCScrollViewTests/JCScrollViewTests-Info.plist"; 439 | PRODUCT_NAME = "$(TARGET_NAME)"; 440 | TEST_HOST = "$(BUNDLE_LOADER)"; 441 | WRAPPER_EXTENSION = xctest; 442 | }; 443 | name = Debug; 444 | }; 445 | 69DB909619FE07EC00B5F257 /* Release */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/JCScrollView.app/JCScrollView"; 449 | FRAMEWORK_SEARCH_PATHS = ( 450 | "$(SDKROOT)/Developer/Library/Frameworks", 451 | "$(inherited)", 452 | "$(DEVELOPER_FRAMEWORKS_DIR)", 453 | ); 454 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 455 | GCC_PREFIX_HEADER = "JCScrollView/JCScrollView-Prefix.pch"; 456 | INFOPLIST_FILE = "JCScrollViewTests/JCScrollViewTests-Info.plist"; 457 | PRODUCT_NAME = "$(TARGET_NAME)"; 458 | TEST_HOST = "$(BUNDLE_LOADER)"; 459 | WRAPPER_EXTENSION = xctest; 460 | }; 461 | name = Release; 462 | }; 463 | /* End XCBuildConfiguration section */ 464 | 465 | /* Begin XCConfigurationList section */ 466 | 69DB905A19FE07EC00B5F257 /* Build configuration list for PBXProject "JCScrollView" */ = { 467 | isa = XCConfigurationList; 468 | buildConfigurations = ( 469 | 69DB908F19FE07EC00B5F257 /* Debug */, 470 | 69DB909019FE07EC00B5F257 /* Release */, 471 | ); 472 | defaultConfigurationIsVisible = 0; 473 | defaultConfigurationName = Release; 474 | }; 475 | 69DB909119FE07EC00B5F257 /* Build configuration list for PBXNativeTarget "JCScrollView" */ = { 476 | isa = XCConfigurationList; 477 | buildConfigurations = ( 478 | 69DB909219FE07EC00B5F257 /* Debug */, 479 | 69DB909319FE07EC00B5F257 /* Release */, 480 | ); 481 | defaultConfigurationIsVisible = 0; 482 | defaultConfigurationName = Release; 483 | }; 484 | 69DB909419FE07EC00B5F257 /* Build configuration list for PBXNativeTarget "JCScrollViewTests" */ = { 485 | isa = XCConfigurationList; 486 | buildConfigurations = ( 487 | 69DB909519FE07EC00B5F257 /* Debug */, 488 | 69DB909619FE07EC00B5F257 /* Release */, 489 | ); 490 | defaultConfigurationIsVisible = 0; 491 | defaultConfigurationName = Release; 492 | }; 493 | /* End XCConfigurationList section */ 494 | }; 495 | rootObject = 69DB905719FE07EC00B5F257 /* Project object */; 496 | } 497 | -------------------------------------------------------------------------------- /JCScrollView/JCScrollView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCScrollView.m 3 | // JCScrollView 4 | // 5 | // Created by JayChou on 14-10-27. 6 | // Copyright (c) 2014年 zys. All rights reserved. 7 | // 8 | 9 | #import "JCScrollView.h" 10 | 11 | //direction Next -1 Previous 1便于后面计算 12 | typedef enum { 13 | JCScrollViewMoveDirectionNext = -1, 14 | JCScrollViewMoveDirectionPrevious = 1 15 | }JCScrollViewMoveDirection; 16 | 17 | @interface JCScrollView () 18 | 19 | /** 20 | * 循环利用imageView数组 21 | */ 22 | @property (nonatomic, strong)NSArray *imageViews; 23 | 24 | /** 25 | * 记录当前的索引 26 | */ 27 | @property (nonatomic, assign)NSInteger currentIndex; 28 | 29 | /** 30 | * 图片数组 31 | */ 32 | @property (nonatomic, strong)NSMutableArray *imageNames; 33 | 34 | @end 35 | 36 | @implementation JCScrollView 37 | 38 | + (instancetype)scrollViewWithFrame:(CGRect)frame andImageNames:(NSArray *)imageNames { 39 | JCScrollView *jcSV = [[JCScrollView alloc]initWithFrame:frame]; 40 | jcSV.imageNames = [NSMutableArray arrayWithArray:imageNames]; 41 | return jcSV; 42 | } 43 | 44 | - (void)setCurrentIndex:(NSInteger)currentIndex { 45 | if (currentIndex == 3) { 46 | currentIndex = 0; 47 | } else if (currentIndex == -1) { 48 | currentIndex = 2; 49 | } 50 | _currentIndex = currentIndex; 51 | } 52 | 53 | - (void)setScrollDirection:(JCScrollViewScrollDirection)scrollDirection { 54 | if (_scrollDirection == scrollDirection) return; 55 | 56 | [self setScrollDirection:scrollDirection animated:NO]; 57 | 58 | _scrollDirection = scrollDirection; 59 | } 60 | 61 | - (void)setPageControlEnabled:(BOOL)pageControlEnabled { 62 | 63 | if(_pageControlEnabled == pageControlEnabled) return; 64 | 65 | if(pageControlEnabled) 66 | [self.superview addSubview:self.pageControl]; 67 | else 68 | [self.pageControl removeFromSuperview]; 69 | 70 | _pageControlEnabled = pageControlEnabled; 71 | } 72 | 73 | - (void)setContentOffset:(CGPoint)contentOffset { 74 | 75 | [super setContentOffset:contentOffset]; 76 | 77 | NSUInteger prePage = self.pageControl.currentPage; 78 | 79 | switch (_scrollDirection) { 80 | case JCScrollViewScrollDirectionHorizontal: 81 | 82 | _pageControl.currentPage = contentOffset.x / self.bounds.size.width + 0.5; 83 | 84 | break; 85 | 86 | case JCScrollViewScrollDirectionVertical: 87 | 88 | _pageControl.currentPage = contentOffset.y / self.bounds.size.height + 0.5; 89 | 90 | break; 91 | default: 92 | break; 93 | } 94 | 95 | if (_pageControl.currentPage > prePage) { //图片向前走 96 | 97 | [self moveImageViewWithDirection:JCScrollViewMoveDirectionNext]; 98 | 99 | } else if (_pageControl.currentPage < prePage) { 100 | 101 | [self moveImageViewWithDirection:JCScrollViewMoveDirectionPrevious]; 102 | 103 | } 104 | 105 | } 106 | 107 | - (NSArray *)imageViews { 108 | if (!_imageViews) { 109 | 110 | NSMutableArray *imageViews = [NSMutableArray array]; 111 | 112 | /** 113 | * 如果图片数量小于3张,就只创建图片数量的imageView 114 | */ 115 | NSInteger count = self.imageNames.count < 3 ? self.imageNames.count + 1 : 3; 116 | int startNum = self.imageNames.count < 3 ? 1 : 0; 117 | for (int i = startNum; i index) { 244 | 245 | self.currentIndex++; 246 | [self moveImageViewWithDirection:JCScrollViewMoveDirectionPrevious]; 247 | 248 | //插入的图片那正好是当前图片 249 | } else if (self.pageControl.currentPage == index) { 250 | 251 | [self setImageWithImageIndex:self.currentIndex andImageNameIndex:index]; 252 | 253 | } 254 | 255 | } 256 | 257 | /** 258 | * 转换垂直或水平滚动时子控件重新布局 259 | */ 260 | - (void)convertImageViewsBetweenHorizontalAndVertical { 261 | 262 | for (UIImageView *imageView in self.imageViews) { 263 | //只改变当前这张 264 | 265 | //还原一下尺寸 266 | // imageView.transform = CGAffineTransformIdentity; 267 | 268 | switch (self.scrollDirection) { 269 | case JCScrollViewScrollDirectionHorizontal: 270 | //来到这里的imageView说明以前是垂直的,也就是说x为0 y有值,那么就转换一下 271 | { 272 | NSInteger currentPage = imageView.frame.origin.y / self.bounds.size.height; 273 | imageView.frame = (CGRect){{currentPage * self.bounds.size.width,0},imageView.bounds.size}; 274 | // NSLog(@"%@",NSStringFromCGRect(imageView.frame)); 275 | break; 276 | } 277 | case JCScrollViewScrollDirectionVertical: 278 | { 279 | NSInteger currentPage = imageView.frame.origin.x / self.bounds.size.width; 280 | imageView.frame = (CGRect){{0,currentPage * self.bounds.size.height},imageView.bounds.size}; 281 | break; 282 | } 283 | default: 284 | break; 285 | } 286 | 287 | } 288 | 289 | //要同时进行,不知不觉中切换,暗度陈仓 290 | switch (self.scrollDirection) { 291 | case JCScrollViewScrollDirectionHorizontal: 292 | 293 | [self setContentOffset:CGPointMake(self.pageControl.currentPage * self.bounds.size.width, 0)]; 294 | 295 | break; 296 | 297 | case JCScrollViewScrollDirectionVertical: 298 | 299 | [self setContentOffset:CGPointMake(0, self.pageControl.currentPage * self.bounds.size.height)]; 300 | 301 | break; 302 | 303 | default: 304 | break; 305 | } 306 | 307 | [self resizeContentWithIndex:-1]; 308 | } 309 | 310 | /** 311 | * 动态切换滚动方向 312 | * 313 | * @param direction 方向 314 | * @param animated 是否执行动画 315 | */ 316 | - (void)setScrollDirection:(JCScrollViewScrollDirection)direction animated:(BOOL)animated { 317 | 318 | if (!animated) { 319 | /** 320 | * 方向相同不执行 321 | */ 322 | if (_scrollDirection == direction) return; 323 | _scrollDirection = direction; 324 | [self convertImageViewsBetweenHorizontalAndVertical]; 325 | return; 326 | } 327 | 328 | if (self.isAnimating) 329 | return; 330 | 331 | void (^JCAffineTransformTranslate)(UIImageView*, CGFloat, CGFloat) = ^(UIImageView *imageView, CGFloat tx, CGFloat ty){ 332 | 333 | CGRect imageframe = imageView.frame; 334 | imageframe.origin.x += tx; 335 | imageframe.origin.y += ty; 336 | imageView.frame = imageframe; 337 | 338 | }; 339 | 340 | void (^JCAffineTransformScale)(UIImageView*, CGFloat) = ^(UIImageView *imageView, CGFloat scale){ 341 | CGRect imageBounds = imageView.bounds; 342 | imageBounds.size.width *= scale; 343 | imageBounds.size.height *= scale; 344 | imageView.bounds = imageBounds; 345 | }; 346 | 347 | /** 348 | * 缩放比例 占据屏幕的3分之一 349 | */ 350 | CGFloat scale = 0.33; 351 | 352 | /** 353 | * 动画时长 354 | */ 355 | CGFloat duration = self.animationDuration; 356 | 357 | self.animating = YES; 358 | 359 | /** 360 | * 通知代理开始动画 361 | */ 362 | if ([self.animationDelegate respondsToSelector:@selector(scrollViewDidBeginAnimating:)]) { 363 | [self.animationDelegate scrollViewDidBeginAnimating:self]; 364 | } 365 | 366 | [UIView animateWithDuration:duration animations:^{ 367 | 368 | for (UIImageView *imageView in self.imageViews) { 369 | 370 | if (self.currentIndex == [self.imageViews indexOfObject:imageView]) { 371 | 372 | JCAffineTransformScale(imageView,scale); 373 | 374 | } else { 375 | 376 | switch (self.scrollDirection) { 377 | case JCScrollViewScrollDirectionHorizontal: 378 | 379 | JCAffineTransformTranslate(imageView,(self.contentOffset.x - imageView.frame.origin.x) * 0.65,0); 380 | 381 | break; 382 | case JCScrollViewScrollDirectionVertical: 383 | 384 | JCAffineTransformTranslate(imageView,0,(self.contentOffset.y - imageView.frame.origin.y) * 0.65); 385 | 386 | break; 387 | default: 388 | break; 389 | } 390 | } 391 | } 392 | 393 | } completion:^(BOOL finished) { 394 | 395 | [UIView animateWithDuration:duration animations:^{ 396 | 397 | for (UIImageView *imageView in self.imageViews) { 398 | 399 | if (self.currentIndex == [self.imageViews indexOfObject:imageView]) { 400 | 401 | continue; 402 | 403 | } else { 404 | 405 | /** 406 | * 适配IOS8, IOS8中调用UIView动画连续调用两个不同的transform会有卡顿 407 | */ 408 | JCAffineTransformScale(imageView,scale); 409 | } 410 | } 411 | 412 | //第三步,乾坤大挪移 413 | } completion:^(BOOL finished) { 414 | //如果方向没有改变,恢复,退出 415 | if (self.scrollDirection == direction) { 416 | 417 | [UIView animateWithDuration:duration animations:^{ 418 | for (UIImageView *imageView in self.imageViews) { 419 | 420 | JCAffineTransformScale(imageView, 1/scale); 421 | 422 | switch (self.scrollDirection) { 423 | case JCScrollViewScrollDirectionHorizontal: 424 | { 425 | NSInteger currentPage = (imageView.frame.origin.x-self.bounds.size.width*self.pageControl.currentPage) / (self.bounds.size.width*scale); 426 | currentPage += self.pageControl.currentPage; 427 | imageView.frame = (CGRect){{currentPage * self.bounds.size.width,imageView.frame.origin.y},imageView.bounds.size}; 428 | break; 429 | } 430 | case JCScrollViewScrollDirectionVertical: 431 | { 432 | NSInteger currentPage = (imageView.frame.origin.y-self.bounds.size.height*self.pageControl.currentPage) / (self.bounds.size.height*scale); 433 | currentPage += self.pageControl.currentPage; 434 | imageView.frame = (CGRect){{imageView.frame.origin.x,currentPage * self.bounds.size.height},imageView.bounds.size}; 435 | 436 | break; 437 | } 438 | default: 439 | break; 440 | } 441 | 442 | } 443 | }completion:^(BOOL finished) { 444 | self.animating = NO; 445 | if ([self.animationDelegate respondsToSelector:@selector(scrollViewDidEndAnimating:)]) { 446 | [self.animationDelegate scrollViewDidEndAnimating:self]; 447 | } 448 | }]; 449 | 450 | return; 451 | } 452 | 453 | //能来到这里说明方向不同 454 | _scrollDirection = direction; 455 | 456 | [UIView animateWithDuration:duration animations:^{ 457 | 458 | CGFloat paddingV = 6.5; 459 | CGFloat paddingH = 11.5; 460 | CGFloat padding = 0; 461 | NSInteger flag = 0; 462 | for (UIImageView *imageView in self.imageViews) { 463 | //当前显示的这张不变 464 | if (self.currentIndex == [self.imageViews indexOfObject:imageView]) { 465 | 466 | continue; 467 | 468 | } else { 469 | //要切换成哪个方向 470 | switch (direction) { 471 | case JCScrollViewScrollDirectionHorizontal: 472 | { 473 | 474 | flag = imageView.frame.origin.y > self.contentOffset.y ? 1 : -1; 475 | 476 | padding = paddingH; 477 | 478 | break; 479 | } 480 | case JCScrollViewScrollDirectionVertical: 481 | { 482 | 483 | flag = imageView.frame.origin.x > self.contentOffset.x ? -1 : 1; 484 | 485 | padding = paddingV; 486 | 487 | break; 488 | } 489 | 490 | default: 491 | break; 492 | } 493 | 494 | JCAffineTransformTranslate(imageView,(imageView.bounds.size.width + padding)*flag,(-imageView.bounds.size.height - padding)*flag); 495 | 496 | } 497 | 498 | } 499 | 500 | } completion:^(BOOL finished) { 501 | 502 | [UIView animateWithDuration:duration animations:^{ 503 | for (UIImageView *imageView in self.imageViews) { 504 | 505 | JCAffineTransformScale(imageView, 1/scale); 506 | 507 | switch (self.scrollDirection) { 508 | case JCScrollViewScrollDirectionHorizontal: 509 | { 510 | NSInteger currentPage = imageView.frame.origin.x / (self.bounds.size.width*scale); 511 | imageView.frame = (CGRect){{currentPage * self.bounds.size.width,imageView.frame.origin.y},imageView.bounds.size}; 512 | break; 513 | } 514 | case JCScrollViewScrollDirectionVertical: 515 | { 516 | NSInteger currentPage = imageView.frame.origin.y / (self.bounds.size.height*scale); 517 | imageView.frame = (CGRect){{imageView.frame.origin.x,currentPage * self.bounds.size.height},imageView.bounds.size}; 518 | break; 519 | } 520 | default: 521 | break; 522 | } 523 | 524 | } 525 | } completion:^(BOOL finished) { 526 | 527 | for (UIImageView *imageView in self.imageViews) { 528 | 529 | switch (self.scrollDirection) { 530 | case JCScrollViewScrollDirectionHorizontal: 531 | { 532 | NSInteger currentPage = imageView.frame.origin.x / self.bounds.size.width; 533 | currentPage += self.pageControl.currentPage; 534 | imageView.frame = (CGRect){{0,currentPage * self.bounds.size.height},imageView.bounds.size}; 535 | break; 536 | } 537 | case JCScrollViewScrollDirectionVertical: 538 | { 539 | NSInteger currentPage = imageView.frame.origin.y / self.bounds.size.height; 540 | currentPage += self.pageControl.currentPage; 541 | imageView.frame = (CGRect){{currentPage * self.bounds.size.width,0},imageView.bounds.size}; 542 | break; 543 | } 544 | default: 545 | break; 546 | } 547 | 548 | 549 | } 550 | 551 | [self convertImageViewsBetweenHorizontalAndVertical]; 552 | 553 | self.animating = NO; 554 | 555 | if ([self.animationDelegate respondsToSelector:@selector(scrollViewDidEndAnimating:)]) { 556 | [self.animationDelegate scrollViewDidEndAnimating:self]; 557 | } 558 | }]; 559 | 560 | }]; 561 | 562 | }]; 563 | 564 | }]; 565 | 566 | } 567 | 568 | - (instancetype)initWithCoder:(NSCoder *)coder 569 | { 570 | self = [super initWithCoder:coder]; 571 | if (self) { 572 | [self setup]; 573 | } 574 | return self; 575 | } 576 | 577 | - (id)initWithFrame:(CGRect)frame 578 | { 579 | if (self = [super initWithFrame:frame]) { 580 | [self setup]; 581 | } 582 | return self; 583 | } 584 | 585 | - (void)setup { 586 | self.currentIndex = 1; 587 | self.bounces = NO; 588 | self.showsHorizontalScrollIndicator = NO; 589 | self.showsVerticalScrollIndicator = NO; 590 | self.pagingEnabled = YES; 591 | self.imageNames = [NSMutableArray array]; 592 | self.animationDuration = 1; 593 | self.pageControlEnabled = YES; 594 | // _scrollDirection = JCScrollViewScrollDirectionVertical; 595 | } 596 | 597 | - (void)layoutSubviews { 598 | [super layoutSubviews]; 599 | [self imageViews]; 600 | CGFloat pageControlW = self.bounds.size.width; 601 | CGFloat pageControlH = self.bounds.size.height * 0.1; 602 | CGFloat pageControlX = self.frame.origin.x; 603 | CGFloat pageControlY = self.bounds.size.height - pageControlH * 1.5; 604 | self.pageControl.frame = CGRectMake(pageControlX, pageControlY, pageControlW, pageControlH); 605 | 606 | if (self.pageControlEnabled) 607 | [self.superview addSubview:self.pageControl]; 608 | } 609 | 610 | //direction Next -1 Previous 1 611 | - (void)moveImageViewWithDirection:(JCScrollViewMoveDirection)direction{ 612 | 613 | NSInteger preIndex = self.currentIndex + direction; 614 | if (preIndex == 3) 615 | preIndex = 0; 616 | else if (preIndex == -1) 617 | preIndex = 2; 618 | 619 | NSInteger offset = _pageControl.currentPage - direction; 620 | 621 | self.currentIndex-=direction; 622 | 623 | //把前一张或后一张移动 624 | [self setImageWithImageIndex:preIndex andImageNameIndex:offset]; 625 | } 626 | 627 | - (void)setImageWithImageIndex:(NSInteger)imageIndex andImageNameIndex:(NSInteger)nameIndex { 628 | if (self.imageNames.count < 3) { 629 | return; 630 | } 631 | UIImageView *imageView = self.imageViews[imageIndex]; 632 | CGRect imageRect = imageView.frame; 633 | 634 | switch (_scrollDirection) { 635 | case JCScrollViewScrollDirectionHorizontal: 636 | 637 | imageRect.origin.x = (nameIndex) * self.bounds.size.width; 638 | 639 | break; 640 | case JCScrollViewScrollDirectionVertical: 641 | 642 | imageRect.origin.y = (nameIndex) * self.bounds.size.height; 643 | 644 | break; 645 | 646 | default: 647 | break; 648 | } 649 | 650 | imageView.frame = imageRect; 651 | 652 | if (nameIndex < self.imageNames.count && nameIndex >= 0) { 653 | imageView.image = [UIImage imageNamed:self.imageNames[nameIndex]]; 654 | } 655 | 656 | } 657 | 658 | @end 659 | -------------------------------------------------------------------------------- /Demo/JCScrollView/JCScrollView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCScrollView.m 3 | // JCScrollView 4 | // 5 | // Created by JayChou on 14-10-27. 6 | // Copyright (c) 2014年 zys. All rights reserved. 7 | // 8 | 9 | #import "JCScrollView.h" 10 | 11 | //direction Next -1 Previous 1便于后面计算 12 | typedef enum { 13 | JCScrollViewMoveDirectionNext = -1, 14 | JCScrollViewMoveDirectionPrevious = 1 15 | }JCScrollViewMoveDirection; 16 | 17 | @interface JCScrollView () 18 | 19 | /** 20 | * 循环利用imageView数组 21 | */ 22 | @property (nonatomic, strong)NSArray *imageViews; 23 | 24 | /** 25 | * 记录当前的索引 26 | */ 27 | @property (nonatomic, assign)NSInteger currentIndex; 28 | 29 | /** 30 | * 图片数组 31 | */ 32 | @property (nonatomic, strong)NSMutableArray *imageNames; 33 | 34 | @end 35 | 36 | @implementation JCScrollView 37 | 38 | + (instancetype)scrollViewWithFrame:(CGRect)frame andImageNames:(NSArray *)imageNames { 39 | JCScrollView *jcSV = [[JCScrollView alloc]initWithFrame:frame]; 40 | jcSV.imageNames = [NSMutableArray arrayWithArray:imageNames]; 41 | return jcSV; 42 | } 43 | 44 | - (void)setCurrentIndex:(NSInteger)currentIndex { 45 | if (currentIndex == 3) { 46 | currentIndex = 0; 47 | } else if (currentIndex == -1) { 48 | currentIndex = 2; 49 | } 50 | _currentIndex = currentIndex; 51 | } 52 | 53 | - (void)setScrollDirection:(JCScrollViewScrollDirection)scrollDirection { 54 | if (_scrollDirection == scrollDirection) return; 55 | 56 | [self setScrollDirection:scrollDirection animated:NO]; 57 | 58 | _scrollDirection = scrollDirection; 59 | } 60 | 61 | - (void)setPageControlEnabled:(BOOL)pageControlEnabled { 62 | 63 | if(_pageControlEnabled == pageControlEnabled) return; 64 | 65 | if(pageControlEnabled) 66 | [self.superview addSubview:self.pageControl]; 67 | else 68 | [self.pageControl removeFromSuperview]; 69 | 70 | _pageControlEnabled = pageControlEnabled; 71 | } 72 | 73 | - (void)setContentOffset:(CGPoint)contentOffset { 74 | 75 | [super setContentOffset:contentOffset]; 76 | 77 | NSUInteger prePage = self.pageControl.currentPage; 78 | 79 | switch (_scrollDirection) { 80 | case JCScrollViewScrollDirectionHorizontal: 81 | 82 | _pageControl.currentPage = contentOffset.x / self.bounds.size.width + 0.5; 83 | 84 | break; 85 | 86 | case JCScrollViewScrollDirectionVertical: 87 | 88 | _pageControl.currentPage = contentOffset.y / self.bounds.size.height + 0.5; 89 | 90 | break; 91 | default: 92 | break; 93 | } 94 | 95 | if (_pageControl.currentPage > prePage) { //图片向前走 96 | 97 | [self moveImageViewWithDirection:JCScrollViewMoveDirectionNext]; 98 | 99 | } else if (_pageControl.currentPage < prePage) { 100 | 101 | [self moveImageViewWithDirection:JCScrollViewMoveDirectionPrevious]; 102 | 103 | } 104 | 105 | } 106 | 107 | - (NSArray *)imageViews { 108 | if (!_imageViews) { 109 | 110 | NSMutableArray *imageViews = [NSMutableArray array]; 111 | 112 | /** 113 | * 如果图片数量小于3张,就只创建图片数量的imageView 114 | */ 115 | NSInteger count = self.imageNames.count < 3 ? self.imageNames.count + 1 : 3; 116 | int startNum = self.imageNames.count < 3 ? 1 : 0; 117 | for (int i = startNum; i index) { 244 | 245 | self.currentIndex++; 246 | [self moveImageViewWithDirection:JCScrollViewMoveDirectionPrevious]; 247 | 248 | //插入的图片那正好是当前图片 249 | } else if (self.pageControl.currentPage == index) { 250 | 251 | [self setImageWithImageIndex:self.currentIndex andImageNameIndex:index]; 252 | 253 | } 254 | 255 | } 256 | 257 | /** 258 | * 转换垂直或水平滚动时子控件重新布局 259 | */ 260 | - (void)convertImageViewsBetweenHorizontalAndVertical { 261 | 262 | for (UIImageView *imageView in self.imageViews) { 263 | //只改变当前这张 264 | 265 | //还原一下尺寸 266 | // imageView.transform = CGAffineTransformIdentity; 267 | 268 | switch (self.scrollDirection) { 269 | case JCScrollViewScrollDirectionHorizontal: 270 | //来到这里的imageView说明以前是垂直的,也就是说x为0 y有值,那么就转换一下 271 | { 272 | NSInteger currentPage = imageView.frame.origin.y / self.bounds.size.height; 273 | imageView.frame = (CGRect){{currentPage * self.bounds.size.width,0},imageView.bounds.size}; 274 | // NSLog(@"%@",NSStringFromCGRect(imageView.frame)); 275 | break; 276 | } 277 | case JCScrollViewScrollDirectionVertical: 278 | { 279 | NSInteger currentPage = imageView.frame.origin.x / self.bounds.size.width; 280 | imageView.frame = (CGRect){{0,currentPage * self.bounds.size.height},imageView.bounds.size}; 281 | break; 282 | } 283 | default: 284 | break; 285 | } 286 | 287 | } 288 | 289 | //要同时进行,不知不觉中切换,暗度陈仓 290 | switch (self.scrollDirection) { 291 | case JCScrollViewScrollDirectionHorizontal: 292 | 293 | [self setContentOffset:CGPointMake(self.pageControl.currentPage * self.bounds.size.width, 0)]; 294 | 295 | break; 296 | 297 | case JCScrollViewScrollDirectionVertical: 298 | 299 | [self setContentOffset:CGPointMake(0, self.pageControl.currentPage * self.bounds.size.height)]; 300 | 301 | break; 302 | 303 | default: 304 | break; 305 | } 306 | 307 | [self resizeContentWithIndex:-1]; 308 | } 309 | 310 | /** 311 | * 动态切换滚动方向 312 | * 313 | * @param direction 方向 314 | * @param animated 是否执行动画 315 | */ 316 | - (void)setScrollDirection:(JCScrollViewScrollDirection)direction animated:(BOOL)animated { 317 | 318 | if (!animated) { 319 | /** 320 | * 方向相同不执行 321 | */ 322 | if (_scrollDirection == direction) return; 323 | _scrollDirection = direction; 324 | [self convertImageViewsBetweenHorizontalAndVertical]; 325 | return; 326 | } 327 | 328 | if (self.isAnimating) 329 | return; 330 | 331 | void (^JCAffineTransformTranslate)(UIImageView*, CGFloat, CGFloat) = ^(UIImageView *imageView, CGFloat tx, CGFloat ty){ 332 | 333 | CGRect imageframe = imageView.frame; 334 | imageframe.origin.x += tx; 335 | imageframe.origin.y += ty; 336 | imageView.frame = imageframe; 337 | 338 | }; 339 | 340 | void (^JCAffineTransformScale)(UIImageView*, CGFloat) = ^(UIImageView *imageView, CGFloat scale){ 341 | CGRect imageBounds = imageView.bounds; 342 | imageBounds.size.width *= scale; 343 | imageBounds.size.height *= scale; 344 | imageView.bounds = imageBounds; 345 | }; 346 | 347 | /** 348 | * 缩放比例 占据屏幕的3分之一 349 | */ 350 | CGFloat scale = 0.33; 351 | 352 | /** 353 | * 动画时长 354 | */ 355 | CGFloat duration = self.animationDuration; 356 | 357 | self.animating = YES; 358 | 359 | /** 360 | * 通知代理开始动画 361 | */ 362 | if ([self.animationDelegate respondsToSelector:@selector(scrollViewDidBeginAnimating:)]) { 363 | [self.animationDelegate scrollViewDidBeginAnimating:self]; 364 | } 365 | 366 | [UIView animateWithDuration:duration animations:^{ 367 | 368 | for (UIImageView *imageView in self.imageViews) { 369 | 370 | if (self.currentIndex == [self.imageViews indexOfObject:imageView]) { 371 | 372 | JCAffineTransformScale(imageView,scale); 373 | 374 | } else { 375 | 376 | switch (self.scrollDirection) { 377 | case JCScrollViewScrollDirectionHorizontal: 378 | 379 | JCAffineTransformTranslate(imageView,(self.contentOffset.x - imageView.frame.origin.x) * 0.65,0); 380 | 381 | break; 382 | case JCScrollViewScrollDirectionVertical: 383 | 384 | JCAffineTransformTranslate(imageView,0,(self.contentOffset.y - imageView.frame.origin.y) * 0.65); 385 | 386 | break; 387 | default: 388 | break; 389 | } 390 | } 391 | } 392 | 393 | } completion:^(BOOL finished) { 394 | 395 | [UIView animateWithDuration:duration animations:^{ 396 | 397 | for (UIImageView *imageView in self.imageViews) { 398 | 399 | if (self.currentIndex == [self.imageViews indexOfObject:imageView]) { 400 | 401 | continue; 402 | 403 | } else { 404 | 405 | /** 406 | * 适配IOS8, IOS8中调用UIView动画连续调用两个不同的transform会有卡顿 407 | */ 408 | JCAffineTransformScale(imageView,scale); 409 | } 410 | } 411 | 412 | //第三步,乾坤大挪移 413 | } completion:^(BOOL finished) { 414 | //如果方向没有改变,恢复,退出 415 | if (self.scrollDirection == direction) { 416 | 417 | [UIView animateWithDuration:duration animations:^{ 418 | for (UIImageView *imageView in self.imageViews) { 419 | 420 | JCAffineTransformScale(imageView, 1/scale); 421 | 422 | switch (self.scrollDirection) { 423 | case JCScrollViewScrollDirectionHorizontal: 424 | { 425 | NSInteger currentPage = (imageView.frame.origin.x-self.bounds.size.width*self.pageControl.currentPage) / (self.bounds.size.width*scale); 426 | currentPage += self.pageControl.currentPage; 427 | imageView.frame = (CGRect){{currentPage * self.bounds.size.width,imageView.frame.origin.y},imageView.bounds.size}; 428 | break; 429 | } 430 | case JCScrollViewScrollDirectionVertical: 431 | { 432 | NSInteger currentPage = (imageView.frame.origin.y-self.bounds.size.height*self.pageControl.currentPage) / (self.bounds.size.height*scale); 433 | currentPage += self.pageControl.currentPage; 434 | imageView.frame = (CGRect){{imageView.frame.origin.x,currentPage * self.bounds.size.height},imageView.bounds.size}; 435 | 436 | break; 437 | } 438 | default: 439 | break; 440 | } 441 | 442 | } 443 | }completion:^(BOOL finished) { 444 | self.animating = NO; 445 | if ([self.animationDelegate respondsToSelector:@selector(scrollViewDidEndAnimating:)]) { 446 | [self.animationDelegate scrollViewDidEndAnimating:self]; 447 | } 448 | }]; 449 | 450 | return; 451 | } 452 | 453 | //能来到这里说明方向不同 454 | _scrollDirection = direction; 455 | 456 | [UIView animateWithDuration:duration animations:^{ 457 | 458 | CGFloat paddingV = 6.5; 459 | CGFloat paddingH = 11.5; 460 | CGFloat padding = 0; 461 | NSInteger flag = 0; 462 | for (UIImageView *imageView in self.imageViews) { 463 | //当前显示的这张不变 464 | if (self.currentIndex == [self.imageViews indexOfObject:imageView]) { 465 | 466 | continue; 467 | 468 | } else { 469 | //要切换成哪个方向 470 | switch (direction) { 471 | case JCScrollViewScrollDirectionHorizontal: 472 | { 473 | 474 | flag = imageView.frame.origin.y > self.contentOffset.y ? 1 : -1; 475 | 476 | padding = paddingH; 477 | 478 | break; 479 | } 480 | case JCScrollViewScrollDirectionVertical: 481 | { 482 | 483 | flag = imageView.frame.origin.x > self.contentOffset.x ? -1 : 1; 484 | 485 | padding = paddingV; 486 | 487 | break; 488 | } 489 | 490 | default: 491 | break; 492 | } 493 | 494 | JCAffineTransformTranslate(imageView,(imageView.bounds.size.width + padding)*flag,(-imageView.bounds.size.height - padding)*flag); 495 | 496 | } 497 | 498 | } 499 | 500 | } completion:^(BOOL finished) { 501 | 502 | [UIView animateWithDuration:duration animations:^{ 503 | for (UIImageView *imageView in self.imageViews) { 504 | 505 | JCAffineTransformScale(imageView, 1/scale); 506 | 507 | switch (self.scrollDirection) { 508 | case JCScrollViewScrollDirectionHorizontal: 509 | { 510 | NSInteger currentPage = imageView.frame.origin.x / (self.bounds.size.width*scale); 511 | imageView.frame = (CGRect){{currentPage * self.bounds.size.width,imageView.frame.origin.y},imageView.bounds.size}; 512 | break; 513 | } 514 | case JCScrollViewScrollDirectionVertical: 515 | { 516 | NSInteger currentPage = imageView.frame.origin.y / (self.bounds.size.height*scale); 517 | imageView.frame = (CGRect){{imageView.frame.origin.x,currentPage * self.bounds.size.height},imageView.bounds.size}; 518 | break; 519 | } 520 | default: 521 | break; 522 | } 523 | 524 | } 525 | } completion:^(BOOL finished) { 526 | 527 | for (UIImageView *imageView in self.imageViews) { 528 | 529 | switch (self.scrollDirection) { 530 | case JCScrollViewScrollDirectionHorizontal: 531 | { 532 | NSInteger currentPage = imageView.frame.origin.x / self.bounds.size.width; 533 | currentPage += self.pageControl.currentPage; 534 | imageView.frame = (CGRect){{0,currentPage * self.bounds.size.height},imageView.bounds.size}; 535 | break; 536 | } 537 | case JCScrollViewScrollDirectionVertical: 538 | { 539 | NSInteger currentPage = imageView.frame.origin.y / self.bounds.size.height; 540 | currentPage += self.pageControl.currentPage; 541 | imageView.frame = (CGRect){{currentPage * self.bounds.size.width,0},imageView.bounds.size}; 542 | break; 543 | } 544 | default: 545 | break; 546 | } 547 | 548 | 549 | } 550 | 551 | [self convertImageViewsBetweenHorizontalAndVertical]; 552 | 553 | self.animating = NO; 554 | 555 | if ([self.animationDelegate respondsToSelector:@selector(scrollViewDidEndAnimating:)]) { 556 | [self.animationDelegate scrollViewDidEndAnimating:self]; 557 | } 558 | }]; 559 | 560 | }]; 561 | 562 | }]; 563 | 564 | }]; 565 | 566 | } 567 | 568 | - (instancetype)initWithCoder:(NSCoder *)coder 569 | { 570 | self = [super initWithCoder:coder]; 571 | if (self) { 572 | [self setup]; 573 | } 574 | return self; 575 | } 576 | 577 | - (id)initWithFrame:(CGRect)frame 578 | { 579 | if (self = [super initWithFrame:frame]) { 580 | [self setup]; 581 | } 582 | return self; 583 | } 584 | 585 | - (void)setup { 586 | self.currentIndex = 1; 587 | self.bounces = NO; 588 | self.showsHorizontalScrollIndicator = NO; 589 | self.showsVerticalScrollIndicator = NO; 590 | self.pagingEnabled = YES; 591 | self.imageNames = [NSMutableArray array]; 592 | self.animationDuration = 1; 593 | self.pageControlEnabled = YES; 594 | // _scrollDirection = JCScrollViewScrollDirectionVertical; 595 | } 596 | 597 | - (void)layoutSubviews { 598 | [super layoutSubviews]; 599 | [self imageViews]; 600 | CGFloat pageControlW = self.bounds.size.width; 601 | CGFloat pageControlH = self.bounds.size.height * 0.1; 602 | CGFloat pageControlX = self.frame.origin.x; 603 | CGFloat pageControlY = self.bounds.size.height - pageControlH * 1.5; 604 | self.pageControl.frame = CGRectMake(pageControlX, pageControlY, pageControlW, pageControlH); 605 | 606 | if (self.pageControlEnabled) 607 | [self.superview addSubview:self.pageControl]; 608 | } 609 | 610 | //direction Next -1 Previous 1 611 | - (void)moveImageViewWithDirection:(JCScrollViewMoveDirection)direction{ 612 | 613 | NSInteger preIndex = self.currentIndex + direction; 614 | if (preIndex == 3) 615 | preIndex = 0; 616 | else if (preIndex == -1) 617 | preIndex = 2; 618 | 619 | NSInteger offset = _pageControl.currentPage - direction; 620 | 621 | self.currentIndex-=direction; 622 | 623 | //把前一张或后一张移动 624 | [self setImageWithImageIndex:preIndex andImageNameIndex:offset]; 625 | } 626 | 627 | - (void)setImageWithImageIndex:(NSInteger)imageIndex andImageNameIndex:(NSInteger)nameIndex { 628 | if (self.imageNames.count < 3) { 629 | return; 630 | } 631 | UIImageView *imageView = self.imageViews[imageIndex]; 632 | CGRect imageRect = imageView.frame; 633 | 634 | switch (_scrollDirection) { 635 | case JCScrollViewScrollDirectionHorizontal: 636 | 637 | imageRect.origin.x = (nameIndex) * self.bounds.size.width; 638 | 639 | break; 640 | case JCScrollViewScrollDirectionVertical: 641 | 642 | imageRect.origin.y = (nameIndex) * self.bounds.size.height; 643 | 644 | break; 645 | 646 | default: 647 | break; 648 | } 649 | 650 | imageView.frame = imageRect; 651 | 652 | if (nameIndex < self.imageNames.count && nameIndex >= 0) { 653 | imageView.image = [UIImage imageNamed:self.imageNames[nameIndex]]; 654 | } 655 | 656 | } 657 | 658 | @end 659 | --------------------------------------------------------------------------------