diff --git a/RCPageControl/RCAbstractIndicatorView.h b/RCPageControl/RCAbstractIndicatorView.h new file mode 100644 index 0000000..f03cedb --- /dev/null +++ b/RCPageControl/RCAbstractIndicatorView.h @@ -0,0 +1,15 @@ +// +// RCAbstractIndicatorView.h +// Pods +// +// Created by Simo ++ on 18/10/2015. +// +// + +#import + +@interface RCAbstractIndicatorView : UIView + +- (void)updateState:(BOOL)isCurrent; + +@end diff --git a/RCPageControl/RCAbstractIndicatorView.m b/RCPageControl/RCAbstractIndicatorView.m new file mode 100644 index 0000000..1382c2e --- /dev/null +++ b/RCPageControl/RCAbstractIndicatorView.m @@ -0,0 +1,27 @@ +// +// RCAbstractIndicatorView.m +// Pods +// +// Created by Simo ++ on 18/10/2015. +// +// + +#import "RCAbstractIndicatorView.h" + +@implementation RCAbstractIndicatorView + +- (instancetype)init { + + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in %@", NSStringFromSelector(_cmd), self.class] + userInfo:nil]; +} + +- (void)updateState:(BOOL)isCurrent { + + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in %@", NSStringFromSelector(_cmd), self.class] + userInfo:nil]; +} + +@end diff --git a/RCPageControl/RCPageControl.h b/RCPageControl/RCPageControl.h index 6f85664..210d4b7 100644 --- a/RCPageControl/RCPageControl.h +++ b/RCPageControl/RCPageControl.h @@ -31,6 +31,7 @@ */ #import +#import "RCAbstractIndicatorView.h" @class RCPageControl; @@ -60,9 +61,12 @@ typedef void (^RCCurrentPageChangedBlock)(RCPageControl *pageControl); @property(nonatomic) UIFont *currentPageIndexTextFont; // default is [UIFont systemFontOfSize:0], the font size is automatically adjusts by the value of indicatorDotWidth and animationScaleFactor +@property (nonatomic, readonly) Class pageIndicatorViewClass; //to use custom indicator view class, must use 'initWithPageControlClass'. + @property (nonatomic, copy) RCCurrentPageChangedBlock currentPageChangedBlock; // if set, -sendActionsForControlEvents will never be called, only available for 'Touch Event' in page control, it also means you need to set non-zero frame for page control to activate 'Touch Event' - (instancetype)initWithNumberOfPages:(NSInteger)pages; // if you want 'currentPageChanged' block available, call -setFrame: after initialization +- (instancetype)initWithPageControlClass:(Class)class; - (void)updateCurrentPageDisplay; // update page display to match the currentPage, ignored if defersCurrentPageDisplay is NO, setting the page value directly will update immediately diff --git a/RCPageControl/RCPageControl.m b/RCPageControl/RCPageControl.m index 4d94ba9..cd90937 100644 --- a/RCPageControl/RCPageControl.m +++ b/RCPageControl/RCPageControl.m @@ -50,7 +50,7 @@ of this software and associated documentation files (the "Software"), to deal #define RCDefaultIndicatorColorAnimationKey @"RCPageControlIndicatorColorAnimation" #define RCDefaultIndicatorIndexLabelAlphaAnimationKey @"RCDefaultIndicatorIndexLabelAlphaAnimationKey" -#define IsFloatZero(A) fabsf(A) < FLT_EPSILON +#define IsFloatZero(A) fabs(A) < FLT_EPSILON #define IsFloatEqualToFloat(A, B) IsFloatZero((A) - (B)) @interface RCPageControl () @@ -87,6 +87,16 @@ - (instancetype)initWithNumberOfPages:(NSInteger)pages { return pageControl; } +- (instancetype)initWithPageControlClass:(Class)class { + RCPageControl *pageControl = [self init]; + + if (class) { + [pageControl setPageIndicatorViewClass:class]; + } + + return pageControl; +} + - (void)awakeFromNib { [self commConfig]; } @@ -253,6 +263,13 @@ - (void)setCurrentPageIndexTextFont:(UIFont *)currentPageIndexTextFont { } } +- (void)setPageIndicatorViewClass:(Class)pageIndicatorViewClass { + if ( ![_pageIndicatorViewClass isEqual:pageIndicatorViewClass]) { + _pageIndicatorViewClass = pageIndicatorViewClass; + [self _refreshIndicator:YES]; + } +} + #pragma mark - Touch Event - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { @@ -357,6 +374,16 @@ - (void)_dotScaleAnimationAtIndex:(NSInteger)index withProgress:(CGFloat)progres } - (void)_dotColorAnimationAtIndex:(NSInteger)index withProgress:(CGFloat)progress { + + if (self.pageIndicatorViewClass) { + + RCAbstractIndicatorView *view = (RCAbstractIndicatorView *)[self _dotAtIndex:index]; + + if ([view respondsToSelector:@selector(updateState:)]) { + [view updateState:(index == _currentDisplayedPage) ? YES : NO]; + } + } + [self _dotColorAnimationAtIndex:index toValue:(index == _currentDisplayedPage) ? _currentPageIndicatorTintColor : _pageIndicatorTintColor]; } @@ -406,7 +433,25 @@ - (void)_refreshIndicator:(BOOL)forceRefresh { for (; index < _numberOfPages; index ++) { CGRect frame = CGRectMake(position.x + index * (_indicatorDotGap + _indicatorDotWidth), position.y, _indicatorDotWidth, _indicatorDotWidth); - UIView *dot = [self _dotAtIndex:index] ?: [[UIView alloc] initWithFrame:frame]; + + UIView *dot; + + if ([self _dotAtIndex:index]) { + dot = [self _dotAtIndex:index]; + } else { + if (_pageIndicatorViewClass) { + + dot = (RCAbstractIndicatorView *)[[_pageIndicatorViewClass alloc] initWithFrame:frame]; + + if ([dot respondsToSelector:@selector(updateState:)]) { + [(RCAbstractIndicatorView *)dot updateState:(index == _currentDisplayedPage) ? YES : NO]; + } + + } else { + dot = [[UIView alloc] initWithFrame:frame]; + [dot.layer setCornerRadius:(frame.size.width/2)]; + } + } if ([UIView respondsToSelector:@selector(performWithoutAnimation:)]) { [UIView performWithoutAnimation:^{ @@ -421,9 +466,7 @@ - (void)_refreshIndicator:(BOOL)forceRefresh { [dot setTag:[self _dotTagAtIndex:index]]; [dot setBackgroundColor:_pageIndicatorTintColor]; - [dot.layer setMasksToBounds:YES]; - [dot.layer setCornerRadius:dot.frame.size.height / 2]; if ( !dot.superview) { [self addSubview:dot]; diff --git a/RCPageControlExample/Podfile.lock b/RCPageControlExample/Podfile.lock index 409ed77..05b041e 100644 --- a/RCPageControlExample/Podfile.lock +++ b/RCPageControlExample/Podfile.lock @@ -1,7 +1,7 @@ PODS: - - iCarousel (1.8.1) - - pop (1.0.7) - - RCPageControl (0.1): + - iCarousel (1.8.2) + - pop (1.0.8) + - RCPageControl (0.1.1): - pop DEPENDENCIES: @@ -14,8 +14,8 @@ EXTERNAL SOURCES: :path: ../ SPEC CHECKSUMS: - iCarousel: 5acab560f10dc13da2440c89f35a0ad278b5147d - pop: 2f14a1ea61339767af9e66741b418c831b3844df - RCPageControl: bdfb2c9322b41bc4e4a166e585f4a6564e14643b + iCarousel: 67c8a43da5a46795b56aadfc96cd36a16f6149b2 + pop: bb773ae2c791ca2629de13b347e7a8b450fa6a57 + RCPageControl: d7f6a8f5e1f9ca9a8ed7dbe32b5c266cf2844070 -COCOAPODS: 0.36.0.rc.1 +COCOAPODS: 0.39.0 diff --git a/RCPageControlExample/RCPageControlExample.xcodeproj/project.pbxproj b/RCPageControlExample/RCPageControlExample.xcodeproj/project.pbxproj index 7b0d112..6f4ea4d 100644 --- a/RCPageControlExample/RCPageControlExample.xcodeproj/project.pbxproj +++ b/RCPageControlExample/RCPageControlExample.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 6E2F734619C72601008985F7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6E2F734519C72601008985F7 /* Images.xcassets */; }; 6E2F734919C72601008985F7 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6E2F734719C72601008985F7 /* LaunchScreen.xib */; }; 6E2F735519C72601008985F7 /* RCPageControlExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E2F735419C72601008985F7 /* RCPageControlExampleTests.m */; }; + B266C4C91BD3DD6500604FD1 /* CustomIndicatorView.m in Sources */ = {isa = PBXBuildFile; fileRef = B266C4C81BD3DD6500604FD1 /* CustomIndicatorView.m */; settings = {ASSET_TAGS = (); }; }; D49C37915C534FBF81B1C62C /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E1326DC0F37B4CD9B3DC981C /* libPods.a */; }; /* End PBXBuildFile section */ @@ -45,6 +46,8 @@ 6E2F735319C72601008985F7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6E2F735419C72601008985F7 /* RCPageControlExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCPageControlExampleTests.m; sourceTree = ""; }; 6E55D24919C97C01008E8B03 /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; + B266C4C71BD3DD6500604FD1 /* CustomIndicatorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomIndicatorView.h; sourceTree = ""; }; + B266C4C81BD3DD6500604FD1 /* CustomIndicatorView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomIndicatorView.m; sourceTree = ""; }; DAF73DA31F7F816C3C0D9AD6 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; E1326DC0F37B4CD9B3DC981C /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -95,6 +98,8 @@ 6E2F733D19C72600008985F7 /* AppDelegate.m */, 6E2F733F19C72600008985F7 /* ViewController.h */, 6E2F734019C72600008985F7 /* ViewController.m */, + B266C4C71BD3DD6500604FD1 /* CustomIndicatorView.h */, + B266C4C81BD3DD6500604FD1 /* CustomIndicatorView.m */, 6E2F734219C72600008985F7 /* Main.storyboard */, 6E2F734519C72601008985F7 /* Images.xcassets */, 6E2F734719C72601008985F7 /* LaunchScreen.xib */, @@ -160,6 +165,7 @@ 6E2F733219C72600008985F7 /* Frameworks */, 6E2F733319C72600008985F7 /* Resources */, 4205A7A3089C4258B519BEEC /* Copy Pods Resources */, + C44C854C1AC0DA35B6023388 /* Embed Pods Frameworks */, ); buildRules = ( ); @@ -277,6 +283,21 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; + C44C854C1AC0DA35B6023388 /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -287,6 +308,7 @@ 6E2F734119C72600008985F7 /* ViewController.m in Sources */, 6E2F733E19C72600008985F7 /* AppDelegate.m in Sources */, 6E2F733B19C72600008985F7 /* main.m in Sources */, + B266C4C91BD3DD6500604FD1 /* CustomIndicatorView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/RCPageControlExample/RCPageControlExample/CustomIndicatorView.h b/RCPageControlExample/RCPageControlExample/CustomIndicatorView.h new file mode 100644 index 0000000..cfd94d9 --- /dev/null +++ b/RCPageControlExample/RCPageControlExample/CustomIndicatorView.h @@ -0,0 +1,14 @@ +// +// CustomIndicatorView.h +// RCPageControlExample +// +// Created by Simo ++ on 18/10/2015. +// Copyright © 2015 RidgeCorn. All rights reserved. +// + +#import +#import "RCAbstractIndicatorView.h" + +@interface CustomIndicatorView : RCAbstractIndicatorView + +@end diff --git a/RCPageControlExample/RCPageControlExample/CustomIndicatorView.m b/RCPageControlExample/RCPageControlExample/CustomIndicatorView.m new file mode 100644 index 0000000..8055059 --- /dev/null +++ b/RCPageControlExample/RCPageControlExample/CustomIndicatorView.m @@ -0,0 +1,56 @@ +// +// CustomIndicatorView.m +// RCPageControlExample +// +// Created by Simo ++ on 18/10/2015. +// Copyright © 2015 RidgeCorn. All rights reserved. +// + +#import "CustomIndicatorView.h" + +@interface CustomIndicatorView() + +@property (nonatomic) UIImageView *imageView; + +@end + +@implementation CustomIndicatorView + +#pragma mark - Properties + +- (UIImageView *)imageView { + if (!_imageView) { + _imageView = [UIImageView new]; + _imageView.backgroundColor = [UIColor clearColor]; + } + return _imageView; +} + +#pragma mark - Lifecycle + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + [self addSubview:self.imageView]; + } + return self; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + self.layer.cornerRadius = (self.frame.size.width/2); + self.imageView.frame = self.bounds; +} + +- (void)updateState:(BOOL)isCurrent { + + //customize your indicator view here. + + UIImage *image = isCurrent ? [UIImage imageNamed:@"Happy"] : [UIImage imageNamed:@"Sad"]; + [self.imageView setImage:image]; +} + +@end diff --git a/RCPageControlExample/RCPageControlExample/Images.xcassets/Contents.json b/RCPageControlExample/RCPageControlExample/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/RCPageControlExample/RCPageControlExample/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RCPageControlExample/RCPageControlExample/Images.xcassets/Happy.imageset/Contents.json b/RCPageControlExample/RCPageControlExample/Images.xcassets/Happy.imageset/Contents.json new file mode 100644 index 0000000..f912274 --- /dev/null +++ b/RCPageControlExample/RCPageControlExample/Images.xcassets/Happy.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Emoticons Happy.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RCPageControlExample/RCPageControlExample/Images.xcassets/Happy.imageset/Emoticons Happy.png b/RCPageControlExample/RCPageControlExample/Images.xcassets/Happy.imageset/Emoticons Happy.png new file mode 100644 index 0000000..9940a24 Binary files /dev/null and b/RCPageControlExample/RCPageControlExample/Images.xcassets/Happy.imageset/Emoticons Happy.png differ diff --git a/RCPageControlExample/RCPageControlExample/Images.xcassets/Sad.imageset/Contents.json b/RCPageControlExample/RCPageControlExample/Images.xcassets/Sad.imageset/Contents.json new file mode 100644 index 0000000..308cfa7 --- /dev/null +++ b/RCPageControlExample/RCPageControlExample/Images.xcassets/Sad.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Emoticons Sad.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RCPageControlExample/RCPageControlExample/Images.xcassets/Sad.imageset/Emoticons Sad.png b/RCPageControlExample/RCPageControlExample/Images.xcassets/Sad.imageset/Emoticons Sad.png new file mode 100644 index 0000000..906a101 Binary files /dev/null and b/RCPageControlExample/RCPageControlExample/Images.xcassets/Sad.imageset/Emoticons Sad.png differ diff --git a/RCPageControlExample/RCPageControlExample/ViewController.m b/RCPageControlExample/RCPageControlExample/ViewController.m index 12623a3..8018f65 100644 --- a/RCPageControlExample/RCPageControlExample/ViewController.m +++ b/RCPageControlExample/RCPageControlExample/ViewController.m @@ -9,10 +9,12 @@ #import "ViewController.h" #import #import +#import "CustomIndicatorView.h" @interface ViewController () @property (nonatomic) RCPageControl *pageControlRC; +@property (nonatomic) RCPageControl *pageControlRCCustomView; @property (nonatomic) iCarousel *pageViews; @property (nonatomic) NSInteger numberOfPages; @property (nonatomic) UIPageControl *pageControlUI; @@ -37,13 +39,40 @@ - (void)viewDidLoad { _pageViews; })]; + [self.view addSubview:({ + if ( !_pageControlRCCustomView) { + _pageControlRCCustomView = [[RCPageControl alloc] initWithPageControlClass:[CustomIndicatorView class]]; + + _pageControlRCCustomView.numberOfPages = _numberOfPages; + _pageControlRCCustomView.indicatorDotWidth = 20.0f; + _pageControlRCCustomView.indicatorDotGap = 30.0f; + _pageControlRCCustomView.animationScaleFactor = 1.2f; + _pageControlRCCustomView.hideCurrentPageIndex = YES; + _pageControlRCCustomView.pageIndicatorTintColor = [UIColor colorWithRed:(48.0/255.0) green:(129.0/255.0) blue:(245.0/255.0) alpha:1.0f]; + _pageControlRCCustomView.currentPageIndicatorTintColor = [UIColor whiteColor]; + + [_pageControlRCCustomView setCenter:({ + CGPoint center = self.view.center; + center.y = self.view.frame.size.height - 120.f; + center; + })]; + + __weak ViewController *weakSelf = self; + [_pageControlRCCustomView setCurrentPageChangedBlock:^(RCPageControl *pageControl) { + [weakSelf.pageViews scrollToItemAtIndex:pageControl.currentPage animated:YES]; + }]; + } + _pageControlRCCustomView; + })]; + + [self.view addSubview:({ if ( !_pageControlRC) { _pageControlRC = [[RCPageControl alloc] initWithNumberOfPages:_numberOfPages]; [_pageControlRC setCenter:({ CGPoint center = self.view.center; - center.y = self.view.frame.size.height - 160.f; + center.y = self.view.frame.size.height - 220.f; center; })]; @@ -55,6 +84,7 @@ - (void)viewDidLoad { _pageControlRC; })]; + [self.view addSubview:({ if ( !_pageControlUI) { _pageControlUI = [[UIPageControl alloc] init]; @@ -105,6 +135,7 @@ - (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSInteger)index r - (void)carouselDidEndScrollingAnimation:(iCarousel *)carousel { [_pageControlRC setCurrentPage:carousel.currentItemIndex]; + [_pageControlRCCustomView setCurrentPage:carousel.currentItemIndex]; [_pageControlUI setCurrentPage:carousel.currentItemIndex]; }