diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..e703d26 Binary files /dev/null and b/.DS_Store differ diff --git a/XLPagerTabStrip.xcodeproj/project.pbxproj b/XLPagerTabStrip.xcodeproj/project.pbxproj index a6879d3..ec0497b 100644 --- a/XLPagerTabStrip.xcodeproj/project.pbxproj +++ b/XLPagerTabStrip.xcodeproj/project.pbxproj @@ -29,6 +29,8 @@ 28B63AF11A45B26600225C66 /* XLPagerTabStripViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28B63AEC1A45B26600225C66 /* XLPagerTabStripViewController.m */; }; 28B63AF21A45B26600225C66 /* XLSegmentedPagerTabStripViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28B63AEE1A45B26600225C66 /* XLSegmentedPagerTabStripViewController.m */; }; 28B63AF51A465E5E00225C66 /* ReloadExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28B63AF41A465E5E00225C66 /* ReloadExampleViewController.m */; }; + 66C6E4B41AB9D538005361FB /* FXPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 66C6E4B11AB9D538005361FB /* FXPageControl.m */; }; + 66CA35B41A8D174900564221 /* XLTwitterPagerTabStripViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 66CA35B31A8D174900564221 /* XLTwitterPagerTabStripViewController.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -84,6 +86,10 @@ 28B63AEE1A45B26600225C66 /* XLSegmentedPagerTabStripViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XLSegmentedPagerTabStripViewController.m; path = Controllers/XLSegmentedPagerTabStripViewController.m; sourceTree = ""; }; 28B63AF31A465E5E00225C66 /* ReloadExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReloadExampleViewController.h; sourceTree = ""; }; 28B63AF41A465E5E00225C66 /* ReloadExampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReloadExampleViewController.m; sourceTree = ""; }; + 66C6E4B01AB9D538005361FB /* FXPageControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FXPageControl.h; sourceTree = ""; }; + 66C6E4B11AB9D538005361FB /* FXPageControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FXPageControl.m; sourceTree = ""; }; + 66CA35B21A8D174900564221 /* XLTwitterPagerTabStripViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XLTwitterPagerTabStripViewController.h; path = Controllers/XLTwitterPagerTabStripViewController.h; sourceTree = ""; }; + 66CA35B31A8D174900564221 /* XLTwitterPagerTabStripViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XLTwitterPagerTabStripViewController.m; path = Controllers/XLTwitterPagerTabStripViewController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -125,6 +131,7 @@ 28B63A881A459F5900225C66 /* XLPagerTabStrip */ = { isa = PBXGroup; children = ( + 66C6E4AF1AB9D538005361FB /* FXPageControl */, 28B63ACC1A45A4CD00225C66 /* XL */, 28B63AAF1A45A4C500225C66 /* Demo */, 28B63A8D1A459F5900225C66 /* AppDelegate.h */, @@ -244,10 +251,21 @@ 28B63AEC1A45B26600225C66 /* XLPagerTabStripViewController.m */, 28B63AED1A45B26600225C66 /* XLSegmentedPagerTabStripViewController.h */, 28B63AEE1A45B26600225C66 /* XLSegmentedPagerTabStripViewController.m */, + 66CA35B21A8D174900564221 /* XLTwitterPagerTabStripViewController.h */, + 66CA35B31A8D174900564221 /* XLTwitterPagerTabStripViewController.m */, ); name = Controllers; sourceTree = ""; }; + 66C6E4AF1AB9D538005361FB /* FXPageControl */ = { + isa = PBXGroup; + children = ( + 66C6E4B01AB9D538005361FB /* FXPageControl.h */, + 66C6E4B11AB9D538005361FB /* FXPageControl.m */, + ); + path = FXPageControl; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -352,6 +370,7 @@ 28B63AC51A45A4C500225C66 /* ChildExampleViewController.m in Sources */, 28B63AF11A45B26600225C66 /* XLPagerTabStripViewController.m in Sources */, 28B63AC41A45A4C500225C66 /* ButtonBarExampleViewController.m in Sources */, + 66CA35B41A8D174900564221 /* XLTwitterPagerTabStripViewController.m in Sources */, 28B63ADC1A45A4CD00225C66 /* XLBarView.m in Sources */, 28B63AC81A45A4C500225C66 /* XLJSONSerialization.m in Sources */, 28B63ADD1A45A4CD00225C66 /* XLButtonBarView.m in Sources */, @@ -366,6 +385,7 @@ 28B63AF01A45B26600225C66 /* XLButtonBarPagerTabStripViewController.m in Sources */, 28B63A8C1A459F5900225C66 /* main.m in Sources */, 28B63AC61A45A4C500225C66 /* TableChildExampleViewController.m in Sources */, + 66C6E4B41AB9D538005361FB /* FXPageControl.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/XLPagerTabStrip/.DS_Store b/XLPagerTabStrip/.DS_Store new file mode 100644 index 0000000..f34cdf0 Binary files /dev/null and b/XLPagerTabStrip/.DS_Store differ diff --git a/XLPagerTabStrip/Demo/Storyboard.storyboard b/XLPagerTabStrip/Demo/Storyboard.storyboard index 688ae69..195a23a 100644 --- a/XLPagerTabStrip/Demo/Storyboard.storyboard +++ b/XLPagerTabStrip/Demo/Storyboard.storyboard @@ -1,7 +1,7 @@ - + - + @@ -14,10 +14,10 @@ - + - + @@ -56,7 +56,7 @@ - + @@ -87,7 +87,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/XLPagerTabStrip/FXPageControl/FXPageControl.h b/XLPagerTabStrip/FXPageControl/FXPageControl.h new file mode 100755 index 0000000..37a0438 --- /dev/null +++ b/XLPagerTabStrip/FXPageControl/FXPageControl.h @@ -0,0 +1,106 @@ +// +// FXPageControl.h +// +// Version 1.4 +// +// Created by Nick Lockwood on 07/01/2010. +// Copyright 2010 Charcoal Design +// +// Distributed under the permissive zlib License +// Get the latest version of FXPageControl from here: +// +// https://github.com/nicklockwood/FXPageControl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis" +#import + + +#import +#undef weak_delegate +#if __has_feature(objc_arc_weak) +#define weak_delegate weak +#else +#define weak_delegate unsafe_unretained +#endif + + +extern const CGPathRef FXPageControlDotShapeCircle; +extern const CGPathRef FXPageControlDotShapeSquare; +extern const CGPathRef FXPageControlDotShapeTriangle; + + +@protocol FXPageControlDelegate; + + +IB_DESIGNABLE @interface FXPageControl : UIControl + +- (void)setUp; +- (CGSize)sizeForNumberOfPages:(NSInteger)pageCount; +- (void)updateCurrentPageDisplay; + +@property (nonatomic, weak_delegate) IBOutlet id delegate; + +@property (nonatomic, assign) IBInspectable NSInteger currentPage; +@property (nonatomic, assign) IBInspectable NSInteger numberOfPages; +@property (nonatomic, assign) IBInspectable BOOL defersCurrentPageDisplay; +@property (nonatomic, assign) IBInspectable BOOL hidesForSinglePage; +@property (nonatomic, assign, getter = isWrapEnabled) IBInspectable BOOL wrapEnabled; +@property (nonatomic, assign, getter = isVertical) IBInspectable BOOL vertical; + +@property (nonatomic, strong) IBInspectable UIImage *dotImage; +@property (nonatomic, assign) IBInspectable CGPathRef dotShape; +@property (nonatomic, assign) IBInspectable CGFloat dotSize; +@property (nonatomic, strong) IBInspectable UIColor *dotColor; +@property (nonatomic, strong) IBInspectable UIColor *dotShadowColor; +@property (nonatomic, assign) IBInspectable CGFloat dotShadowBlur; +@property (nonatomic, assign) IBInspectable CGSize dotShadowOffset; + +@property (nonatomic, strong) IBInspectable UIImage *selectedDotImage; +@property (nonatomic, assign) IBInspectable CGPathRef selectedDotShape; +@property (nonatomic, assign) IBInspectable CGFloat selectedDotSize; +@property (nonatomic, strong) IBInspectable UIColor *selectedDotColor; +@property (nonatomic, strong) IBInspectable UIColor *selectedDotShadowColor; +@property (nonatomic, assign) IBInspectable CGFloat selectedDotShadowBlur; +@property (nonatomic, assign) IBInspectable CGSize selectedDotShadowOffset; + +@property (nonatomic, assign) IBInspectable CGFloat dotSpacing; + +@end + + +@protocol FXPageControlDelegate +@optional + +- (UIImage *)pageControl:(FXPageControl *)pageControl imageForDotAtIndex:(NSInteger)index; +- (CGPathRef)pageControl:(FXPageControl *)pageControl shapeForDotAtIndex:(NSInteger)index; +- (UIColor *)pageControl:(FXPageControl *)pageControl colorForDotAtIndex:(NSInteger)index; + +- (UIImage *)pageControl:(FXPageControl *)pageControl selectedImageForDotAtIndex:(NSInteger)index; +- (CGPathRef)pageControl:(FXPageControl *)pageControl selectedShapeForDotAtIndex:(NSInteger)index; +- (UIColor *)pageControl:(FXPageControl *)pageControl selectedColorForDotAtIndex:(NSInteger)index; + +@end + + +#pragma GCC diagnostic pop diff --git a/XLPagerTabStrip/FXPageControl/FXPageControl.m b/XLPagerTabStrip/FXPageControl/FXPageControl.m new file mode 100755 index 0000000..338eb19 --- /dev/null +++ b/XLPagerTabStrip/FXPageControl/FXPageControl.m @@ -0,0 +1,433 @@ +// +// FXPageControl.m +// +// Version 1.4 +// +// Created by Nick Lockwood on 07/01/2010. +// Copyright 2010 Charcoal Design +// +// Distributed under the permissive zlib License +// Get the latest version of FXPageControl from here: +// +// https://github.com/nicklockwood/FXPageControl +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + +#import "FXPageControl.h" + + +#pragma GCC diagnostic ignored "-Wgnu" +#pragma GCC diagnostic ignored "-Wreceiver-is-weak" +#pragma GCC diagnostic ignored "-Warc-repeated-use-of-weak" +#pragma GCC diagnostic ignored "-Wdirect-ivar-access" + + +#import +#if !__has_feature(objc_arc) +#error This class requires automatic reference counting +#endif + + +const CGPathRef FXPageControlDotShapeCircle = (const CGPathRef)1; +const CGPathRef FXPageControlDotShapeSquare = (const CGPathRef)2; +const CGPathRef FXPageControlDotShapeTriangle = (const CGPathRef)3; +#define LAST_SHAPE FXPageControlDotShapeTriangle + + +@implementation NSObject (FXPageControl) + +- (UIImage *)pageControl:(__unused FXPageControl *)pageControl imageForDotAtIndex:(__unused NSInteger)index { return nil; } +- (CGPathRef)pageControl:(__unused FXPageControl *)pageControl shapeForDotAtIndex:(__unused NSInteger)index { return NULL; } +- (UIColor *)pageControl:(__unused FXPageControl *)pageControl colorForDotAtIndex:(__unused NSInteger)index { return nil; } + +- (UIImage *)pageControl:(__unused FXPageControl *)pageControl selectedImageForDotAtIndex:(__unused NSInteger)index { return nil; } +- (CGPathRef)pageControl:(__unused FXPageControl *)pageControl selectedShapeForDotAtIndex:(__unused NSInteger)index { return NULL; } +- (UIColor *)pageControl:(__unused FXPageControl *)pageControl selectedColorForDotAtIndex:(__unused NSInteger)index { return nil; } + +@end + + +@implementation FXPageControl + +- (void)setUp +{ + //needs redrawing if bounds change + self.contentMode = UIViewContentModeRedraw; + + //set defaults + _dotSpacing = 10.0f; + _dotSize = 6.0f; + _dotShadowOffset = CGSizeMake(0, 1); + _selectedDotShadowOffset = CGSizeMake(0, 1); +} + +- (id)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) + { + [self setUp]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + if ((self = [super initWithCoder:aDecoder])) + { + [self setUp]; + } + return self; +} + +- (void)dealloc +{ + if (_dotShape > LAST_SHAPE) CGPathRelease(_dotShape); + if (_selectedDotShape > LAST_SHAPE) CGPathRelease(_selectedDotShape); +} + +- (CGSize)sizeForNumberOfPages:(__unused NSInteger)pageCount +{ + CGFloat width = _dotSize + (_dotSize + _dotSpacing) * (_numberOfPages - 1); + return _vertical? CGSizeMake(_dotSize, width): CGSizeMake(width, _dotSize); +} + +- (void)updateCurrentPageDisplay +{ + [self setNeedsDisplay]; +} + +- (void)drawRect:(__unused CGRect)rect +{ + if (_numberOfPages > 1 || !_hidesForSinglePage) + { + CGContextRef context = UIGraphicsGetCurrentContext(); + CGSize size = [self sizeForNumberOfPages:_numberOfPages]; + if (_vertical) + { + CGContextTranslateCTM(context, self.frame.size.width / 2, (self.frame.size.height - size.height) / 2); + } + else + { + CGContextTranslateCTM(context, (self.frame.size.width - size.width) / 2, self.frame.size.height / 2); + } + + for (int i = 0; i < _numberOfPages; i++) + { + UIImage *dotImage = nil; + UIColor *dotColor = nil; + CGPathRef dotShape = NULL; + CGFloat dotSize = 0; + UIColor *dotShadowColor = nil; + CGSize dotShadowOffset = CGSizeZero; + CGFloat dotShadowBlur = 0; + + if (i == _currentPage) + { + [_selectedDotColor setFill]; + dotImage = [_delegate pageControl:self selectedImageForDotAtIndex:i] ?: _selectedDotImage; + dotShape = [_delegate pageControl:self selectedShapeForDotAtIndex:i] ?: _selectedDotShape ?: _dotShape; + dotColor = [_delegate pageControl:self selectedColorForDotAtIndex:i] ?: _selectedDotColor ?: [UIColor blackColor]; + dotShadowBlur = _selectedDotShadowBlur; + dotShadowColor = _selectedDotShadowColor; + dotShadowOffset = _selectedDotShadowOffset; + dotSize = _selectedDotSize ?: _dotSize; + } + else + { + [_dotColor setFill]; + dotImage = [_delegate pageControl:self imageForDotAtIndex:i] ?: _dotImage; + dotShape = [_delegate pageControl:self shapeForDotAtIndex:i] ?: _dotShape; + dotColor = [_delegate pageControl:self colorForDotAtIndex:i] ?: _dotColor; + if (!dotColor) + { + //fall back to selected dot color with reduced alpha + dotColor = [_delegate pageControl:self selectedColorForDotAtIndex:i] ?: _selectedDotColor ?: [UIColor blackColor]; + dotColor = [dotColor colorWithAlphaComponent:0.25f]; + } + dotShadowBlur = _dotShadowBlur; + dotShadowColor = _dotShadowColor; + dotShadowOffset = _dotShadowOffset; + dotSize = _dotSize; + } + + CGContextSaveGState(context); + CGFloat offset = (_dotSize + _dotSpacing) * i + _dotSize / 2; + CGContextTranslateCTM(context, _vertical? 0: offset, _vertical? offset: 0); + + if (dotShadowColor && ![dotShadowColor isEqual:[UIColor clearColor]]) + { + CGContextSetShadowWithColor(context, dotShadowOffset, dotShadowBlur, dotShadowColor.CGColor); + } + if (dotImage) + { + [dotImage drawInRect:CGRectMake(-dotImage.size.width / 2, -dotImage.size.height / 2, dotImage.size.width, dotImage.size.height)]; + } + else + { + [dotColor setFill]; + if (!dotShape || dotShape == FXPageControlDotShapeCircle) + { + CGContextFillEllipseInRect(context, CGRectMake(-dotSize / 2, -dotSize / 2, dotSize, dotSize)); + } + else if (dotShape == FXPageControlDotShapeSquare) + { + CGContextFillRect(context, CGRectMake(-dotSize / 2, -dotSize / 2, dotSize, dotSize)); + } + else if (dotShape == FXPageControlDotShapeTriangle) + { + CGContextBeginPath(context); + CGContextMoveToPoint(context, 0, -dotSize / 2); + CGContextAddLineToPoint(context, dotSize / 2, dotSize / 2); + CGContextAddLineToPoint(context, -dotSize / 2, dotSize / 2); + CGContextAddLineToPoint(context, 0, -dotSize / 2); + CGContextFillPath(context); + } + else + { + CGContextBeginPath(context); + CGContextAddPath(context, dotShape); + CGContextFillPath(context); + } + } + CGContextRestoreGState(context); + } + } +} + +- (NSInteger)clampedPageValue:(NSInteger)page +{ + if (_wrapEnabled) + { + return _numberOfPages? (page + _numberOfPages) % _numberOfPages: 0; + } + else + { + return MIN(MAX(0, page), _numberOfPages - 1); + } +} + +- (void)setDotImage:(UIImage *)dotImage +{ + if (_dotImage != dotImage) + { + _dotImage = dotImage; + [self setNeedsDisplay]; + } +} + +- (void)setDotShape:(CGPathRef)dotShape +{ + if (_dotShape != dotShape) + { + if (_dotShape > LAST_SHAPE) CGPathRelease(_dotShape); + _dotShape = dotShape; + if (_dotShape > LAST_SHAPE) CGPathRetain(_dotShape); + [self setNeedsDisplay]; + } +} + +- (void)setDotSize:(CGFloat)dotSize +{ + if (ABS(_dotSize - dotSize) > 0.001) + { + _dotSize = dotSize; + [self setNeedsDisplay]; + } +} + +- (void)setDotColor:(UIColor *)dotColor +{ + if (_dotColor != dotColor) + { + _dotColor = dotColor; + [self setNeedsDisplay]; + } +} + +- (void)setDotShadowColor:(UIColor *)dotColor +{ + if (_dotShadowColor != dotColor) + { + _dotShadowColor = dotColor; + [self setNeedsDisplay]; + } +} + +- (void)setDotShadowBlur:(CGFloat)dotShadowBlur +{ + if (ABS(_dotShadowBlur - dotShadowBlur) > 0.001) + { + _dotShadowBlur = dotShadowBlur; + [self setNeedsDisplay]; + } +} + +- (void)setDotShadowOffset:(CGSize)dotShadowOffset +{ + if (!CGSizeEqualToSize(_dotShadowOffset, dotShadowOffset)) + { + _dotShadowOffset = dotShadowOffset; + [self setNeedsDisplay]; + } +} + +- (void)setSelectedDotImage:(UIImage *)dotImage +{ + if (_selectedDotImage != dotImage) + { + _selectedDotImage = dotImage; + [self setNeedsDisplay]; + } +} + +- (void)setSelectedDotColor:(UIColor *)dotColor +{ + if (_selectedDotColor != dotColor) + { + _selectedDotColor = dotColor; + [self setNeedsDisplay]; + } +} + +- (void)setSelectedDotShape:(CGPathRef)dotShape +{ + if (_selectedDotShape != dotShape) + { + if (_selectedDotShape > LAST_SHAPE) CGPathRelease(_selectedDotShape); + _selectedDotShape = dotShape; + if (_selectedDotShape > LAST_SHAPE) CGPathRetain(_selectedDotShape); + [self setNeedsDisplay]; + } +} + +- (void)setSelectedDotSize:(CGFloat)dotSize +{ + if (ABS(_selectedDotSize - dotSize) > 0.001) + { + _selectedDotSize = dotSize; + [self setNeedsDisplay]; + } +} + +- (void)setSelectedDotShadowColor:(UIColor *)dotColor +{ + if (_selectedDotShadowColor != dotColor) + { + _selectedDotShadowColor = dotColor; + [self setNeedsDisplay]; + } +} + +- (void)setSelectedDotShadowBlur:(CGFloat)dotShadowBlur +{ + if (ABS(_selectedDotShadowBlur - dotShadowBlur) > 0.001) + { + _selectedDotShadowBlur = dotShadowBlur; + [self setNeedsDisplay]; + } +} + +- (void)setSelectedDotShadowOffset:(CGSize)dotShadowOffset +{ + if (!CGSizeEqualToSize(_selectedDotShadowOffset, dotShadowOffset)) + { + _selectedDotShadowOffset = dotShadowOffset; + [self setNeedsDisplay]; + } +} + +- (void)setDotSpacing:(CGFloat)dotSpacing +{ + if (ABS(_dotSpacing - dotSpacing) > 0.001) + { + _dotSpacing = dotSpacing; + [self setNeedsDisplay]; + } +} + +- (void)setDelegate:(id)delegate +{ + if (_delegate != delegate) + { + _delegate = delegate; + [self setNeedsDisplay]; + } +} + +- (void)setCurrentPage:(NSInteger)page +{ + _currentPage = [self clampedPageValue:page]; + [self setNeedsDisplay]; +} + +- (void)setNumberOfPages:(NSInteger)pages +{ + if (_numberOfPages != pages) + { + _numberOfPages = pages; + if (_currentPage >= pages) + { + _currentPage = pages - 1; + } + [self setNeedsDisplay]; + } +} + +- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event +{ + CGPoint point = [touch locationInView:self]; + BOOL forward = _vertical? (point.y > self.frame.size.height / 2): (point.x > self.frame.size.width / 2); + _currentPage = [self clampedPageValue:_currentPage + (forward? 1: -1)]; + if (!_defersCurrentPageDisplay) + { + [self setNeedsDisplay]; + } + [self sendActionsForControlEvents:UIControlEventValueChanged]; + [super endTrackingWithTouch:touch withEvent:event]; +} + +- (CGSize)sizeThatFits:(__unused CGSize)size +{ + CGSize dotSize = [self sizeForNumberOfPages:_numberOfPages]; + if (_selectedDotSize) + { + CGFloat width = (_selectedDotSize - _dotSize); + CGFloat height = MAX(36, MAX(_dotSize, _selectedDotSize)); + dotSize.width = _vertical? height: dotSize.width + width; + dotSize.height = _vertical? dotSize.height + width: height; + + } + if ((_dotShadowColor && ![_dotShadowColor isEqual:[UIColor clearColor]]) || + (_selectedDotShadowColor && ![_selectedDotShadowColor isEqual:[UIColor clearColor]])) + { + dotSize.width += MAX(_dotShadowOffset.width, _selectedDotShadowOffset.width) * 2; + dotSize.height += MAX(_dotShadowOffset.height, _selectedDotShadowOffset.height) * 2; + dotSize.width += MAX(_dotShadowBlur, _selectedDotShadowBlur) * 2; + dotSize.height += MAX(_dotShadowBlur, _selectedDotShadowBlur) * 2; + } + return dotSize; +} + +- (CGSize)intrinsicContentSize +{ + return [self sizeThatFits:self.bounds.size]; +} + +@end diff --git a/XLPagerTabStrip/XL/.DS_Store b/XLPagerTabStrip/XL/.DS_Store new file mode 100644 index 0000000..5f0b3b9 Binary files /dev/null and b/XLPagerTabStrip/XL/.DS_Store differ diff --git a/XLPagerTabStrip/XL/Controllers/XLPagerTabStripViewController.m b/XLPagerTabStrip/XL/Controllers/XLPagerTabStripViewController.m index d9c89d1..3816a6e 100644 --- a/XLPagerTabStrip/XL/Controllers/XLPagerTabStripViewController.m +++ b/XLPagerTabStrip/XL/Controllers/XLPagerTabStripViewController.m @@ -155,13 +155,15 @@ -(void)pagerTabStripViewController:(XLPagerTabStripViewController *)pagerTabStripViewController updateIndicatorToViewController:(UIViewController *)toViewController - fromViewController:(UIViewController *)fromViewController{ + fromViewController:(UIViewController *)fromViewController +{ } -(void)pagerTabStripViewController:(XLPagerTabStripViewController *)pagerTabStripViewController updateIndicatorFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex - withProgressPercentage:(CGFloat)progressPercentage{ + withProgressPercentage:(CGFloat)progressPercentage +{ } diff --git a/XLPagerTabStrip/XL/Controllers/XLTwitterPagerTabStripViewController.h b/XLPagerTabStrip/XL/Controllers/XLTwitterPagerTabStripViewController.h new file mode 100644 index 0000000..8409c2a --- /dev/null +++ b/XLPagerTabStrip/XL/Controllers/XLTwitterPagerTabStripViewController.h @@ -0,0 +1,15 @@ +// +// XLTwitterPagerTabStripViewController.h +// XLPagerTabStrip +// +// Created by Martin Pastorin on 2/12/15. +// Copyright (c) 2015 Xmartlabs. All rights reserved. +// + +#import "XLPagerTabStripViewController.h" + +@interface XLTwitterPagerTabStripViewController : XLPagerTabStripViewController + +@property (nonatomic, readonly) UIView * navigationView; + +@end diff --git a/XLPagerTabStrip/XL/Controllers/XLTwitterPagerTabStripViewController.m b/XLPagerTabStrip/XL/Controllers/XLTwitterPagerTabStripViewController.m new file mode 100644 index 0000000..b317ae4 --- /dev/null +++ b/XLPagerTabStrip/XL/Controllers/XLTwitterPagerTabStripViewController.m @@ -0,0 +1,224 @@ +// +// XLTwitterPagerTabStripViewController.m +// XLPagerTabStrip +// +// Created by Martin Pastorin on 2/12/15. +// Copyright (c) 2015 Xmartlabs. All rights reserved. +// + +#import "XLTwitterPagerTabStripViewController.h" +#import "TableChildExampleViewController.h" +#import "ChildExampleViewController.h" +#import "FXPageControl.h" + +@interface XLTwitterPagerTabStripViewController () +{ + BOOL _isReload; +} +@property (nonatomic) IBOutlet UIView * navigationView; +@property (nonatomic) UIScrollView * navigationScrollView; +@property (nonatomic) FXPageControl * navigationPageControl; +@property (nonatomic, strong) NSMutableArray * navigationItemsViews; + +@end + +@implementation XLTwitterPagerTabStripViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view. + if (!self.navigationView.superview) { + [self.navigationController.navigationBar addSubview:self.navigationView]; + } + if (!self.navigationScrollView.superview) { + [self.navigationView addSubview:self.navigationScrollView]; + } + + if (!self.navigationPageControl.superview) { + [self.navigationView addSubview:self.navigationPageControl]; + } + + self.isProgressiveIndicator = YES; + + _navigationScrollView.bounces = YES; + _navigationScrollView.scrollsToTop = NO; + _navigationScrollView.delegate = self; + _navigationScrollView.showsVerticalScrollIndicator = NO; + _navigationScrollView.showsHorizontalScrollIndicator = NO; + _navigationScrollView.pagingEnabled = YES; + _navigationScrollView.userInteractionEnabled = NO; + [_navigationScrollView setAlwaysBounceHorizontal:YES]; + [_navigationScrollView setAlwaysBounceVertical:NO]; + + [self reloadNavigatorContainerView]; +} + +-(void)reloadNavigatorContainerView +{ + __block NSMutableArray *items = [[NSMutableArray alloc] init]; + [self.pagerTabStripChildViewControllers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSAssert([obj conformsToProtocol:@protocol(XLPagerTabStripChildItem)], @"child view controller must conform to XLPagerTabStripChildItem"); + UIViewController * childViewController = (UIViewController *)obj; + if ([childViewController respondsToSelector:@selector(titleForPagerTabStripViewController:)]){ + UILabel *navTitleLabel = [self createNewLabelWithText:[childViewController titleForPagerTabStripViewController:self]]; + [navTitleLabel setAlpha: self.currentIndex == idx ? 1 : 0]; + [items addObject:navTitleLabel]; + } + }]; + + [items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if([obj isKindOfClass:UIView.class]) + [self addNavigationViewItem:obj index:idx]; + }]; + + // Update Navigation Page Control + [self.navigationPageControl setNumberOfPages:[self.navigationItemsViews count]]; + [self.navigationPageControl setCurrentPage:self.currentIndex]; + CGSize viewSize = [self.navigationPageControl sizeForNumberOfPages:[self.navigationItemsViews count]]; + CGFloat distance = CGRectGetWidth(self.navigationScrollView.frame) / 2; + CGFloat originX = (distance - viewSize.width/2); + [self.navigationPageControl setFrame:(CGRect){originX, 34, viewSize.width, viewSize.height}]; +} + +-(UIView *)navigationView +{ + if (_navigationView) return _navigationView; + _navigationView = [[UIView alloc] init]; + _navigationView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + return _navigationView; +} + +- (UIScrollView *)navigationScrollView +{ + if (_navigationScrollView) return _navigationScrollView; + _navigationScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 44)]; + _navigationScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + return _navigationScrollView; +} + +-(NSMutableArray *)navigationItemsViews +{ + if (_navigationItemsViews) return _navigationItemsViews; + _navigationItemsViews = [[NSMutableArray alloc] init]; + return _navigationItemsViews; +} + +-(FXPageControl *)navigationPageControl +{ + if (_navigationPageControl) return _navigationPageControl; + _navigationPageControl = [[FXPageControl alloc] init]; + [_navigationPageControl setBackgroundColor:[UIColor clearColor]]; + [_navigationPageControl setDotSize:3.8f]; + [_navigationPageControl setDotSpacing:4.0f]; + [_navigationPageControl setDotColor:[UIColor colorWithWhite:1 alpha:0.4]]; + [_navigationPageControl setSelectedDotColor:[UIColor whiteColor]]; + return _navigationPageControl; +} + + +#pragma mark - XLPagerTabStripViewControllerDataSource + +-(void)pagerTabStripViewController:(XLPagerTabStripViewController *)pagerTabStripViewController + updateIndicatorFromIndex:(NSInteger)fromIndex + toIndex:(NSInteger)toIndex + withProgressPercentage:(CGFloat)progressPercentage +{ + CGFloat distance = CGRectGetWidth(self.navigationScrollView.frame) / 2; + UIAccelerationValue xOffset = fromIndex < toIndex ? distance * fromIndex + distance * progressPercentage : distance * fromIndex - distance * progressPercentage; + [self.navigationScrollView setContentOffset:CGPointMake(xOffset, 0)]; + + [self setAlphaToItemAtIndex:fromIndex withOffset:xOffset]; + [self setAlphaToItemAtIndex:toIndex withOffset:xOffset]; + + [_navigationPageControl setCurrentPage:self.currentIndex]; +} + + +#pragma mark - Helpers + +- (void)addNavigationViewItem:(UIView*)view index:(NSInteger)index +{ + CGFloat distance = CGRectGetWidth(self.navigationScrollView.frame) / 2; + CGSize viewSize = [view isKindOfClass:[UILabel class]] ? [self getLabelSize:(UILabel*)view] : view.frame.size; + CGFloat originX = (distance - viewSize.width/2) + self.navigationItemsViews.count * distance; + view.frame = (CGRect){originX, 8, viewSize.width, viewSize.height}; + view.tag = index; + + [_navigationScrollView addSubview:view]; + [_navigationItemsViews addObject:view]; +} + +-(CGSize) getLabelSize:(UILabel *)label +{ + return [[label text] sizeWithAttributes:@{NSFontAttributeName:[label font]}];; +} + +-(UILabel *)createNewLabelWithText:(NSString *)text +{ + UILabel *navTitleLabel = [UILabel new]; + navTitleLabel.text = text; + navTitleLabel.font = [UIFont fontWithName:@"Helvetica" size:18]; + navTitleLabel.textColor = [UIColor whiteColor]; + return navTitleLabel; +} + +-(void)setAlphaToItemAtIndex:(NSInteger)index withOffset:(UIAccelerationValue)xOffset +{ + if (index<0 || index>=[self.navigationItemsViews count]) { + return; + } + + CGFloat distance = CGRectGetWidth(self.navigationScrollView.frame) / 2; + CGFloat alpha; + + if(xOffset < distance * index) { + alpha = (xOffset - distance * (index - 1)) / distance; + }else{ + alpha = 1 - ((xOffset - distance * index) / distance); + } + + UILabel *label = (UILabel*)[self.navigationItemsViews objectAtIndex:index]; + [label setAlpha:alpha]; +} + + +#pragma mark - XLPagerTabStripViewControllerDataSource + +-(NSArray *)childViewControllersForPagerTabStripViewController:(XLPagerTabStripViewController *)pagerTabStripViewController +{ + // create child view controllers that will be managed by XLPagerTabStripViewController + TableChildExampleViewController * child_1 = [[TableChildExampleViewController alloc] initWithStyle:UITableViewStylePlain]; + ChildExampleViewController * child_2 = [[ChildExampleViewController alloc] init]; + TableChildExampleViewController * child_3 = [[TableChildExampleViewController alloc] initWithStyle:UITableViewStyleGrouped]; + ChildExampleViewController * child_4 = [[ChildExampleViewController alloc] init]; + TableChildExampleViewController * child_5 = [[TableChildExampleViewController alloc] initWithStyle:UITableViewStylePlain]; + ChildExampleViewController * child_6 = [[ChildExampleViewController alloc] init]; + TableChildExampleViewController * child_7 = [[TableChildExampleViewController alloc] initWithStyle:UITableViewStyleGrouped]; + ChildExampleViewController * child_8 = [[ChildExampleViewController alloc] init]; + if (!_isReload){ + return @[child_1, child_2, child_3, child_4, child_5, child_6, child_7, child_8]; + } + + NSMutableArray * childViewControllers = [NSMutableArray arrayWithObjects:child_1, child_2, child_3, child_4, child_5, child_6, child_7, child_8, nil]; + NSUInteger count = [childViewControllers count]; + for (NSUInteger i = 0; i < count; ++i) { + // Select a random element between i and end of array to swap with. + NSUInteger nElements = count - i; + NSUInteger n = (arc4random() % nElements) + i; + [childViewControllers exchangeObjectAtIndex:i withObjectAtIndex:n]; + } + NSUInteger nItems = 1 + (rand() % 8); + return [childViewControllers subarrayWithRange:NSMakeRange(0, nItems)]; +} + +-(void)reloadPagerTabStripView +{ + _isReload = YES; + self.isProgressiveIndicator = (rand() % 2 == 0); + self.isElasticIndicatorLimit = (rand() % 2 == 0); + [super reloadPagerTabStripView]; +} + + +@end