├── .gitignore ├── ECStretchableHeaderView.h ├── ECStretchableHeaderView.m ├── ECStretchableHeaderView.podspec ├── ECStretchableHeaderViewExample ├── ECStretchableHeaderViewExample.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── ECStretchableHeaderViewExample.xccheckout │ │ └── xcuserdata │ │ │ └── eric.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── eric.xcuserdatad │ │ └── xcschemes │ │ ├── ECStretchableHeaderViewExample.xcscheme │ │ └── xcschememanagement.plist ├── ECStretchableHeaderViewExample.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── ECStretchableHeaderViewExample.xccheckout │ └── xcuserdata │ │ └── eric.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── ECStretchableHeaderViewExample │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── ECStretchableHeaderViewExampleTests │ ├── ECStretchableHeaderViewExampleTests.m │ └── Info.plist └── Podfile ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ECStretchableHeaderViewExample/Podfile.lock 3 | 4 | ECStretchableHeaderViewExample/Pods 5 | -------------------------------------------------------------------------------- /ECStretchableHeaderView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECStretchableHeaderView.h 3 | // StretchableHeaderViewExample 4 | // 5 | // Created by Eric Castro on 30/07/14. 6 | // Copyright (c) 2014 cast.ro. All rights reserved. 7 | // 8 | 9 | #import 10 | @protocol ECStretchableHeaderViewDelegate; 11 | 12 | @interface ECStretchableHeaderView : UIView 13 | 14 | @property (assign) CGFloat maxHeight; 15 | @property (assign) CGFloat minHeight; 16 | @property (assign) CGFloat minOffset; 17 | @property (assign) BOOL compensateBottomScrollingArea; 18 | @property (assign) BOOL resizingEnabled; 19 | 20 | @property (strong) NSLayoutConstraint *heightConstraint; 21 | 22 | @property (assign) BOOL tapToExpand; 23 | 24 | @property(nonatomic, strong) UIScrollView *attachedScrollView; 25 | 26 | - (void)attachToScrollView:(UIScrollView *)scrollView inset:(CGFloat)inset; 27 | 28 | - (void)attachToScrollView:(UIScrollView *)scrollView parentView:(UIView *)parentView inset:(CGFloat)inset; 29 | 30 | @end 31 | 32 | @protocol ECStretchableHeaderViewDelegate 33 | 34 | 35 | @end -------------------------------------------------------------------------------- /ECStretchableHeaderView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECStretchableHeaderView.m 3 | // StretchableHeaderViewExample 4 | // 5 | // Created by Eric Castro on 30/07/14. 6 | // Copyright (c) 2014 cast.ro. All rights reserved. 7 | // 8 | #import 9 | #import 10 | 11 | #import "ECStretchableHeaderView.h" 12 | 13 | @implementation ECStretchableHeaderView 14 | { 15 | UIPanGestureRecognizer *_panGestureRecognizer; 16 | UITapGestureRecognizer *_tapGestureRecognizer; 17 | 18 | CGPoint _lastPanLocation; 19 | 20 | BOOL _touchesStartedOnSelf; 21 | 22 | CGFloat _inset; 23 | 24 | HTDelegateProxy *_delegateProxy; 25 | id _originalScrollViewDelegate; 26 | } 27 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 28 | { 29 | self = [super initWithCoder:aDecoder]; 30 | if (self) { 31 | [self _setupView]; 32 | } 33 | return self; 34 | } 35 | - (instancetype)initWithFrame:(CGRect)frame 36 | { 37 | self = [super initWithFrame:frame]; 38 | if (self) { 39 | [self _setupView]; 40 | } 41 | return self; 42 | } 43 | 44 | - (void)_setupView 45 | { 46 | _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didPan:)]; 47 | [self addGestureRecognizer:_panGestureRecognizer]; 48 | _panGestureRecognizer.delegate = self; 49 | 50 | _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap:)]; 51 | [self addGestureRecognizer:_tapGestureRecognizer]; 52 | _tapGestureRecognizer.delegate = self; 53 | 54 | self.clipsToBounds = YES; 55 | self.translatesAutoresizingMaskIntoConstraints = NO; 56 | 57 | _minHeight = 0.0; 58 | _maxHeight = CGRectGetHeight(self.frame); 59 | _touchesStartedOnSelf = NO; 60 | _tapToExpand = NO; 61 | _compensateBottomScrollingArea = NO; 62 | _resizingEnabled = YES; 63 | } 64 | 65 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 66 | { 67 | return NO; 68 | } 69 | 70 | - (void)didTap:(id)sender 71 | { 72 | CGPoint newOffset = self.attachedScrollView.contentOffset; 73 | newOffset.y -= self.maxHeight - CGRectGetHeight(self.frame); 74 | [UIView animateWithDuration:0.2f delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{ 75 | [self.attachedScrollView setContentOffset:newOffset animated:YES]; 76 | } completion:nil]; 77 | } 78 | - (void)didPan:(id)sender 79 | { 80 | CGPoint currentLocation = [_panGestureRecognizer locationInView:self]; 81 | 82 | if (_panGestureRecognizer.state == UIGestureRecognizerStateBegan) 83 | { 84 | _lastPanLocation = currentLocation; 85 | [self.attachedScrollView pop_removeAllAnimations]; 86 | [self.attachedScrollView setContentOffset:self.attachedScrollView.contentOffset animated:NO]; 87 | } 88 | 89 | if (_panGestureRecognizer.state == UIGestureRecognizerStateChanged) 90 | { 91 | CGFloat heightDiff = currentLocation.y - _lastPanLocation.y; 92 | 93 | if (self.attachedScrollView.contentOffset.y <= -self.attachedScrollView.contentInset.top) 94 | { 95 | heightDiff = heightDiff/3; 96 | } 97 | self.attachedScrollView.contentOffset = CGPointMake(self.attachedScrollView.contentOffset.x, self.attachedScrollView.contentOffset.y - heightDiff); 98 | } 99 | 100 | if ( 101 | _panGestureRecognizer.state == UIGestureRecognizerStateEnded || 102 | _panGestureRecognizer.state == UIGestureRecognizerStateCancelled|| 103 | _panGestureRecognizer.state == UIGestureRecognizerStateFailed) 104 | { 105 | if (self.attachedScrollView.contentOffset.y <= -self.attachedScrollView.contentInset.top) 106 | { 107 | _touchesStartedOnSelf = YES; 108 | [self _performBounceBackToTopAnimation]; 109 | } 110 | else 111 | { 112 | _touchesStartedOnSelf = YES; 113 | CGPoint velocity = [_panGestureRecognizer velocityInView:self]; 114 | 115 | if (self.attachedScrollView.bounds.size.width >= self.attachedScrollView.contentSize.width) velocity.x = 0; 116 | //if (self.attachedScrollView.bounds.size.height >= self.attachedScrollView.contentSize.height) velocity.y = 0; 117 | 118 | velocity.x = -velocity.x; 119 | velocity.y = -velocity.y; 120 | 121 | [self _performDecelerateAnimationWithVelocity:velocity completionBlock:^{ 122 | _touchesStartedOnSelf = NO; 123 | }]; 124 | } 125 | } 126 | 127 | _lastPanLocation = currentLocation; 128 | } 129 | 130 | - (void)_performDecelerateAnimationWithVelocity:(CGPoint)velocity completionBlock:(void (^)())completionBlock 131 | { 132 | POPDecayAnimation *decayAnimation = [POPDecayAnimation animation]; 133 | 134 | POPAnimatableProperty *prop = [POPAnimatableProperty propertyWithName:@"com.rounak.boundsY" initializer:^(POPMutableAnimatableProperty *prop) { 135 | // read value, feed data to Pop 136 | prop.readBlock = ^(id obj, CGFloat values[]) { 137 | values[0] = [obj bounds].origin.x; 138 | values[1] = [obj bounds].origin.y; 139 | }; 140 | // write value, get data from Pop, and apply it to the view 141 | prop.writeBlock = ^(id obj, const CGFloat values[]) { 142 | 143 | CGRect tempBounds = [obj bounds]; 144 | tempBounds.origin.x = values[0]; 145 | CGFloat topBoundCheck = values[1] + CGRectGetHeight(self.frame) + _inset; 146 | CGFloat velocityThreshold = ((NSValue *)decayAnimation.velocity).CGPointValue.y / 10.0f * 0.2f; 147 | 148 | if (velocityThreshold < 0 && topBoundCheck < velocityThreshold && values[1] < self.maxHeight) 149 | { 150 | [self.attachedScrollView pop_removeAllAnimations]; 151 | _touchesStartedOnSelf = YES; 152 | tempBounds.origin.y = - CGRectGetHeight(self.frame) - _inset + topBoundCheck; 153 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (0.001 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 154 | [self _performBounceBackToTopAnimation]; 155 | }); 156 | } 157 | else if (tempBounds.origin.y > _attachedScrollView.contentSize.height - _attachedScrollView.frame.size.height + _attachedScrollView.contentInset.bottom + velocityThreshold) 158 | { 159 | [self.attachedScrollView pop_removeAllAnimations]; 160 | _touchesStartedOnSelf = YES; 161 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (0.001 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 162 | [self _performBounceBackToBottomAnimation]; 163 | }); 164 | } 165 | else 166 | tempBounds.origin.y = values[1]; 167 | 168 | [self _scrollView:_attachedScrollView offsetChanged:@{@"new":[NSValue valueWithCGSize:CGSizeMake(0.0f, values[1])], @"old":[NSValue valueWithCGSize:CGSizeMake(0.0f, values[1])]}]; 169 | [obj setBounds:tempBounds]; 170 | }; 171 | // dynamics threshold 172 | prop.threshold = 0.01; 173 | 174 | }]; 175 | 176 | decayAnimation.property = prop; 177 | decayAnimation.velocity = [NSValue valueWithCGPoint:velocity]; 178 | decayAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) { if (completionBlock) completionBlock(); }; 179 | [self.attachedScrollView pop_addAnimation:decayAnimation forKey:@"decelerate"]; 180 | } 181 | - (POPBasicAnimation *)_bounceBackAnimation 182 | { 183 | POPBasicAnimation *basicAnimation = [POPBasicAnimation animation]; 184 | POPAnimatableProperty *prop = [POPAnimatableProperty propertyWithName:@"com.rounak.boundsY" initializer:^(POPMutableAnimatableProperty *prop) { 185 | prop.readBlock = ^(id obj, CGFloat values[]) { 186 | values[0] = [obj bounds].origin.x; 187 | values[1] = [obj bounds].origin.y; 188 | }; 189 | prop.writeBlock = ^(id obj, const CGFloat values[]) { 190 | CGRect tempBounds = [obj bounds]; 191 | tempBounds.origin.x = values[0]; 192 | tempBounds.origin.y = values[1]; 193 | [obj setBounds:tempBounds]; 194 | }; 195 | // dynamics threshold 196 | prop.threshold = 0.01; 197 | }]; 198 | basicAnimation.property = prop; 199 | basicAnimation.duration = 0.3f; 200 | basicAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) { 201 | _touchesStartedOnSelf = NO; 202 | }; 203 | return basicAnimation; 204 | 205 | } 206 | - (void)_performBounceBackToTopAnimation 207 | { 208 | POPBasicAnimation *basicAnimation = [self _bounceBackAnimation]; 209 | basicAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(self.attachedScrollView.contentOffset.x, - CGRectGetHeight(self.frame) - _inset)]; 210 | [self.attachedScrollView pop_addAnimation:basicAnimation forKey:@"bounceBack"]; 211 | } 212 | 213 | - (void)_performBounceBackToBottomAnimation 214 | { 215 | POPBasicAnimation *basicAnimation = [self _bounceBackAnimation]; 216 | 217 | if (self.attachedScrollView.contentSize.height < self.attachedScrollView.frame.size.height) //fixes weird jump bug 218 | { 219 | basicAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(self.attachedScrollView.contentOffset.x, 0.0f)]; 220 | } 221 | else 222 | { 223 | basicAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(self.attachedScrollView.contentOffset.x,self.attachedScrollView.contentSize.height - self.attachedScrollView.bounds.size.height)]; 224 | } 225 | 226 | [self.attachedScrollView pop_addAnimation:basicAnimation forKey:@"bounceBack"]; 227 | } 228 | - (BOOL)changeHeightBy:(CGFloat)heightDiff 229 | { 230 | CGRect frame = self.frame; 231 | 232 | if (frame.size.height + heightDiff > self.maxHeight) 233 | frame.size.height = self.maxHeight; 234 | 235 | else if (frame.size.height + heightDiff < self.minHeight) 236 | frame.size.height = self.minHeight; 237 | 238 | else 239 | frame.size.height += heightDiff; 240 | 241 | if (self.heightConstraint) 242 | { 243 | self.heightConstraint.constant = frame.size.height; 244 | } 245 | else 246 | { 247 | self.frame = frame; 248 | } 249 | 250 | 251 | return YES; 252 | } 253 | 254 | - (void)attachToScrollView:(UIScrollView *)scrollView inset:(CGFloat)inset 255 | { 256 | [self attachToScrollView:scrollView parentView:scrollView.superview inset:inset]; 257 | } 258 | - (void)attachToScrollView:(UIScrollView *)scrollView parentView:(UIView *)parentView inset:(CGFloat)inset 259 | { 260 | _inset = inset; 261 | 262 | CGRect frame = self.frame; 263 | frame.origin.x = parentView.frame.origin.x; 264 | frame.origin.y = parentView.frame.origin.y + inset; 265 | frame.size.width = CGRectGetWidth(parentView.frame); 266 | self.frame = frame; 267 | 268 | [parentView addSubview:self]; 269 | 270 | self.attachedScrollView = scrollView; 271 | 272 | } 273 | 274 | - (void)setAttachedScrollView:(UIScrollView *)attachedScrollView 275 | { 276 | if (_attachedScrollView) 277 | { 278 | _attachedScrollView.delegate = _originalScrollViewDelegate==[NSNull null] ? nil : _originalScrollViewDelegate; 279 | [_attachedScrollView removeObserver:self forKeyPath:@"contentOffset"]; 280 | } 281 | _attachedScrollView = attachedScrollView; 282 | _originalScrollViewDelegate = _attachedScrollView.delegate ? _attachedScrollView.delegate : [NSNull null]; 283 | _delegateProxy = [[HTDelegateProxy alloc] initWithDelegates:@[_originalScrollViewDelegate, self]]; 284 | 285 | _attachedScrollView.delegate = (id)_delegateProxy; 286 | 287 | UIEdgeInsets contentInset = attachedScrollView.contentInset; 288 | contentInset.top = self.maxHeight; 289 | attachedScrollView.contentInset = contentInset; 290 | attachedScrollView.scrollIndicatorInsets = contentInset; 291 | attachedScrollView.contentOffset = CGPointMake(attachedScrollView.contentOffset.x, -CGRectGetHeight(self.frame)); 292 | [attachedScrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:NULL]; 293 | [attachedScrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:NULL]; 294 | [self _scrollView:attachedScrollView sizeChanged:@{@"new":[NSValue valueWithCGSize:attachedScrollView.contentSize]}]; 295 | 296 | _minOffset = 0.0f; 297 | } 298 | 299 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 300 | { 301 | UIScrollView *scrollView = object; 302 | 303 | if ([keyPath isEqualToString:@"contentOffset"]) 304 | { 305 | [self _scrollView:scrollView offsetChanged:change]; 306 | } 307 | 308 | if ([keyPath isEqualToString:@"contentSize"]) 309 | { 310 | [self _scrollView:scrollView sizeChanged:change]; 311 | } 312 | } 313 | 314 | - (void)_scrollView:(UIScrollView *)scrollView offsetChanged:(NSDictionary *)change 315 | { 316 | if (!self.resizingEnabled) return; 317 | 318 | NSValue *oldValue = [change valueForKey:@"old"]; 319 | NSValue *newValue = [change valueForKey:@"new"]; 320 | 321 | CGFloat oldYOffset = oldValue.CGPointValue.y; 322 | CGFloat newYOffset = newValue.CGPointValue.y; 323 | CGFloat offsetDiff = oldYOffset-newYOffset; 324 | 325 | CGRect frame = self.frame; 326 | frame.origin.y = newYOffset + _inset; 327 | //self.frame = frame; 328 | 329 | if (newYOffset > scrollView.contentSize.height - scrollView.frame.size.height + scrollView.contentInset.bottom) 330 | { 331 | //bouncing at the bottom; do nothing 332 | } 333 | 334 | CGFloat relativePosition = newYOffset + self.maxHeight - self.minOffset; 335 | CGFloat heightCheck = self.maxHeight - relativePosition; 336 | 337 | if (relativePosition >= 0.0f) 338 | { 339 | if (heightCheck < self.minHeight) 340 | self.heightConstraint.constant = self.minHeight; 341 | else 342 | self.heightConstraint.constant = self.maxHeight - relativePosition; 343 | } 344 | else 345 | self.heightConstraint.constant = self.maxHeight; 346 | 347 | 348 | } 349 | 350 | - (void)_scrollView:(UIScrollView *)scrollView sizeChanged:(NSDictionary *)change 351 | { 352 | if (!self.resizingEnabled) return; 353 | 354 | NSValue *newValue = [change valueForKey:@"new"]; 355 | 356 | UIEdgeInsets contentInset = scrollView.contentInset; 357 | 358 | if (scrollView.contentSize.height < scrollView.frame.size.height) 359 | { 360 | contentInset.bottom = (scrollView.frame.size.height - newValue.CGSizeValue.height) ; 361 | } 362 | else 363 | { 364 | contentInset.bottom = (_compensateBottomScrollingArea ? self.maxHeight : 0.0f); 365 | } 366 | 367 | scrollView.contentInset = contentInset; 368 | 369 | } 370 | 371 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView 372 | { 373 | [self.attachedScrollView pop_removeAllAnimations]; 374 | } 375 | - (void)dealloc 376 | { 377 | [self.attachedScrollView removeObserver:self forKeyPath:@"contentSize"]; 378 | [self.attachedScrollView removeObserver:self forKeyPath:@"contentOffset"]; 379 | } 380 | 381 | @end 382 | -------------------------------------------------------------------------------- /ECStretchableHeaderView.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | 4 | s.name = "ECStretchableHeaderView" 5 | s.version = "1.0.3" 6 | s.summary = "A header view that attaches on top of a UIScrollView and reacts to scrolling gestures to expand or contract itself." 7 | s.homepage = "https://github.com/ericcastro/ECStretchableHeaderView" 8 | s.license = { :type => "MIT", :file => "LICENSE.md" } 9 | s.author = { "Eric Castro" => "eric@cast.ro" } 10 | s.social_media_url = "http://twitter.com/_eric_castro" 11 | s.platform = :ios 12 | s.source = { :git => "https://github.com/ericcastro/ECStretchableHeaderView.git", :tag => "v#{s.version}" } 13 | s.source_files = "ECStretchableHeaderView.{h,m}" 14 | s.requires_arc = true 15 | s.dependency 'pop' 16 | s.dependency 'HTDelegateProxy' 17 | s.ios.deployment_target = '6.0' 18 | 19 | end 20 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | archiveVersion 6 | 1 7 | classes 8 | 9 | objectVersion 10 | 46 11 | objects 12 | 13 | 07115A3F1AB4E10A00A25EB8 14 | 15 | children 16 | 17 | 07115A4A1AB4E10A00A25EB8 18 | 07115A641AB4E10A00A25EB8 19 | 07115A491AB4E10A00A25EB8 20 | 59E4FED27F9EFB404A958132 21 | ED05BAB4E568A0893596B497 22 | 23 | isa 24 | PBXGroup 25 | sourceTree 26 | <group> 27 | 28 | 07115A401AB4E10A00A25EB8 29 | 30 | attributes 31 | 32 | LastUpgradeCheck 33 | 0620 34 | ORGANIZATIONNAME 35 | Eric Castro 36 | TargetAttributes 37 | 38 | 07115A471AB4E10A00A25EB8 39 | 40 | CreatedOnToolsVersion 41 | 6.2 42 | 43 | 07115A601AB4E10A00A25EB8 44 | 45 | CreatedOnToolsVersion 46 | 6.2 47 | TestTargetID 48 | 07115A471AB4E10A00A25EB8 49 | 50 | 51 | 52 | buildConfigurationList 53 | 07115A431AB4E10A00A25EB8 54 | compatibilityVersion 55 | Xcode 3.2 56 | developmentRegion 57 | English 58 | hasScannedForEncodings 59 | 0 60 | isa 61 | PBXProject 62 | knownRegions 63 | 64 | en 65 | Base 66 | 67 | mainGroup 68 | 07115A3F1AB4E10A00A25EB8 69 | productRefGroup 70 | 07115A491AB4E10A00A25EB8 71 | projectDirPath 72 | 73 | projectReferences 74 | 75 | projectRoot 76 | 77 | targets 78 | 79 | 07115A471AB4E10A00A25EB8 80 | 07115A601AB4E10A00A25EB8 81 | 82 | 83 | 07115A431AB4E10A00A25EB8 84 | 85 | buildConfigurations 86 | 87 | 07115A691AB4E10A00A25EB8 88 | 07115A6A1AB4E10A00A25EB8 89 | 90 | defaultConfigurationIsVisible 91 | 0 92 | defaultConfigurationName 93 | Release 94 | isa 95 | XCConfigurationList 96 | 97 | 07115A441AB4E10A00A25EB8 98 | 99 | buildActionMask 100 | 2147483647 101 | files 102 | 103 | 07115A791AB4E39700A25EB8 104 | 07115A511AB4E10A00A25EB8 105 | 07115A4E1AB4E10A00A25EB8 106 | 107 | isa 108 | PBXSourcesBuildPhase 109 | runOnlyForDeploymentPostprocessing 110 | 0 111 | 112 | 07115A451AB4E10A00A25EB8 113 | 114 | buildActionMask 115 | 2147483647 116 | files 117 | 118 | 3EEA326F8B7FC2DADC7AA39C 119 | 120 | isa 121 | PBXFrameworksBuildPhase 122 | runOnlyForDeploymentPostprocessing 123 | 0 124 | 125 | 07115A461AB4E10A00A25EB8 126 | 127 | buildActionMask 128 | 2147483647 129 | files 130 | 131 | 07115A571AB4E10A00A25EB8 132 | 07115A5C1AB4E10A00A25EB8 133 | 07115A591AB4E10A00A25EB8 134 | 135 | isa 136 | PBXResourcesBuildPhase 137 | runOnlyForDeploymentPostprocessing 138 | 0 139 | 140 | 07115A471AB4E10A00A25EB8 141 | 142 | buildConfigurationList 143 | 07115A6B1AB4E10A00A25EB8 144 | buildPhases 145 | 146 | E7E3F57097DFCEF2A4AEFA6F 147 | 07115A441AB4E10A00A25EB8 148 | 07115A451AB4E10A00A25EB8 149 | 07115A461AB4E10A00A25EB8 150 | A3C9AA899E984A20F4C8AF74 151 | 152 | buildRules 153 | 154 | dependencies 155 | 156 | isa 157 | PBXNativeTarget 158 | name 159 | ECStretchableHeaderViewExample 160 | productName 161 | ECStretchableHeaderViewExample 162 | productReference 163 | 07115A481AB4E10A00A25EB8 164 | productType 165 | com.apple.product-type.application 166 | 167 | 07115A481AB4E10A00A25EB8 168 | 169 | explicitFileType 170 | wrapper.application 171 | includeInIndex 172 | 0 173 | isa 174 | PBXFileReference 175 | path 176 | ECStretchableHeaderViewExample.app 177 | sourceTree 178 | BUILT_PRODUCTS_DIR 179 | 180 | 07115A491AB4E10A00A25EB8 181 | 182 | children 183 | 184 | 07115A481AB4E10A00A25EB8 185 | 07115A611AB4E10A00A25EB8 186 | 187 | isa 188 | PBXGroup 189 | name 190 | Products 191 | sourceTree 192 | <group> 193 | 194 | 07115A4A1AB4E10A00A25EB8 195 | 196 | children 197 | 198 | 07115A4F1AB4E10A00A25EB8 199 | 07115A501AB4E10A00A25EB8 200 | 07115A551AB4E10A00A25EB8 201 | 07115A581AB4E10A00A25EB8 202 | 07115A5A1AB4E10A00A25EB8 203 | 07115A4B1AB4E10A00A25EB8 204 | 07115A771AB4E39700A25EB8 205 | 07115A781AB4E39700A25EB8 206 | 207 | isa 208 | PBXGroup 209 | path 210 | ECStretchableHeaderViewExample 211 | sourceTree 212 | <group> 213 | 214 | 07115A4B1AB4E10A00A25EB8 215 | 216 | children 217 | 218 | 07115A4C1AB4E10A00A25EB8 219 | 07115A4D1AB4E10A00A25EB8 220 | 221 | isa 222 | PBXGroup 223 | name 224 | Supporting Files 225 | sourceTree 226 | <group> 227 | 228 | 07115A4C1AB4E10A00A25EB8 229 | 230 | isa 231 | PBXFileReference 232 | lastKnownFileType 233 | text.plist.xml 234 | path 235 | Info.plist 236 | sourceTree 237 | <group> 238 | 239 | 07115A4D1AB4E10A00A25EB8 240 | 241 | isa 242 | PBXFileReference 243 | lastKnownFileType 244 | sourcecode.c.objc 245 | path 246 | main.m 247 | sourceTree 248 | <group> 249 | 250 | 07115A4E1AB4E10A00A25EB8 251 | 252 | fileRef 253 | 07115A4D1AB4E10A00A25EB8 254 | isa 255 | PBXBuildFile 256 | 257 | 07115A4F1AB4E10A00A25EB8 258 | 259 | isa 260 | PBXFileReference 261 | lastKnownFileType 262 | sourcecode.c.h 263 | path 264 | AppDelegate.h 265 | sourceTree 266 | <group> 267 | 268 | 07115A501AB4E10A00A25EB8 269 | 270 | isa 271 | PBXFileReference 272 | lastKnownFileType 273 | sourcecode.c.objc 274 | path 275 | AppDelegate.m 276 | sourceTree 277 | <group> 278 | 279 | 07115A511AB4E10A00A25EB8 280 | 281 | fileRef 282 | 07115A501AB4E10A00A25EB8 283 | isa 284 | PBXBuildFile 285 | 286 | 07115A551AB4E10A00A25EB8 287 | 288 | children 289 | 290 | 07115A561AB4E10A00A25EB8 291 | 292 | isa 293 | PBXVariantGroup 294 | name 295 | Main.storyboard 296 | sourceTree 297 | <group> 298 | 299 | 07115A561AB4E10A00A25EB8 300 | 301 | isa 302 | PBXFileReference 303 | lastKnownFileType 304 | file.storyboard 305 | name 306 | Base 307 | path 308 | Base.lproj/Main.storyboard 309 | sourceTree 310 | <group> 311 | 312 | 07115A571AB4E10A00A25EB8 313 | 314 | fileRef 315 | 07115A551AB4E10A00A25EB8 316 | isa 317 | PBXBuildFile 318 | 319 | 07115A581AB4E10A00A25EB8 320 | 321 | isa 322 | PBXFileReference 323 | lastKnownFileType 324 | folder.assetcatalog 325 | path 326 | Images.xcassets 327 | sourceTree 328 | <group> 329 | 330 | 07115A591AB4E10A00A25EB8 331 | 332 | fileRef 333 | 07115A581AB4E10A00A25EB8 334 | isa 335 | PBXBuildFile 336 | 337 | 07115A5A1AB4E10A00A25EB8 338 | 339 | children 340 | 341 | 07115A5B1AB4E10A00A25EB8 342 | 343 | isa 344 | PBXVariantGroup 345 | name 346 | LaunchScreen.xib 347 | sourceTree 348 | <group> 349 | 350 | 07115A5B1AB4E10A00A25EB8 351 | 352 | isa 353 | PBXFileReference 354 | lastKnownFileType 355 | file.xib 356 | name 357 | Base 358 | path 359 | Base.lproj/LaunchScreen.xib 360 | sourceTree 361 | <group> 362 | 363 | 07115A5C1AB4E10A00A25EB8 364 | 365 | fileRef 366 | 07115A5A1AB4E10A00A25EB8 367 | isa 368 | PBXBuildFile 369 | 370 | 07115A5D1AB4E10A00A25EB8 371 | 372 | buildActionMask 373 | 2147483647 374 | files 375 | 376 | 07115A681AB4E10A00A25EB8 377 | 378 | isa 379 | PBXSourcesBuildPhase 380 | runOnlyForDeploymentPostprocessing 381 | 0 382 | 383 | 07115A5E1AB4E10A00A25EB8 384 | 385 | buildActionMask 386 | 2147483647 387 | files 388 | 389 | isa 390 | PBXFrameworksBuildPhase 391 | runOnlyForDeploymentPostprocessing 392 | 0 393 | 394 | 07115A5F1AB4E10A00A25EB8 395 | 396 | buildActionMask 397 | 2147483647 398 | files 399 | 400 | isa 401 | PBXResourcesBuildPhase 402 | runOnlyForDeploymentPostprocessing 403 | 0 404 | 405 | 07115A601AB4E10A00A25EB8 406 | 407 | buildConfigurationList 408 | 07115A6E1AB4E10A00A25EB8 409 | buildPhases 410 | 411 | 07115A5D1AB4E10A00A25EB8 412 | 07115A5E1AB4E10A00A25EB8 413 | 07115A5F1AB4E10A00A25EB8 414 | 415 | buildRules 416 | 417 | dependencies 418 | 419 | 07115A631AB4E10A00A25EB8 420 | 421 | isa 422 | PBXNativeTarget 423 | name 424 | ECStretchableHeaderViewExampleTests 425 | productName 426 | ECStretchableHeaderViewExampleTests 427 | productReference 428 | 07115A611AB4E10A00A25EB8 429 | productType 430 | com.apple.product-type.bundle.unit-test 431 | 432 | 07115A611AB4E10A00A25EB8 433 | 434 | explicitFileType 435 | wrapper.cfbundle 436 | includeInIndex 437 | 0 438 | isa 439 | PBXFileReference 440 | path 441 | ECStretchableHeaderViewExampleTests.xctest 442 | sourceTree 443 | BUILT_PRODUCTS_DIR 444 | 445 | 07115A621AB4E10A00A25EB8 446 | 447 | containerPortal 448 | 07115A401AB4E10A00A25EB8 449 | isa 450 | PBXContainerItemProxy 451 | proxyType 452 | 1 453 | remoteGlobalIDString 454 | 07115A471AB4E10A00A25EB8 455 | remoteInfo 456 | ECStretchableHeaderViewExample 457 | 458 | 07115A631AB4E10A00A25EB8 459 | 460 | isa 461 | PBXTargetDependency 462 | target 463 | 07115A471AB4E10A00A25EB8 464 | targetProxy 465 | 07115A621AB4E10A00A25EB8 466 | 467 | 07115A641AB4E10A00A25EB8 468 | 469 | children 470 | 471 | 07115A671AB4E10A00A25EB8 472 | 07115A651AB4E10A00A25EB8 473 | 474 | isa 475 | PBXGroup 476 | path 477 | ECStretchableHeaderViewExampleTests 478 | sourceTree 479 | <group> 480 | 481 | 07115A651AB4E10A00A25EB8 482 | 483 | children 484 | 485 | 07115A661AB4E10A00A25EB8 486 | 487 | isa 488 | PBXGroup 489 | name 490 | Supporting Files 491 | sourceTree 492 | <group> 493 | 494 | 07115A661AB4E10A00A25EB8 495 | 496 | isa 497 | PBXFileReference 498 | lastKnownFileType 499 | text.plist.xml 500 | path 501 | Info.plist 502 | sourceTree 503 | <group> 504 | 505 | 07115A671AB4E10A00A25EB8 506 | 507 | isa 508 | PBXFileReference 509 | lastKnownFileType 510 | sourcecode.c.objc 511 | path 512 | ECStretchableHeaderViewExampleTests.m 513 | sourceTree 514 | <group> 515 | 516 | 07115A681AB4E10A00A25EB8 517 | 518 | fileRef 519 | 07115A671AB4E10A00A25EB8 520 | isa 521 | PBXBuildFile 522 | 523 | 07115A691AB4E10A00A25EB8 524 | 525 | buildSettings 526 | 527 | ALWAYS_SEARCH_USER_PATHS 528 | NO 529 | CLANG_CXX_LANGUAGE_STANDARD 530 | gnu++0x 531 | CLANG_CXX_LIBRARY 532 | libc++ 533 | CLANG_ENABLE_MODULES 534 | YES 535 | CLANG_ENABLE_OBJC_ARC 536 | YES 537 | CLANG_WARN_BOOL_CONVERSION 538 | YES 539 | CLANG_WARN_CONSTANT_CONVERSION 540 | YES 541 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE 542 | YES_ERROR 543 | CLANG_WARN_EMPTY_BODY 544 | YES 545 | CLANG_WARN_ENUM_CONVERSION 546 | YES 547 | CLANG_WARN_INT_CONVERSION 548 | YES 549 | CLANG_WARN_OBJC_ROOT_CLASS 550 | YES_ERROR 551 | CLANG_WARN_UNREACHABLE_CODE 552 | YES 553 | CLANG_WARN__DUPLICATE_METHOD_MATCH 554 | YES 555 | CODE_SIGN_IDENTITY[sdk=iphoneos*] 556 | iPhone Developer 557 | COPY_PHASE_STRIP 558 | NO 559 | ENABLE_STRICT_OBJC_MSGSEND 560 | YES 561 | GCC_C_LANGUAGE_STANDARD 562 | gnu99 563 | GCC_DYNAMIC_NO_PIC 564 | NO 565 | GCC_OPTIMIZATION_LEVEL 566 | 0 567 | GCC_PREPROCESSOR_DEFINITIONS 568 | 569 | DEBUG=1 570 | $(inherited) 571 | 572 | GCC_SYMBOLS_PRIVATE_EXTERN 573 | NO 574 | GCC_WARN_64_TO_32_BIT_CONVERSION 575 | YES 576 | GCC_WARN_ABOUT_RETURN_TYPE 577 | YES_ERROR 578 | GCC_WARN_UNDECLARED_SELECTOR 579 | YES 580 | GCC_WARN_UNINITIALIZED_AUTOS 581 | YES_AGGRESSIVE 582 | GCC_WARN_UNUSED_FUNCTION 583 | YES 584 | GCC_WARN_UNUSED_VARIABLE 585 | YES 586 | IPHONEOS_DEPLOYMENT_TARGET 587 | 8.2 588 | MTL_ENABLE_DEBUG_INFO 589 | YES 590 | ONLY_ACTIVE_ARCH 591 | YES 592 | SDKROOT 593 | iphoneos 594 | TARGETED_DEVICE_FAMILY 595 | 1,2 596 | 597 | isa 598 | XCBuildConfiguration 599 | name 600 | Debug 601 | 602 | 07115A6A1AB4E10A00A25EB8 603 | 604 | buildSettings 605 | 606 | ALWAYS_SEARCH_USER_PATHS 607 | NO 608 | CLANG_CXX_LANGUAGE_STANDARD 609 | gnu++0x 610 | CLANG_CXX_LIBRARY 611 | libc++ 612 | CLANG_ENABLE_MODULES 613 | YES 614 | CLANG_ENABLE_OBJC_ARC 615 | YES 616 | CLANG_WARN_BOOL_CONVERSION 617 | YES 618 | CLANG_WARN_CONSTANT_CONVERSION 619 | YES 620 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE 621 | YES_ERROR 622 | CLANG_WARN_EMPTY_BODY 623 | YES 624 | CLANG_WARN_ENUM_CONVERSION 625 | YES 626 | CLANG_WARN_INT_CONVERSION 627 | YES 628 | CLANG_WARN_OBJC_ROOT_CLASS 629 | YES_ERROR 630 | CLANG_WARN_UNREACHABLE_CODE 631 | YES 632 | CLANG_WARN__DUPLICATE_METHOD_MATCH 633 | YES 634 | CODE_SIGN_IDENTITY[sdk=iphoneos*] 635 | iPhone Developer 636 | COPY_PHASE_STRIP 637 | NO 638 | ENABLE_NS_ASSERTIONS 639 | NO 640 | ENABLE_STRICT_OBJC_MSGSEND 641 | YES 642 | GCC_C_LANGUAGE_STANDARD 643 | gnu99 644 | GCC_WARN_64_TO_32_BIT_CONVERSION 645 | YES 646 | GCC_WARN_ABOUT_RETURN_TYPE 647 | YES_ERROR 648 | GCC_WARN_UNDECLARED_SELECTOR 649 | YES 650 | GCC_WARN_UNINITIALIZED_AUTOS 651 | YES_AGGRESSIVE 652 | GCC_WARN_UNUSED_FUNCTION 653 | YES 654 | GCC_WARN_UNUSED_VARIABLE 655 | YES 656 | IPHONEOS_DEPLOYMENT_TARGET 657 | 8.2 658 | MTL_ENABLE_DEBUG_INFO 659 | NO 660 | SDKROOT 661 | iphoneos 662 | TARGETED_DEVICE_FAMILY 663 | 1,2 664 | VALIDATE_PRODUCT 665 | YES 666 | 667 | isa 668 | XCBuildConfiguration 669 | name 670 | Release 671 | 672 | 07115A6B1AB4E10A00A25EB8 673 | 674 | buildConfigurations 675 | 676 | 07115A6C1AB4E10A00A25EB8 677 | 07115A6D1AB4E10A00A25EB8 678 | 679 | defaultConfigurationIsVisible 680 | 0 681 | isa 682 | XCConfigurationList 683 | 684 | 07115A6C1AB4E10A00A25EB8 685 | 686 | baseConfigurationReference 687 | 37983508342DE7EBF0570CFD 688 | buildSettings 689 | 690 | ASSETCATALOG_COMPILER_APPICON_NAME 691 | AppIcon 692 | INFOPLIST_FILE 693 | ECStretchableHeaderViewExample/Info.plist 694 | LD_RUNPATH_SEARCH_PATHS 695 | $(inherited) @executable_path/Frameworks 696 | PRODUCT_NAME 697 | $(TARGET_NAME) 698 | 699 | isa 700 | XCBuildConfiguration 701 | name 702 | Debug 703 | 704 | 07115A6D1AB4E10A00A25EB8 705 | 706 | baseConfigurationReference 707 | B993CAF2E3AEEB31DAB403B2 708 | buildSettings 709 | 710 | ASSETCATALOG_COMPILER_APPICON_NAME 711 | AppIcon 712 | INFOPLIST_FILE 713 | ECStretchableHeaderViewExample/Info.plist 714 | LD_RUNPATH_SEARCH_PATHS 715 | $(inherited) @executable_path/Frameworks 716 | PRODUCT_NAME 717 | $(TARGET_NAME) 718 | 719 | isa 720 | XCBuildConfiguration 721 | name 722 | Release 723 | 724 | 07115A6E1AB4E10A00A25EB8 725 | 726 | buildConfigurations 727 | 728 | 07115A6F1AB4E10A00A25EB8 729 | 07115A701AB4E10A00A25EB8 730 | 731 | defaultConfigurationIsVisible 732 | 0 733 | isa 734 | XCConfigurationList 735 | 736 | 07115A6F1AB4E10A00A25EB8 737 | 738 | buildSettings 739 | 740 | BUNDLE_LOADER 741 | $(TEST_HOST) 742 | FRAMEWORK_SEARCH_PATHS 743 | 744 | $(SDKROOT)/Developer/Library/Frameworks 745 | $(inherited) 746 | 747 | GCC_PREPROCESSOR_DEFINITIONS 748 | 749 | DEBUG=1 750 | $(inherited) 751 | 752 | INFOPLIST_FILE 753 | ECStretchableHeaderViewExampleTests/Info.plist 754 | LD_RUNPATH_SEARCH_PATHS 755 | $(inherited) @executable_path/Frameworks @loader_path/Frameworks 756 | PRODUCT_NAME 757 | $(TARGET_NAME) 758 | TEST_HOST 759 | $(BUILT_PRODUCTS_DIR)/ECStretchableHeaderViewExample.app/ECStretchableHeaderViewExample 760 | 761 | isa 762 | XCBuildConfiguration 763 | name 764 | Debug 765 | 766 | 07115A701AB4E10A00A25EB8 767 | 768 | buildSettings 769 | 770 | BUNDLE_LOADER 771 | $(TEST_HOST) 772 | FRAMEWORK_SEARCH_PATHS 773 | 774 | $(SDKROOT)/Developer/Library/Frameworks 775 | $(inherited) 776 | 777 | INFOPLIST_FILE 778 | ECStretchableHeaderViewExampleTests/Info.plist 779 | LD_RUNPATH_SEARCH_PATHS 780 | $(inherited) @executable_path/Frameworks @loader_path/Frameworks 781 | PRODUCT_NAME 782 | $(TARGET_NAME) 783 | TEST_HOST 784 | $(BUILT_PRODUCTS_DIR)/ECStretchableHeaderViewExample.app/ECStretchableHeaderViewExample 785 | 786 | isa 787 | XCBuildConfiguration 788 | name 789 | Release 790 | 791 | 07115A771AB4E39700A25EB8 792 | 793 | fileEncoding 794 | 4 795 | isa 796 | PBXFileReference 797 | lastKnownFileType 798 | sourcecode.c.h 799 | path 800 | ViewController.h 801 | sourceTree 802 | <group> 803 | 804 | 07115A781AB4E39700A25EB8 805 | 806 | fileEncoding 807 | 4 808 | isa 809 | PBXFileReference 810 | lastKnownFileType 811 | sourcecode.c.objc 812 | path 813 | ViewController.m 814 | sourceTree 815 | <group> 816 | 817 | 07115A791AB4E39700A25EB8 818 | 819 | fileRef 820 | 07115A781AB4E39700A25EB8 821 | isa 822 | PBXBuildFile 823 | 824 | 37983508342DE7EBF0570CFD 825 | 826 | includeInIndex 827 | 1 828 | isa 829 | PBXFileReference 830 | lastKnownFileType 831 | text.xcconfig 832 | name 833 | Pods.debug.xcconfig 834 | path 835 | Pods/Target Support Files/Pods/Pods.debug.xcconfig 836 | sourceTree 837 | <group> 838 | 839 | 3EEA326F8B7FC2DADC7AA39C 840 | 841 | fileRef 842 | C3B553D77354886DBD04B522 843 | isa 844 | PBXBuildFile 845 | 846 | 59E4FED27F9EFB404A958132 847 | 848 | children 849 | 850 | 37983508342DE7EBF0570CFD 851 | B993CAF2E3AEEB31DAB403B2 852 | 853 | isa 854 | PBXGroup 855 | name 856 | Pods 857 | sourceTree 858 | <group> 859 | 860 | A3C9AA899E984A20F4C8AF74 861 | 862 | buildActionMask 863 | 2147483647 864 | files 865 | 866 | inputPaths 867 | 868 | isa 869 | PBXShellScriptBuildPhase 870 | name 871 | Copy Pods Resources 872 | outputPaths 873 | 874 | runOnlyForDeploymentPostprocessing 875 | 0 876 | shellPath 877 | /bin/sh 878 | shellScript 879 | "${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh" 880 | 881 | showEnvVarsInLog 882 | 0 883 | 884 | B993CAF2E3AEEB31DAB403B2 885 | 886 | includeInIndex 887 | 1 888 | isa 889 | PBXFileReference 890 | lastKnownFileType 891 | text.xcconfig 892 | name 893 | Pods.release.xcconfig 894 | path 895 | Pods/Target Support Files/Pods/Pods.release.xcconfig 896 | sourceTree 897 | <group> 898 | 899 | C3B553D77354886DBD04B522 900 | 901 | explicitFileType 902 | archive.ar 903 | includeInIndex 904 | 0 905 | isa 906 | PBXFileReference 907 | path 908 | libPods.a 909 | sourceTree 910 | BUILT_PRODUCTS_DIR 911 | 912 | E7E3F57097DFCEF2A4AEFA6F 913 | 914 | buildActionMask 915 | 2147483647 916 | files 917 | 918 | inputPaths 919 | 920 | isa 921 | PBXShellScriptBuildPhase 922 | name 923 | Check Pods Manifest.lock 924 | outputPaths 925 | 926 | runOnlyForDeploymentPostprocessing 927 | 0 928 | shellPath 929 | /bin/sh 930 | shellScript 931 | diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null 932 | if [[ $? != 0 ]] ; then 933 | cat << EOM 934 | error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation. 935 | EOM 936 | exit 1 937 | fi 938 | 939 | showEnvVarsInLog 940 | 0 941 | 942 | ED05BAB4E568A0893596B497 943 | 944 | children 945 | 946 | C3B553D77354886DBD04B522 947 | 948 | isa 949 | PBXGroup 950 | name 951 | Frameworks 952 | sourceTree 953 | <group> 954 | 955 | 956 | rootObject 957 | 07115A401AB4E10A00A25EB8 958 | 959 | 960 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcodeproj/project.xcworkspace/xcshareddata/ECStretchableHeaderViewExample.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 4833E1E9-A846-4814-A8AD-C15656585B7F 9 | IDESourceControlProjectName 10 | ECStretchableHeaderViewExample 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | A9BFA83A52C2A0E934CA8B5AB99EB2C586BCD0E5 14 | https://github.com/ericcastro/ECStretchableHeaderView.git 15 | 16 | IDESourceControlProjectPath 17 | ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | A9BFA83A52C2A0E934CA8B5AB99EB2C586BCD0E5 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/ericcastro/ECStretchableHeaderView.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | A9BFA83A52C2A0E934CA8B5AB99EB2C586BCD0E5 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | A9BFA83A52C2A0E934CA8B5AB99EB2C586BCD0E5 36 | IDESourceControlWCCName 37 | ECStretchableHeaderView 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcodeproj/project.xcworkspace/xcuserdata/eric.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericcastro/ECStretchableHeaderView/86e3a293c5c6f58861d962088a9138d5a6ca3d0f/ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcodeproj/project.xcworkspace/xcuserdata/eric.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcodeproj/xcuserdata/eric.xcuserdatad/xcschemes/ECStretchableHeaderViewExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcodeproj/xcuserdata/eric.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ECStretchableHeaderViewExample.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 07115A471AB4E10A00A25EB8 16 | 17 | primary 18 | 19 | 20 | 07115A601AB4E10A00A25EB8 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcworkspace/xcshareddata/ECStretchableHeaderViewExample.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | FE1F1134-EB6B-4579-B3A2-0110B7338A81 9 | IDESourceControlProjectName 10 | ECStretchableHeaderViewExample 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | A9BFA83A52C2A0E934CA8B5AB99EB2C586BCD0E5 14 | https://github.com/ericcastro/ECStretchableHeaderView.git 15 | 16 | IDESourceControlProjectPath 17 | ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | A9BFA83A52C2A0E934CA8B5AB99EB2C586BCD0E5 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/ericcastro/ECStretchableHeaderView.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | A9BFA83A52C2A0E934CA8B5AB99EB2C586BCD0E5 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | A9BFA83A52C2A0E934CA8B5AB99EB2C586BCD0E5 36 | IDESourceControlWCCName 37 | ECStretchableHeaderView 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcworkspace/xcuserdata/eric.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericcastro/ECStretchableHeaderView/86e3a293c5c6f58861d962088a9138d5a6ca3d0f/ECStretchableHeaderViewExample/ECStretchableHeaderViewExample.xcworkspace/xcuserdata/eric.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ECStretchableHeaderViewExample 4 | // 5 | // Created by Eric Castro on 14/03/15. 6 | // Copyright (c) 2015 Eric Castro. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ECStretchableHeaderViewExample 4 | // 5 | // Created by Eric Castro on 14/03/15. 6 | // Copyright (c) 2015 Eric Castro. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // 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. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 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 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample/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 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 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 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample/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" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | ro.cast.eric.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ECStretchableHeaderViewExample 4 | // 5 | // Created by Eric Castro on 14/03/15. 6 | // Copyright (c) 2015 Eric Castro. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | @end 13 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ECStretchableHeaderViewExample 4 | // 5 | // Created by Eric Castro on 14/03/15. 6 | // Copyright (c) 2015 Eric Castro. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "ECStretchableHeaderView.h" 11 | 12 | @interface ViewController () 13 | 14 | @property (weak, nonatomic) IBOutlet ECStretchableHeaderView *headerView; 15 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 16 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *headerViewHeightConstraint; 17 | 18 | 19 | @end 20 | 21 | @implementation ViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | self.headerView.maxHeight = 320; 26 | self.headerView.minHeight = 100; 27 | self.headerView.layer.borderColor = [UIColor redColor].CGColor; 28 | self.headerView.layer.borderWidth = 3.0f; 29 | self.headerView.heightConstraint = self.headerViewHeightConstraint; 30 | [self.headerView attachToScrollView:self.tableView inset:100.0f]; 31 | } 32 | 33 | - (void)didReceiveMemoryWarning { 34 | [super didReceiveMemoryWarning]; 35 | // Dispose of any resources that can be recreated. 36 | } 37 | 38 | /* 39 | #pragma mark - Navigation 40 | 41 | // In a storyboard-based application, you will often want to do a little preparation before navigation 42 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 43 | // Get the new view controller using [segue destinationViewController]. 44 | // Pass the selected object to the new view controller. 45 | } 46 | */ 47 | 48 | #pragma mark UITableViewDataSource - 49 | 50 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 51 | { 52 | return 200; 53 | } 54 | 55 | // Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier: 56 | // Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls) 57 | 58 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 59 | { 60 | UITableViewCell *c = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"]; 61 | c.textLabel.text = [NSString stringWithFormat:@"Item %ld", indexPath.row]; 62 | return c; 63 | } 64 | 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ECStretchableHeaderViewExample 4 | // 5 | // Created by Eric Castro on 14/03/15. 6 | // Copyright (c) 2015 Eric Castro. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExampleTests/ECStretchableHeaderViewExampleTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECStretchableHeaderViewExampleTests.m 3 | // ECStretchableHeaderViewExampleTests 4 | // 5 | // Created by Eric Castro on 14/03/15. 6 | // Copyright (c) 2015 Eric Castro. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface ECStretchableHeaderViewExampleTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation ECStretchableHeaderViewExampleTests 17 | 18 | - (void)setUp { 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 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/ECStretchableHeaderViewExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | ro.cast.eric.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ECStretchableHeaderViewExample/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | pod 'ECStretchableHeaderView' 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Eric Castro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ECStretchableHeaderView 2 | ======================= 3 | 4 | A multi-purpose header view that you can attach to a UITableView (or any UIScrollView), allowing you to maximize the scrolling content's screen real state by expanding and contracting the top header upon scrolling down or up, or by delegating the decision on when to do this through a another object. 5 | 6 | Useful when such header isn't fully needed, but might have some buttons or some other interactive control that needs to remain visible. 7 | 8 | ![ECStretchableHeaderView](http://i.imgur.com/RCqO0O9.gif) 9 | 10 | ## Usage 11 | 12 | ```objc 13 | ECStretchableHeaderView *headerView; 14 | 15 | headerView = [[ECStretchableHeaderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.frame), maxHeight)]; 16 | 17 | // the header will expand up to 320 pixels tall when scrolling down 18 | headerView.maxHeight = 320.0f; 19 | 20 | // the header will shrink down to 100 pixels tall when scrolling up 21 | headerView.minHeight = 100.0f; 22 | 23 | // for demo purposes we programmatically create 24 | // a height constraint for the header view 25 | // but more likely you will create it on Interface Builder 26 | // and assign it to a private IBOutlet property 27 | 28 | NSLayoutConstraint *heightConstraint = [NSLayoutConstraint 29 | constraintWithItem:headerView 30 | attribute:NSLayoutAttributeHeight 31 | relatedBy:NSLayoutRelationEqual 32 | toItem:nil 33 | attribute:NSLayoutAttributeNotAnAttribute 34 | multiplier:1.0 35 | constant:headerView.maxHeight]]; 36 | 37 | [headerView addConstraint:heightConstraint]; 38 | 39 | headerView.heightConstraint = heightConstraint; 40 | 41 | // put it at the top of your table vew 42 | [headerView attachToScrollView:self.tableView inset:0.0f]; 43 | ``` 44 | 45 | ## Why do you need to set a height constraint? 46 | 47 | Because **ECStretchableHeaderView** is made to be auto-layout friendly, in a way that you can design your header view on your Storyboard, and not let it get your interface builder be full of layout errors and warnings for missing constraints. 48 | 49 | The height of the header view varies by modifying this constraint constant, as opposed to changing the view's frame. 50 | 51 | The example project contains a **ECStretchableHeaderView** that is not created programatically, but instead created in Interface Builder. 52 | 53 | ## License 54 | 55 | This project is MIT licensed. Feel free to contribute :-) --------------------------------------------------------------------------------