123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383 |
- //
- // IDMPhotoBrowser.m
- // IDMPhotoBrowser
- //
- // Created by Michael Waterfall on 14/10/2010.
- // Copyright 2010 d3i. All rights reserved.
- //
- #import <QuartzCore/QuartzCore.h>
- #import "IDMPhotoBrowser.h"
- #import "IDMZoomingScrollView.h"
- #import "pop/POP.h"
- #ifndef IDMPhotoBrowserLocalizedStrings
- #define IDMPhotoBrowserLocalizedStrings(key) \
- NSLocalizedStringFromTableInBundle((key), nil, [NSBundle bundleWithPath:[[NSBundle bundleForClass: [IDMPhotoBrowser class]] pathForResource:@"IDMPBLocalizations" ofType:@"bundle"]], nil)
- #endif
- // Private
- @interface IDMPhotoBrowser () {
- // Data
- NSMutableArray *_photos;
- // Views
- UIScrollView *_pagingScrollView;
- // Gesture
- UIPanGestureRecognizer *_panGesture;
- // Paging
- NSMutableSet *_visiblePages, *_recycledPages;
- NSUInteger _pageIndexBeforeRotation;
- NSUInteger _currentPageIndex;
- // Buttons
- UIButton *_doneButton;
- // Toolbar
- UIToolbar *_toolbar;
- UIBarButtonItem *_previousButton, *_nextButton, *_actionButton;
- UIBarButtonItem *_counterButton;
- UILabel *_counterLabel;
- // Actions
- UIActionSheet *_actionsSheet;
- UIActivityViewController *activityViewController;
- // Control
- NSTimer *_controlVisibilityTimer;
- // Appearance
- //UIStatusBarStyle _previousStatusBarStyle;
- BOOL _statusBarOriginallyHidden;
- // Present
- UIView *_senderViewForAnimation;
- // Misc
- BOOL _performingLayout;
- BOOL _rotating;
- BOOL _viewIsActive; // active as in it's in the view heirarchy
- BOOL _autoHide;
- NSInteger _initalPageIndex;
- BOOL _isdraggingPhoto;
- CGRect _senderViewOriginalFrame;
- //UIImage *_backgroundScreenshot;
- UIWindow *_applicationWindow;
- // iOS 7
- UIViewController *_applicationTopViewController;
- int _previousModalPresentationStyle;
- }
- // Private Properties
- @property (nonatomic, strong) UIActionSheet *actionsSheet;
- @property (nonatomic, strong) UIActivityViewController *activityViewController;
- // Private Methods
- // Layout
- - (void)performLayout;
- // Paging
- - (void)tilePages;
- - (BOOL)isDisplayingPageForIndex:(NSUInteger)index;
- - (IDMZoomingScrollView *)pageDisplayedAtIndex:(NSUInteger)index;
- - (IDMZoomingScrollView *)pageDisplayingPhoto:(id<IDMPhoto>)photo;
- - (IDMZoomingScrollView *)dequeueRecycledPage;
- - (void)configurePage:(IDMZoomingScrollView *)page forIndex:(NSUInteger)index;
- - (void)didStartViewingPageAtIndex:(NSUInteger)index;
- // Frames
- - (CGRect)frameForPagingScrollView;
- - (CGRect)frameForPageAtIndex:(NSUInteger)index;
- - (CGSize)contentSizeForPagingScrollView;
- - (CGPoint)contentOffsetForPageAtIndex:(NSUInteger)index;
- - (CGRect)frameForToolbarAtOrientation:(UIInterfaceOrientation)orientation;
- - (CGRect)frameForDoneButtonAtOrientation:(UIInterfaceOrientation)orientation;
- - (CGRect)frameForCaptionView:(IDMCaptionView *)captionView atIndex:(NSUInteger)index;
- // Toolbar
- - (void)updateToolbar;
- // Navigation
- - (void)jumpToPageAtIndex:(NSUInteger)index;
- - (void)gotoPreviousPage;
- - (void)gotoNextPage;
- // Controls
- - (void)cancelControlHiding;
- - (void)hideControlsAfterDelay;
- - (void)setControlsHidden:(BOOL)hidden animated:(BOOL)animated permanent:(BOOL)permanent;
- //- (void)toggleControls;
- - (BOOL)areControlsHidden;
- // Interactions
- - (void)handleSingleTap;
- // Data
- - (NSUInteger)numberOfPhotos;
- - (id<IDMPhoto>)photoAtIndex:(NSUInteger)index;
- - (UIImage *)imageForPhoto:(id<IDMPhoto>)photo;
- - (void)loadAdjacentPhotosIfNecessary:(id<IDMPhoto>)photo;
- - (void)releaseAllUnderlyingPhotos;
- @end
- // IDMPhotoBrowser
- @implementation IDMPhotoBrowser
- // Properties
- @synthesize displayDoneButton = _displayDoneButton, displayToolbar = _displayToolbar, displayActionButton = _displayActionButton, displayCounterLabel = _displayCounterLabel, useWhiteBackgroundColor = _useWhiteBackgroundColor, doneButtonImage = _doneButtonImage;
- @synthesize leftArrowImage = _leftArrowImage, rightArrowImage = _rightArrowImage, leftArrowSelectedImage = _leftArrowSelectedImage, rightArrowSelectedImage = _rightArrowSelectedImage;
- @synthesize displayArrowButton = _displayArrowButton, actionButtonTitles = _actionButtonTitles;
- @synthesize arrowButtonsChangePhotosAnimated = _arrowButtonsChangePhotosAnimated;
- @synthesize forceHideStatusBar = _forceHideStatusBar;
- @synthesize usePopAnimation = _usePopAnimation;
- @synthesize disableVerticalSwipe = _disableVerticalSwipe;
- @synthesize dismissOnTouch = _dismissOnTouch;
- @synthesize actionsSheet = _actionsSheet, activityViewController = _activityViewController;
- @synthesize trackTintColor = _trackTintColor, progressTintColor = _progressTintColor;
- @synthesize delegate = _delegate;
- #pragma mark - NSObject
- - (id)init {
- if ((self = [super init])) {
- // Defaults
- self.hidesBottomBarWhenPushed = YES;
-
- _currentPageIndex = 0;
- _performingLayout = NO; // Reset on view did appear
- _rotating = NO;
- _viewIsActive = NO;
- _visiblePages = [NSMutableSet new];
- _recycledPages = [NSMutableSet new];
- _photos = [NSMutableArray new];
- _initalPageIndex = 0;
- _autoHide = YES;
- _autoHideInterface = YES;
- _displayDoneButton = YES;
- _doneButtonImage = nil;
- _displayToolbar = YES;
- _displayActionButton = YES;
- _displayArrowButton = YES;
- _displayCounterLabel = NO;
- _forceHideStatusBar = NO;
- _usePopAnimation = NO;
- _disableVerticalSwipe = NO;
-
- _dismissOnTouch = NO;
- _useWhiteBackgroundColor = NO;
- _leftArrowImage = _rightArrowImage = _leftArrowSelectedImage = _rightArrowSelectedImage = nil;
- _arrowButtonsChangePhotosAnimated = YES;
- _backgroundScaleFactor = 1.0;
- _animationDuration = 0.28;
- _senderViewForAnimation = nil;
- _scaleImage = nil;
- _isdraggingPhoto = NO;
- if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {
- self.automaticallyAdjustsScrollViewInsets = NO;
- }
-
- _applicationWindow = [[[UIApplication sharedApplication] delegate] window];
- self.modalPresentationStyle = UIModalPresentationCustom;
- self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
- self.modalPresentationCapturesStatusBarAppearance = YES;
- self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
- // Listen for IDMPhoto notifications
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(handleIDMPhotoLoadingDidEndNotification:)
- name:IDMPhoto_LOADING_DID_END_NOTIFICATION
- object:nil];
- }
-
- return self;
- }
- - (id)initWithPhotos:(NSArray *)photosArray {
- if ((self = [self init])) {
- _photos = [[NSMutableArray alloc] initWithArray:photosArray];
- }
- return self;
- }
- - (id)initWithPhotos:(NSArray *)photosArray animatedFromView:(UIView*)view {
- if ((self = [self init])) {
- _photos = [[NSMutableArray alloc] initWithArray:photosArray];
- _senderViewForAnimation = view;
- }
- return self;
- }
- - (id)initWithPhotoURLs:(NSArray *)photoURLsArray {
- if ((self = [self init])) {
- NSArray *photosArray = [IDMPhoto photosWithURLs:photoURLsArray];
- _photos = [[NSMutableArray alloc] initWithArray:photosArray];
- }
- return self;
- }
- - (id)initWithPhotoURLs:(NSArray *)photoURLsArray animatedFromView:(UIView*)view {
- if ((self = [self init])) {
- NSArray *photosArray = [IDMPhoto photosWithURLs:photoURLsArray];
- _photos = [[NSMutableArray alloc] initWithArray:photosArray];
- _senderViewForAnimation = view;
- }
- return self;
- }
- - (void)dealloc {
- _pagingScrollView.delegate = nil;
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [self releaseAllUnderlyingPhotos];
- }
- - (void)releaseAllUnderlyingPhotos {
- for (id p in _photos) { if (p != [NSNull null]) [p unloadUnderlyingImage]; } // Release photos
- }
- - (void)didReceiveMemoryWarning {
- // Release any cached data, images, etc that aren't in use.
- [self releaseAllUnderlyingPhotos];
- [_recycledPages removeAllObjects];
- // Releases the view if it doesn't have a superview.
- [super didReceiveMemoryWarning];
- }
- #pragma mark - Pan Gesture
- - (void)panGestureRecognized:(id)sender {
- // Initial Setup
- IDMZoomingScrollView *scrollView = [self pageDisplayedAtIndex:_currentPageIndex];
- //IDMTapDetectingImageView *scrollView.photoImageView = scrollView.photoImageView;
- static float firstX, firstY;
- float viewHeight = scrollView.frame.size.height;
- float viewHalfHeight = viewHeight/2;
- CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self.view];
- // Gesture Began
- if ([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
- [self setControlsHidden:YES animated:YES permanent:YES];
- firstX = [scrollView center].x;
- firstY = [scrollView center].y;
- _senderViewForAnimation.hidden = (_currentPageIndex == _initalPageIndex);
- _isdraggingPhoto = YES;
- [self setNeedsStatusBarAppearanceUpdate];
- }
- translatedPoint = CGPointMake(firstX, firstY+translatedPoint.y);
- [scrollView setCenter:translatedPoint];
- float newY = scrollView.center.y - viewHalfHeight;
- float newAlpha = 1 - fabsf(newY)/viewHeight; //abs(newY)/viewHeight * 1.8;
- self.view.opaque = YES;
- self.view.backgroundColor = [UIColor colorWithWhite:(_useWhiteBackgroundColor ? 1 : 0) alpha:newAlpha];
- // Gesture Ended
- if ([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
- if(scrollView.center.y > viewHalfHeight+40 || scrollView.center.y < viewHalfHeight-40) // Automatic Dismiss View
- {
- if (_senderViewForAnimation && _currentPageIndex == _initalPageIndex) {
- [self performCloseAnimationWithScrollView:scrollView];
- return;
- }
- CGFloat finalX = firstX, finalY;
- CGFloat windowsHeigt = [_applicationWindow frame].size.height;
- if(scrollView.center.y > viewHalfHeight+30) // swipe down
- finalY = windowsHeigt*2;
- else // swipe up
- finalY = -viewHalfHeight;
- CGFloat animationDuration = 0.35;
- [UIView beginAnimations:nil context:NULL];
- [UIView setAnimationDuration:animationDuration];
- [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
- [UIView setAnimationDelegate:self];
- [scrollView setCenter:CGPointMake(finalX, finalY)];
- self.view.backgroundColor = [UIColor colorWithWhite:0 alpha:0];
- [UIView commitAnimations];
- [self performSelector:@selector(doneButtonPressed:) withObject:self afterDelay:animationDuration];
- }
- else // Continue Showing View
- {
- _isdraggingPhoto = NO;
- [self setNeedsStatusBarAppearanceUpdate];
- self.view.backgroundColor = [UIColor colorWithWhite:(_useWhiteBackgroundColor ? 1 : 0) alpha:1];
- CGFloat velocityY = (.35*[(UIPanGestureRecognizer*)sender velocityInView:self.view].y);
- CGFloat finalX = firstX;
- CGFloat finalY = viewHalfHeight;
- CGFloat animationDuration = (ABS(velocityY)*.0002)+.2;
- [UIView beginAnimations:nil context:NULL];
- [UIView setAnimationDuration:animationDuration];
- [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
- [UIView setAnimationDelegate:self];
- [scrollView setCenter:CGPointMake(finalX, finalY)];
- [UIView commitAnimations];
- }
- }
- }
- #pragma mark - Animation
- - (void)performPresentAnimation {
- self.view.alpha = 0.0f;
- _pagingScrollView.alpha = 0.0f;
- UIImage *imageFromView = _scaleImage ? _scaleImage : [self getImageFromView:_senderViewForAnimation];
- _senderViewOriginalFrame = [_senderViewForAnimation.superview convertRect:_senderViewForAnimation.frame toView:nil];
- UIView *fadeView = [[UIView alloc] initWithFrame:_applicationWindow.bounds];
- fadeView.backgroundColor = [UIColor clearColor];
- [_applicationWindow addSubview:fadeView];
- UIImageView *resizableImageView = [[UIImageView alloc] initWithImage:imageFromView];
- resizableImageView.frame = _senderViewOriginalFrame;
- resizableImageView.clipsToBounds = YES;
- resizableImageView.contentMode = _senderViewForAnimation ? _senderViewForAnimation.contentMode : UIViewContentModeScaleAspectFill;
- resizableImageView.backgroundColor = [UIColor clearColor];
- [_applicationWindow addSubview:resizableImageView];
- _senderViewForAnimation.hidden = YES;
- void (^completion)() = ^() {
- self.view.alpha = 1.0f;
- _pagingScrollView.alpha = 1.0f;
- resizableImageView.backgroundColor = [UIColor colorWithWhite:(_useWhiteBackgroundColor) ? 1 : 0 alpha:1];
- [fadeView removeFromSuperview];
- [resizableImageView removeFromSuperview];
- };
- [UIView animateWithDuration:_animationDuration animations:^{
- fadeView.backgroundColor = self.useWhiteBackgroundColor ? [UIColor whiteColor] : [UIColor blackColor];
- } completion:nil];
- CGRect finalImageViewFrame = [self animationFrameForImage:imageFromView presenting:YES scrollView:nil];
- if(_usePopAnimation)
- {
- [self animateView:resizableImageView
- toFrame:finalImageViewFrame
- completion:completion];
- }
- else
- {
- [UIView animateWithDuration:_animationDuration animations:^{
- resizableImageView.layer.frame = finalImageViewFrame;
- } completion:^(BOOL finished) {
- completion();
- }];
- }
- }
- - (void)performCloseAnimationWithScrollView:(IDMZoomingScrollView*)scrollView {
- if ([_delegate respondsToSelector:@selector(willDisappearPhotoBrowser:)]) {
- [_delegate willDisappearPhotoBrowser:self];
- }
- float fadeAlpha = 1 - fabs(scrollView.frame.origin.y)/scrollView.frame.size.height;
- UIImage *imageFromView = [scrollView.photo underlyingImage];
- if (!imageFromView && [scrollView.photo respondsToSelector:@selector(placeholderImage)]) {
- imageFromView = [scrollView.photo placeholderImage];
- }
- UIView *fadeView = [[UIView alloc] initWithFrame:_applicationWindow.bounds];
- fadeView.backgroundColor = self.useWhiteBackgroundColor ? [UIColor whiteColor] : [UIColor blackColor];
- fadeView.alpha = fadeAlpha;
- [_applicationWindow addSubview:fadeView];
- CGRect imageViewFrame = [self animationFrameForImage:imageFromView presenting:NO scrollView:scrollView];
- UIImageView *resizableImageView = [[UIImageView alloc] initWithImage:imageFromView];
- resizableImageView.frame = imageViewFrame;
- resizableImageView.contentMode = _senderViewForAnimation ? _senderViewForAnimation.contentMode : UIViewContentModeScaleAspectFill;
- resizableImageView.backgroundColor = [UIColor clearColor];
- resizableImageView.clipsToBounds = YES;
- [_applicationWindow addSubview:resizableImageView];
- self.view.hidden = YES;
- void (^completion)() = ^() {
- _senderViewForAnimation.hidden = NO;
- _senderViewForAnimation = nil;
- _scaleImage = nil;
- [fadeView removeFromSuperview];
- [resizableImageView removeFromSuperview];
- [self prepareForClosePhotoBrowser];
- [self dismissPhotoBrowserAnimated:NO];
- };
- [UIView animateWithDuration:_animationDuration animations:^{
- fadeView.alpha = 0;
- self.view.backgroundColor = [UIColor clearColor];
- } completion:nil];
- CGRect senderViewOriginalFrame = _senderViewForAnimation.superview ? [_senderViewForAnimation.superview convertRect:_senderViewForAnimation.frame toView:nil] : _senderViewOriginalFrame;
- if(_usePopAnimation)
- {
- [self animateView:resizableImageView
- toFrame:senderViewOriginalFrame
- completion:completion];
- }
- else
- {
- [UIView animateWithDuration:_animationDuration animations:^{
- resizableImageView.layer.frame = senderViewOriginalFrame;
- } completion:^(BOOL finished) {
- completion();
- }];
- }
- }
- - (CGRect)animationFrameForImage:(UIImage *)image presenting:(BOOL)presenting scrollView:(UIScrollView *)scrollView
- {
- if (!image) {
- return CGRectZero;
- }
- CGSize imageSize = image.size;
- CGFloat maxWidth = CGRectGetWidth(_applicationWindow.bounds);
- CGFloat maxHeight = CGRectGetHeight(_applicationWindow.bounds);
- CGRect animationFrame = CGRectZero;
- CGFloat aspect = imageSize.width / imageSize.height;
- if (maxWidth / aspect <= maxHeight) {
- animationFrame.size = CGSizeMake(maxWidth, maxWidth / aspect);
- }
- else {
- animationFrame.size = CGSizeMake(maxHeight * aspect, maxHeight);
- }
- animationFrame.origin.x = roundf((maxWidth - animationFrame.size.width) / 2.0f);
- animationFrame.origin.y = roundf((maxHeight - animationFrame.size.height) / 2.0f);
- if (!presenting) {
- animationFrame.origin.y += scrollView.frame.origin.y;
- }
- return animationFrame;
- }
- #pragma mark - Genaral
- - (void)prepareForClosePhotoBrowser {
- // Gesture
- [_applicationWindow removeGestureRecognizer:_panGesture];
- _autoHide = NO;
- // Controls
- [NSObject cancelPreviousPerformRequestsWithTarget:self]; // Cancel any pending toggles from taps
- }
- - (void)dismissPhotoBrowserAnimated:(BOOL)animated {
- self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
- if ([_delegate respondsToSelector:@selector(photoBrowser:willDismissAtPageIndex:)])
- [_delegate photoBrowser:self willDismissAtPageIndex:_currentPageIndex];
- [self dismissViewControllerAnimated:animated completion:^{
- if ([_delegate respondsToSelector:@selector(photoBrowser:didDismissAtPageIndex:)])
- [_delegate photoBrowser:self didDismissAtPageIndex:_currentPageIndex];
- // if (SYSTEM_VERSION_LESS_THAN(@"8.0"))
- // {
- // _applicationTopViewController.modalPresentationStyle = _previousModalPresentationStyle;
- // }
- }];
- }
- - (UIButton*)customToolbarButtonImage:(UIImage*)image imageSelected:(UIImage*)selectedImage action:(SEL)action {
- UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
- [button setImage:image forState:UIControlStateNormal];
- [button setImage:selectedImage forState:UIControlStateDisabled];
- [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
- [button setContentMode:UIViewContentModeCenter];
- [button setFrame:[self getToolbarButtonFrame:image]];
- return button;
- }
- - (CGRect)getToolbarButtonFrame:(UIImage *)image{
- BOOL const isRetinaHd = ((float)[[UIScreen mainScreen] scale] > 2.0f);
- float const defaultButtonSize = isRetinaHd ? 66.0f : 44.0f;
- CGFloat buttonWidth = (image.size.width > defaultButtonSize) ? image.size.width : defaultButtonSize;
- CGFloat buttonHeight = (image.size.height > defaultButtonSize) ? image.size.width : defaultButtonSize;
- return CGRectMake(0,0, buttonWidth, buttonHeight);
- }
- - (UIImage*)getImageFromView:(UIView *)view {
- UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, 2);
- [view.layer renderInContext:UIGraphicsGetCurrentContext()];
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return image;
- }
- - (UIViewController *)topviewController
- {
- UIViewController *topviewController = [UIApplication sharedApplication].keyWindow.rootViewController;
- while (topviewController.presentedViewController) {
- topviewController = topviewController.presentedViewController;
- }
- return topviewController;
- }
- #pragma mark - View Lifecycle
- - (void)viewDidLoad {
- // View
- self.view.backgroundColor = [UIColor colorWithWhite:(_useWhiteBackgroundColor ? 1 : 0) alpha:1];
- self.view.clipsToBounds = YES;
- // Setup paging scrolling view
- CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
- _pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];
- //_pagingScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- _pagingScrollView.pagingEnabled = YES;
- _pagingScrollView.delegate = self;
- _pagingScrollView.showsHorizontalScrollIndicator = NO;
- _pagingScrollView.showsVerticalScrollIndicator = NO;
- _pagingScrollView.backgroundColor = [UIColor clearColor];
- _pagingScrollView.contentSize = [self contentSizeForPagingScrollView];
- [self.view addSubview:_pagingScrollView];
- // Transition animation
- [self performPresentAnimation];
- UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation;
- // Toolbar
- _toolbar = [[UIToolbar alloc] initWithFrame:[self frameForToolbarAtOrientation:currentOrientation]];
- _toolbar.backgroundColor = [UIColor clearColor];
- _toolbar.clipsToBounds = YES;
- _toolbar.translucent = YES;
- [_toolbar setBackgroundImage:[UIImage new]
- forToolbarPosition:UIToolbarPositionAny
- barMetrics:UIBarMetricsDefault];
- // Close Button
- _doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
- [_doneButton setFrame:[self frameForDoneButtonAtOrientation:currentOrientation]];
- [_doneButton setAlpha:1.0f];
- [_doneButton addTarget:self action:@selector(doneButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
- if(!_doneButtonImage) {
- [_doneButton setTitleColor:[UIColor colorWithWhite:0.9 alpha:0.9] forState:UIControlStateNormal|UIControlStateHighlighted];
- [_doneButton setTitle:IDMPhotoBrowserLocalizedStrings(@"Done") forState:UIControlStateNormal];
- [_doneButton.titleLabel setFont:[UIFont boldSystemFontOfSize:11.0f]];
- [_doneButton setBackgroundColor:[UIColor colorWithWhite:0.1 alpha:0.5]];
- _doneButton.layer.cornerRadius = 3.0f;
- _doneButton.layer.borderColor = [UIColor colorWithWhite:0.9 alpha:0.9].CGColor;
- _doneButton.layer.borderWidth = 1.0f;
- }
- else {
- [_doneButton setImage:_doneButtonImage forState:UIControlStateNormal];
- _doneButton.contentMode = UIViewContentModeScaleAspectFit;
- }
- UIImage *leftButtonImage = (_leftArrowImage == nil) ?
- [UIImage imageNamed:@"IDMPhotoBrowser.bundle/images/IDMPhotoBrowser_arrowLeft.png"] : _leftArrowImage;
- UIImage *rightButtonImage = (_rightArrowImage == nil) ?
- [UIImage imageNamed:@"IDMPhotoBrowser.bundle/images/IDMPhotoBrowser_arrowRight.png"] : _rightArrowImage;
- UIImage *leftButtonSelectedImage = (_leftArrowSelectedImage == nil) ?
- [UIImage imageNamed:@"IDMPhotoBrowser.bundle/images/IDMPhotoBrowser_arrowLeftSelected.png"] : _leftArrowSelectedImage;
- UIImage *rightButtonSelectedImage = (_rightArrowSelectedImage == nil) ?
- [UIImage imageNamed:@"IDMPhotoBrowser.bundle/images/IDMPhotoBrowser_arrowRightSelected.png"] : _rightArrowSelectedImage;
- // Arrows
- _previousButton = [[UIBarButtonItem alloc] initWithCustomView:[self customToolbarButtonImage:leftButtonImage
- imageSelected:leftButtonSelectedImage
- action:@selector(gotoPreviousPage)]];
- _nextButton = [[UIBarButtonItem alloc] initWithCustomView:[self customToolbarButtonImage:rightButtonImage
- imageSelected:rightButtonSelectedImage
- action:@selector(gotoNextPage)]];
- // Counter Label
- _counterLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 95, 40)];
- _counterLabel.textAlignment = NSTextAlignmentCenter;
- _counterLabel.backgroundColor = [UIColor clearColor];
- _counterLabel.font = [UIFont fontWithName:@"Helvetica" size:17];
- if(_useWhiteBackgroundColor == NO) {
- _counterLabel.textColor = [UIColor whiteColor];
- _counterLabel.shadowColor = [UIColor darkTextColor];
- _counterLabel.shadowOffset = CGSizeMake(0, 1);
- }
- else {
- _counterLabel.textColor = [UIColor blackColor];
- }
- // Counter Button
- _counterButton = [[UIBarButtonItem alloc] initWithCustomView:_counterLabel];
- // Action Button
- _actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction
- target:self
- action:@selector(actionButtonPressed:)];
- // Gesture
- _panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognized:)];
- [_panGesture setMinimumNumberOfTouches:1];
- [_panGesture setMaximumNumberOfTouches:1];
- // Update
- //[self reloadData];
- // Super
- [super viewDidLoad];
- }
- - (void)viewWillAppear:(BOOL)animated {
- // Update
- [self reloadData];
- if ([_delegate respondsToSelector:@selector(willAppearPhotoBrowser:)]) {
- [_delegate willAppearPhotoBrowser:self];
- }
- // Super
- [super viewWillAppear:animated];
- // Status Bar
- _statusBarOriginallyHidden = [UIApplication sharedApplication].statusBarHidden;
- // Update UI
- [self hideControlsAfterDelay];
- }
- - (void)viewDidAppear:(BOOL)animated {
- [super viewDidAppear:animated];
- _viewIsActive = YES;
- }
- // Release any retained subviews of the main view.
- - (void)viewDidUnload {
- _currentPageIndex = 0;
- _pagingScrollView = nil;
- _visiblePages = nil;
- _recycledPages = nil;
- _toolbar = nil;
- _doneButton = nil;
- _previousButton = nil;
- _nextButton = nil;
- [super viewDidUnload];
- }
- #pragma mark - Status Bar
- - (UIStatusBarStyle)preferredStatusBarStyle {
- return _useWhiteBackgroundColor ? UIStatusBarStyleDefault : UIStatusBarStyleLightContent;
- }
- - (BOOL)prefersStatusBarHidden {
- if(_forceHideStatusBar) {
- return YES;
- }
- if(_isdraggingPhoto) {
- if(_statusBarOriginallyHidden) {
- return YES;
- }
- else {
- return NO;
- }
- }
- else {
- return [self areControlsHidden];
- }
- }
- - (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
- return UIStatusBarAnimationFade;
- }
- #pragma mark - Layout
- - (void)viewWillLayoutSubviews {
- // Flag
- _performingLayout = YES;
- UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation;
- // Toolbar
- _toolbar.frame = [self frameForToolbarAtOrientation:currentOrientation];
- // Done button
- _doneButton.frame = [self frameForDoneButtonAtOrientation:currentOrientation];
- // Remember index
- NSUInteger indexPriorToLayout = _currentPageIndex;
- // Get paging scroll view frame to determine if anything needs changing
- CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
- // Frame needs changing
- _pagingScrollView.frame = pagingScrollViewFrame;
- // Recalculate contentSize based on current orientation
- _pagingScrollView.contentSize = [self contentSizeForPagingScrollView];
- // Adjust frames and configuration of each visible page
- for (IDMZoomingScrollView *page in _visiblePages) {
- NSUInteger index = PAGE_INDEX(page);
- page.frame = [self frameForPageAtIndex:index];
- page.captionView.frame = [self frameForCaptionView:page.captionView atIndex:index];
- [page setMaxMinZoomScalesForCurrentBounds];
- }
- // Adjust contentOffset to preserve page location based on values collected prior to location
- _pagingScrollView.contentOffset = [self contentOffsetForPageAtIndex:indexPriorToLayout];
- [self didStartViewingPageAtIndex:_currentPageIndex]; // initial
- // Reset
- _currentPageIndex = indexPriorToLayout;
- _performingLayout = NO;
- // Super
- [super viewWillLayoutSubviews];
- }
- - (void)performLayout {
- // Setup
- _performingLayout = YES;
- NSUInteger numberOfPhotos = [self numberOfPhotos];
- // Setup pages
- [_visiblePages removeAllObjects];
- [_recycledPages removeAllObjects];
- // Toolbar
- if (_displayToolbar) {
- [self.view addSubview:_toolbar];
- } else {
- [_toolbar removeFromSuperview];
- }
- // Close button
- if(_displayDoneButton && !self.navigationController.navigationBar)
- [self.view addSubview:_doneButton];
- // Toolbar items & navigation
- UIBarButtonItem *fixedLeftSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
- target:self action:nil];
- fixedLeftSpace.width = 32; // To balance action button
- UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
- target:self action:nil];
- NSMutableArray *items = [NSMutableArray new];
- if (_displayActionButton)
- [items addObject:fixedLeftSpace];
- [items addObject:flexSpace];
- if (numberOfPhotos > 1 && _displayArrowButton)
- [items addObject:_previousButton];
- if(_displayCounterLabel) {
- [items addObject:flexSpace];
- [items addObject:_counterButton];
- }
- [items addObject:flexSpace];
- if (numberOfPhotos > 1 && _displayArrowButton)
- [items addObject:_nextButton];
- [items addObject:flexSpace];
- if(_displayActionButton)
- [items addObject:_actionButton];
- [_toolbar setItems:items];
- [self updateToolbar];
- // Content offset
- _pagingScrollView.contentOffset = [self contentOffsetForPageAtIndex:_currentPageIndex];
- [self tilePages];
- _performingLayout = NO;
- if(! _disableVerticalSwipe) {
- [self.view addGestureRecognizer:_panGesture];
- }
- }
- #pragma mark - Data
- - (void)reloadData {
- // Get data
- [self releaseAllUnderlyingPhotos];
- // Update
- [self performLayout];
- // Layout
- [self.view setNeedsLayout];
- }
- - (NSUInteger)numberOfPhotos {
- return _photos.count;
- }
- - (id<IDMPhoto>)photoAtIndex:(NSUInteger)index {
- return _photos[index];
- }
- - (IDMCaptionView *)captionViewForPhotoAtIndex:(NSUInteger)index {
- IDMCaptionView *captionView = nil;
- if ([_delegate respondsToSelector:@selector(photoBrowser:captionViewForPhotoAtIndex:)]) {
- captionView = [_delegate photoBrowser:self captionViewForPhotoAtIndex:index];
- } else {
- id <IDMPhoto> photo = [self photoAtIndex:index];
- if ([photo respondsToSelector:@selector(caption)]) {
- if ([photo caption]) captionView = [[IDMCaptionView alloc] initWithPhoto:photo];
- }
- }
- captionView.alpha = [self areControlsHidden] ? 0 : 1; // Initial alpha
- return captionView;
- }
- - (UIImage *)imageForPhoto:(id<IDMPhoto>)photo {
- if (photo) {
- // Get image or obtain in background
- if ([photo underlyingImage]) {
- return [photo underlyingImage];
- } else {
- [photo loadUnderlyingImageAndNotify];
- if ([photo respondsToSelector:@selector(placeholderImage)]) {
- return [photo placeholderImage];
- }
- }
- }
- return nil;
- }
- - (void)loadAdjacentPhotosIfNecessary:(id<IDMPhoto>)photo {
- IDMZoomingScrollView *page = [self pageDisplayingPhoto:photo];
- if (page) {
- // If page is current page then initiate loading of previous and next pages
- NSUInteger pageIndex = PAGE_INDEX(page);
- if (_currentPageIndex == pageIndex) {
- if (pageIndex > 0) {
- // Preload index - 1
- id <IDMPhoto> photo = [self photoAtIndex:pageIndex-1];
- if (![photo underlyingImage]) {
- [photo loadUnderlyingImageAndNotify];
- IDMLog(@"Pre-loading image at index %i", pageIndex-1);
- }
- }
- if (pageIndex < [self numberOfPhotos] - 1) {
- // Preload index + 1
- id <IDMPhoto> photo = [self photoAtIndex:pageIndex+1];
- if (![photo underlyingImage]) {
- [photo loadUnderlyingImageAndNotify];
- IDMLog(@"Pre-loading image at index %i", pageIndex+1);
- }
- }
- }
- }
- }
- #pragma mark - IDMPhoto Loading Notification
- - (void)handleIDMPhotoLoadingDidEndNotification:(NSNotification *)notification {
- id <IDMPhoto> photo = [notification object];
- IDMZoomingScrollView *page = [self pageDisplayingPhoto:photo];
- if (page) {
- if ([photo underlyingImage]) {
- // Successful load
- [page displayImage];
- [self loadAdjacentPhotosIfNecessary:photo];
- } else {
- // Failed to load
- [page displayImageFailure];
- }
- }
- }
- #pragma mark - Paging
- - (void)tilePages {
- // Calculate which pages should be visible
- // Ignore padding as paging bounces encroach on that
- // and lead to false page loads
- CGRect visibleBounds = _pagingScrollView.bounds;
- NSInteger iFirstIndex = (NSInteger) floorf((CGRectGetMinX(visibleBounds)+PADDING*2) / CGRectGetWidth(visibleBounds));
- NSInteger iLastIndex = (NSInteger) floorf((CGRectGetMaxX(visibleBounds)-PADDING*2-1) / CGRectGetWidth(visibleBounds));
- if (iFirstIndex < 0) iFirstIndex = 0;
- if (iFirstIndex > [self numberOfPhotos] - 1) iFirstIndex = [self numberOfPhotos] - 1;
- if (iLastIndex < 0) iLastIndex = 0;
- if (iLastIndex > [self numberOfPhotos] - 1) iLastIndex = [self numberOfPhotos] - 1;
- // Recycle no longer needed pages
- NSInteger pageIndex;
- for (IDMZoomingScrollView *page in _visiblePages) {
- pageIndex = PAGE_INDEX(page);
- if (pageIndex < (NSUInteger)iFirstIndex || pageIndex > (NSUInteger)iLastIndex) {
- [_recycledPages addObject:page];
- [page prepareForReuse];
- [page removeFromSuperview];
- IDMLog(@"Removed page at index %i", PAGE_INDEX(page));
- }
- }
- [_visiblePages minusSet:_recycledPages];
- while (_recycledPages.count > 2) // Only keep 2 recycled pages
- [_recycledPages removeObject:[_recycledPages anyObject]];
- // Add missing pages
- for (NSUInteger index = (NSUInteger)iFirstIndex; index <= (NSUInteger)iLastIndex; index++) {
- if (![self isDisplayingPageForIndex:index]) {
- // Add new page
- IDMZoomingScrollView *page;
- page = [[IDMZoomingScrollView alloc] initWithPhotoBrowser:self];
- page.backgroundColor = [UIColor clearColor];
- page.opaque = YES;
- [self configurePage:page forIndex:index];
- [_visiblePages addObject:page];
- [_pagingScrollView addSubview:page];
- IDMLog(@"Added page at index %i", index);
- // Add caption
- IDMCaptionView *captionView = [self captionViewForPhotoAtIndex:index];
- captionView.frame = [self frameForCaptionView:captionView atIndex:index];
- [_pagingScrollView addSubview:captionView];
- page.captionView = captionView;
- }
- }
- }
- - (BOOL)isDisplayingPageForIndex:(NSUInteger)index {
- for (IDMZoomingScrollView *page in _visiblePages)
- if (PAGE_INDEX(page) == index) return YES;
- return NO;
- }
- - (IDMZoomingScrollView *)pageDisplayedAtIndex:(NSUInteger)index {
- IDMZoomingScrollView *thePage = nil;
- for (IDMZoomingScrollView *page in _visiblePages) {
- if (PAGE_INDEX(page) == index) {
- thePage = page; break;
- }
- }
- return thePage;
- }
- - (IDMZoomingScrollView *)pageDisplayingPhoto:(id<IDMPhoto>)photo {
- IDMZoomingScrollView *thePage = nil;
- for (IDMZoomingScrollView *page in _visiblePages) {
- if (page.photo == photo) {
- thePage = page; break;
- }
- }
- return thePage;
- }
- - (void)configurePage:(IDMZoomingScrollView *)page forIndex:(NSUInteger)index {
- page.frame = [self frameForPageAtIndex:index];
- page.tag = PAGE_INDEX_TAG_OFFSET + index;
- page.photo = [self photoAtIndex:index];
- __block __weak IDMPhoto *photo = (IDMPhoto*)page.photo;
- __weak IDMZoomingScrollView* weakPage = page;
- photo.progressUpdateBlock = ^(CGFloat progress){
- [weakPage setProgress:progress forPhoto:photo];
- };
- }
- - (IDMZoomingScrollView *)dequeueRecycledPage {
- IDMZoomingScrollView *page = [_recycledPages anyObject];
- if (page) {
- [_recycledPages removeObject:page];
- }
- return page;
- }
- // Handle page changes
- - (void)didStartViewingPageAtIndex:(NSUInteger)index {
- // Load adjacent images if needed and the photo is already
- // loaded. Also called after photo has been loaded in background
- id <IDMPhoto> currentPhoto = [self photoAtIndex:index];
- if ([currentPhoto underlyingImage]) {
- // photo loaded so load ajacent now
- [self loadAdjacentPhotosIfNecessary:currentPhoto];
- }
- if ([_delegate respondsToSelector:@selector(photoBrowser:didShowPhotoAtIndex:)]) {
- [_delegate photoBrowser:self didShowPhotoAtIndex:index];
- }
- }
- #pragma mark - Frame Calculations
- - (CGRect)frameForPagingScrollView {
- CGRect frame = self.view.bounds;
- frame.origin.x -= PADDING;
- frame.size.width += (2 * PADDING);
- return frame;
- }
- - (CGRect)frameForPageAtIndex:(NSUInteger)index {
- // We have to use our paging scroll view's bounds, not frame, to calculate the page placement. When the device is in
- // landscape orientation, the frame will still be in portrait because the pagingScrollView is the root view controller's
- // view, so its frame is in window coordinate space, which is never rotated. Its bounds, however, will be in landscape
- // because it has a rotation transform applied.
- CGRect bounds = _pagingScrollView.bounds;
- CGRect pageFrame = bounds;
- pageFrame.size.width -= (2 * PADDING);
- pageFrame.origin.x = (bounds.size.width * index) + PADDING;
- return pageFrame;
- }
- - (CGSize)contentSizeForPagingScrollView {
- // We have to use the paging scroll view's bounds to calculate the contentSize, for the same reason outlined above.
- CGRect bounds = _pagingScrollView.bounds;
- return CGSizeMake(bounds.size.width * [self numberOfPhotos], bounds.size.height);
- }
- - (CGPoint)contentOffsetForPageAtIndex:(NSUInteger)index {
- CGFloat pageWidth = _pagingScrollView.bounds.size.width;
- CGFloat newOffset = index * pageWidth;
- return CGPointMake(newOffset, 0);
- }
- - (BOOL)isLandscape:(UIInterfaceOrientation)orientation
- {
- return UIInterfaceOrientationIsLandscape(orientation);
- }
- - (CGRect)frameForToolbarAtOrientation:(UIInterfaceOrientation)orientation {
- CGFloat height = 44;
- if ([self isLandscape:orientation])
- height = 32;
- return CGRectMake(0, self.view.bounds.size.height - height, self.view.bounds.size.width, height);
- }
- - (CGRect)frameForDoneButtonAtOrientation:(UIInterfaceOrientation)orientation {
- CGRect screenBound = self.view.bounds;
- CGFloat screenWidth = screenBound.size.width;
- // if ([self isLandscape:orientation]) screenWidth = screenBound.size.height;
- return CGRectMake(screenWidth - 75, 30, 55, 26);
- }
- - (CGRect)frameForCaptionView:(IDMCaptionView *)captionView atIndex:(NSUInteger)index {
- CGRect pageFrame = [self frameForPageAtIndex:index];
- CGSize captionSize = [captionView sizeThatFits:CGSizeMake(pageFrame.size.width, 0)];
- CGRect captionFrame = CGRectMake(pageFrame.origin.x, pageFrame.size.height - captionSize.height - (_toolbar.superview?_toolbar.frame.size.height:0), pageFrame.size.width, captionSize.height);
- return captionFrame;
- }
- #pragma mark - UIScrollView Delegate
- - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
- // Checks
- if (!_viewIsActive || _performingLayout || _rotating) return;
- // Tile pages
- [self tilePages];
- // Calculate current page
- CGRect visibleBounds = _pagingScrollView.bounds;
- NSInteger index = (NSInteger) (floorf(CGRectGetMidX(visibleBounds) / CGRectGetWidth(visibleBounds)));
- if (index < 0) index = 0;
- if (index > [self numberOfPhotos] - 1) index = [self numberOfPhotos] - 1;
- NSUInteger previousCurrentPage = _currentPageIndex;
- _currentPageIndex = index;
- if (_currentPageIndex != previousCurrentPage) {
- [self didStartViewingPageAtIndex:index];
- if(_arrowButtonsChangePhotosAnimated) [self updateToolbar];
- }
- }
- - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
- // Hide controls when dragging begins
- if(_autoHideInterface){
- [self setControlsHidden:YES animated:YES permanent:NO];
- }
- }
- - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
- // Update toolbar when page changes
- if(! _arrowButtonsChangePhotosAnimated) [self updateToolbar];
- }
- #pragma mark - Toolbar
- - (void)updateToolbar {
- // Counter
- if ([self numberOfPhotos] > 1) {
- _counterLabel.text = [NSString stringWithFormat:@"%lu %@ %lu", (unsigned long)(_currentPageIndex+1), IDMPhotoBrowserLocalizedStrings(@"of"), (unsigned long)[self numberOfPhotos]];
- } else {
- _counterLabel.text = nil;
- }
- // Buttons
- _previousButton.enabled = (_currentPageIndex > 0);
- _nextButton.enabled = (_currentPageIndex < [self numberOfPhotos]-1);
- }
- - (void)jumpToPageAtIndex:(NSUInteger)index {
- // Change page
- if (index < [self numberOfPhotos]) {
- CGRect pageFrame = [self frameForPageAtIndex:index];
- if(_arrowButtonsChangePhotosAnimated)
- {
- [_pagingScrollView setContentOffset:CGPointMake(pageFrame.origin.x - PADDING, 0) animated:YES];
- }
- else
- {
- _pagingScrollView.contentOffset = CGPointMake(pageFrame.origin.x - PADDING, 0);
- [self updateToolbar];
- }
- }
- // Update timer to give more time
- [self hideControlsAfterDelay];
- }
- - (void)gotoPreviousPage { [self jumpToPageAtIndex:_currentPageIndex-1]; }
- - (void)gotoNextPage { [self jumpToPageAtIndex:_currentPageIndex+1]; }
- #pragma mark - Control Hiding / Showing
- // If permanent then we don't set timers to hide again
- - (void)setControlsHidden:(BOOL)hidden animated:(BOOL)animated permanent:(BOOL)permanent {
- // Cancel any timers
- [self cancelControlHiding];
- // Captions
- NSMutableSet *captionViews = [[NSMutableSet alloc] initWithCapacity:_visiblePages.count];
- for (IDMZoomingScrollView *page in _visiblePages) {
- if (page.captionView) [captionViews addObject:page.captionView];
- }
- // Hide/show bars
- [UIView animateWithDuration:(animated ? 0.1 : 0) animations:^(void) {
- CGFloat alpha = hidden ? 0 : 1;
- [self.navigationController.navigationBar setAlpha:alpha];
- [_toolbar setAlpha:alpha];
- [_doneButton setAlpha:alpha];
- for (UIView *v in captionViews) v.alpha = alpha;
- } completion:^(BOOL finished) {}];
- // Control hiding timer
- // Will cancel existing timer but only begin hiding if they are visible
- if (!permanent) {
- [self hideControlsAfterDelay];
- }
-
- [self setNeedsStatusBarAppearanceUpdate];
- }
- - (void)cancelControlHiding {
- // If a timer exists then cancel and release
- if (_controlVisibilityTimer) {
- [_controlVisibilityTimer invalidate];
- _controlVisibilityTimer = nil;
- }
- }
- // Enable/disable control visiblity timer
- - (void)hideControlsAfterDelay {
- if (![self autoHideInterface]) {
- return;
- }
- if (![self areControlsHidden]) {
- [self cancelControlHiding];
- _controlVisibilityTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(hideControls) userInfo:nil repeats:NO];
- }
- }
- - (BOOL)areControlsHidden {
- return (_toolbar.alpha == 0);
- }
- - (void)hideControls {
- if(_autoHide && _autoHideInterface) {
- [self setControlsHidden:YES animated:YES permanent:NO];
- }
- }
- - (void)handleSingleTap {
- if (_dismissOnTouch) {
- [self doneButtonPressed:nil];
- } else {
- [self setControlsHidden:![self areControlsHidden] animated:YES permanent:NO];
- }
- }
- #pragma mark - Properties
- - (void)setInitialPageIndex:(NSUInteger)index {
- // Validate
- if (index >= [self numberOfPhotos]) index = [self numberOfPhotos]-1;
- _initalPageIndex = index;
- _currentPageIndex = index;
- if ([self isViewLoaded]) {
- [self jumpToPageAtIndex:index];
- if (!_viewIsActive) [self tilePages]; // Force tiling if view is not visible
- }
- }
- #pragma mark - Buttons
- - (void)doneButtonPressed:(id)sender {
- if ([_delegate respondsToSelector:@selector(willDisappearPhotoBrowser:)]) {
- [_delegate willDisappearPhotoBrowser:self];
- }
- if (_senderViewForAnimation && _currentPageIndex == _initalPageIndex) {
- IDMZoomingScrollView *scrollView = [self pageDisplayedAtIndex:_currentPageIndex];
- [self performCloseAnimationWithScrollView:scrollView];
- }
- else {
- _senderViewForAnimation.hidden = NO;
- [self prepareForClosePhotoBrowser];
- [self dismissPhotoBrowserAnimated:YES];
- }
- }
- - (void)actionButtonPressed:(id)sender {
- id <IDMPhoto> photo = [self photoAtIndex:_currentPageIndex];
- if ([self numberOfPhotos] > 0 && [photo underlyingImage]) {
- if(!_actionButtonTitles)
- {
- // Activity view
- NSMutableArray *activityItems = [NSMutableArray arrayWithObject:[photo underlyingImage]];
- if (photo.caption) [activityItems addObject:photo.caption];
- self.activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
- __typeof__(self) __weak selfBlock = self;
- [self.activityViewController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
- [selfBlock hideControlsAfterDelay];
- selfBlock.activityViewController = nil;
- }];
- if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
- [self presentViewController:self.activityViewController animated:YES completion:nil];
- }
- else { // iPad
- UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:self.activityViewController];
- [popover presentPopoverFromRect:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0)
- inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny
- animated:YES];
- }
- }
- else
- {
- // Action sheet
- self.actionsSheet = [UIActionSheet new];
- self.actionsSheet.delegate = self;
- for(NSString *action in _actionButtonTitles) {
- [self.actionsSheet addButtonWithTitle:action];
- }
- self.actionsSheet.cancelButtonIndex = [self.actionsSheet addButtonWithTitle:IDMPhotoBrowserLocalizedStrings(@"Cancel")];
- self.actionsSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
- if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
- [_actionsSheet showInView:self.view];
- } else {
- [_actionsSheet showFromBarButtonItem:sender animated:YES];
- }
- }
- // Keep controls hidden
- [self setControlsHidden:NO animated:YES permanent:YES];
- }
- }
- #pragma mark - Action Sheet Delegate
- - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
- if (actionSheet == _actionsSheet) {
- self.actionsSheet = nil;
- if (buttonIndex != actionSheet.cancelButtonIndex) {
- if ([_delegate respondsToSelector:@selector(photoBrowser:didDismissActionSheetWithButtonIndex:photoIndex:)]) {
- [_delegate photoBrowser:self didDismissActionSheetWithButtonIndex:buttonIndex photoIndex:_currentPageIndex];
- return;
- }
- }
- }
- [self hideControlsAfterDelay]; // Continue as normal...
- }
- #pragma mark - pop Animation
- - (void)animateView:(UIView *)view toFrame:(CGRect)frame completion:(void (^)(void))completion
- {
- POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
- [animation setSpringBounciness:6];
- [animation setDynamicsMass:1];
- [animation setToValue:[NSValue valueWithCGRect:frame]];
- [view pop_addAnimation:animation forKey:nil];
- if (completion)
- {
- [animation setCompletionBlock:^(POPAnimation *animation, BOOL finished) {
- completion();
- }];
- }
- }
- @end
|