mirror of
https://github.com/zhigang1992/MWPhotoBrowser.git
synced 2026-04-29 12:45:10 +08:00
Added SDWebImage3+ support and FBGallery ready
This commit is contained in:
0
MWPhotoBrowser/Classes/MWCaptionView.h
Normal file → Executable file
0
MWPhotoBrowser/Classes/MWCaptionView.h
Normal file → Executable file
4
MWPhotoBrowser/Classes/MWCaptionView.m
Normal file → Executable file
4
MWPhotoBrowser/Classes/MWCaptionView.m
Normal file → Executable file
@@ -48,8 +48,8 @@ static const CGFloat labelPadding = 10;
|
||||
_label.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
|
||||
_label.opaque = NO;
|
||||
_label.backgroundColor = [UIColor clearColor];
|
||||
_label.textAlignment = UITextAlignmentCenter;
|
||||
_label.lineBreakMode = UILineBreakModeWordWrap;
|
||||
_label.textAlignment = NSTextAlignmentCenter;
|
||||
_label.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
_label.numberOfLines = 3;
|
||||
_label.textColor = [UIColor whiteColor];
|
||||
_label.shadowColor = [UIColor blackColor];
|
||||
|
||||
2
MWPhotoBrowser/Classes/MWPhoto.h
Normal file → Executable file
2
MWPhotoBrowser/Classes/MWPhoto.h
Normal file → Executable file
@@ -15,7 +15,7 @@
|
||||
// If you want to handle photos, caching, decompression
|
||||
// yourself then you can simply ensure your custom data model
|
||||
// conforms to MWPhotoProtocol
|
||||
@interface MWPhoto : NSObject <MWPhoto, SDWebImageManagerDelegate, SDWebImageDecoderDelegate>
|
||||
@interface MWPhoto : NSObject <MWPhoto>
|
||||
|
||||
// Properties
|
||||
@property (nonatomic, retain) NSString *caption;
|
||||
|
||||
47
MWPhotoBrowser/Classes/MWPhoto.m
Normal file → Executable file
47
MWPhotoBrowser/Classes/MWPhoto.m
Normal file → Executable file
@@ -80,7 +80,6 @@ caption = _caption;
|
||||
|
||||
- (void)dealloc {
|
||||
[_caption release];
|
||||
[[SDWebImageManager sharedManager] cancelForDelegate:self];
|
||||
[_photoPath release];
|
||||
[_photoURL release];
|
||||
[_underlyingImage release];
|
||||
@@ -105,8 +104,14 @@ caption = _caption;
|
||||
[self performSelectorInBackground:@selector(loadImageFromFileAsync) withObject:nil];
|
||||
} else if (_photoURL) {
|
||||
// Load async from web (using SDWebImage)
|
||||
SDWebImageManager *manager = [SDWebImageManager sharedManager];
|
||||
[manager downloadWithURL:_photoURL delegate:self];
|
||||
[[SDWebImageManager sharedManager] downloadWithURL: _photoURL
|
||||
options: 0
|
||||
progress:^(NSUInteger receivedSize, long long expectedSize) {
|
||||
|
||||
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
|
||||
self.underlyingImage = image;
|
||||
[self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO];
|
||||
}];
|
||||
} else {
|
||||
// Failed - no source
|
||||
self.underlyingImage = nil;
|
||||
@@ -118,7 +123,6 @@ caption = _caption;
|
||||
// Release if we can get it again from path or url
|
||||
- (void)unloadUnderlyingImage {
|
||||
_loadingInProgress = NO;
|
||||
[[SDWebImageManager sharedManager] cancelForDelegate:self];
|
||||
if (self.underlyingImage && (_photoPath || _photoURL)) {
|
||||
self.underlyingImage = nil;
|
||||
}
|
||||
@@ -141,22 +145,13 @@ caption = _caption;
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
} @finally {
|
||||
[self performSelectorOnMainThread:@selector(imageDidFinishLoadingSoDecompress) withObject:nil waitUntilDone:NO];
|
||||
self.underlyingImage = [UIImage decodedImageWithImage: self.underlyingImage];
|
||||
[self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO];
|
||||
[pool drain];
|
||||
}
|
||||
}
|
||||
|
||||
// Called on main
|
||||
- (void)imageDidFinishLoadingSoDecompress {
|
||||
NSAssert([[NSThread currentThread] isMainThread], @"This method must be called on the main thread.");
|
||||
if (self.underlyingImage) {
|
||||
// Decode image async to avoid lagging when UIKit lazy loads
|
||||
[[SDWebImageDecoder sharedImageDecoder] decodeImage:self.underlyingImage withDelegate:self userInfo:nil];
|
||||
} else {
|
||||
// Failed
|
||||
[self imageLoadingComplete];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)imageLoadingComplete {
|
||||
NSAssert([[NSThread currentThread] isMainThread], @"This method must be called on the main thread.");
|
||||
@@ -166,26 +161,4 @@ caption = _caption;
|
||||
object:self];
|
||||
}
|
||||
|
||||
#pragma mark - SDWebImage Delegate
|
||||
|
||||
// Called on main
|
||||
- (void)webImageManager:(SDWebImageManager *)imageManager didFinishWithImage:(UIImage *)image {
|
||||
self.underlyingImage = image;
|
||||
[self imageDidFinishLoadingSoDecompress];
|
||||
}
|
||||
|
||||
// Called on main
|
||||
- (void)webImageManager:(SDWebImageManager *)imageManager didFailWithError:(NSError *)error {
|
||||
self.underlyingImage = nil;
|
||||
MWLog(@"SDWebImage failed to download image: %@", error);
|
||||
[self imageDidFinishLoadingSoDecompress];
|
||||
}
|
||||
|
||||
// Called on main
|
||||
- (void)imageDecoder:(SDWebImageDecoder *)decoder didFinishDecodingImage:(UIImage *)image userInfo:(NSDictionary *)userInfo {
|
||||
// Finished compression so we're complete
|
||||
self.underlyingImage = image;
|
||||
[self imageLoadingComplete];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
21
MWPhotoBrowser/Classes/MWPhotoBrowser.h
Normal file → Executable file
21
MWPhotoBrowser/Classes/MWPhotoBrowser.h
Normal file → Executable file
@@ -11,6 +11,7 @@
|
||||
#import "MWPhoto.h"
|
||||
#import "MWPhotoProtocol.h"
|
||||
#import "MWCaptionView.h"
|
||||
#import "MWTapDetectingImageView.h"
|
||||
|
||||
// Debug Logging
|
||||
#if 0 // Set to 1 to enable debug logging
|
||||
@@ -29,11 +30,26 @@
|
||||
@end
|
||||
|
||||
// MWPhotoBrowser
|
||||
@interface MWPhotoBrowser : UIViewController <UIScrollViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate>
|
||||
@interface MWPhotoBrowser : UIViewController <UIScrollViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate>
|
||||
|
||||
|
||||
|
||||
|
||||
// FB Photo Browser
|
||||
@property (nonatomic,strong) UIImageView *screenshot;
|
||||
@property (nonatomic,strong) UIView *screenshotView;
|
||||
@property (nonatomic,strong) UIImageView *entranceImg;
|
||||
@property (nonatomic,strong) UIView *entranceImgMask;
|
||||
- (void) setTransparentForScreenshot:(float)alpha;
|
||||
|
||||
|
||||
|
||||
|
||||
// Properties
|
||||
@property (nonatomic) BOOL displayActionButton;
|
||||
|
||||
@property (nonatomic, retain) NSArray *photos;
|
||||
|
||||
// Init
|
||||
- (id)initWithPhotos:(NSArray *)photosArray __attribute__((deprecated)); // Depreciated
|
||||
- (id)initWithDelegate:(id <MWPhotoBrowserDelegate>)delegate;
|
||||
@@ -44,6 +60,9 @@
|
||||
// Set page that photo browser starts on
|
||||
- (void)setInitialPageIndex:(NSUInteger)index;
|
||||
|
||||
|
||||
- (UIScrollView *)getPagingScrollView;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
203
MWPhotoBrowser/Classes/MWPhotoBrowser.m
Normal file → Executable file
203
MWPhotoBrowser/Classes/MWPhotoBrowser.m
Normal file → Executable file
@@ -11,6 +11,7 @@
|
||||
#import "MWZoomingScrollView.h"
|
||||
#import "MBProgressHUD.h"
|
||||
#import "SDImageCache.h"
|
||||
#import "UIView+viewController.h"
|
||||
|
||||
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
|
||||
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
|
||||
@@ -22,6 +23,18 @@
|
||||
#define PAGE_INDEX_TAG_OFFSET 1000
|
||||
#define PAGE_INDEX(page) ([(page) tag] - PAGE_INDEX_TAG_OFFSET)
|
||||
|
||||
|
||||
// FB Photo Browser
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
#define kAnimationDuration 0.3
|
||||
#define kBGpushBackRatio 0.92
|
||||
#define tagScreenshot 1000
|
||||
|
||||
|
||||
|
||||
|
||||
// Private
|
||||
@interface MWPhotoBrowser () {
|
||||
|
||||
@@ -140,6 +153,11 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
@synthesize progressHUD = _progressHUD;
|
||||
@synthesize previousViewControllerBackButton = _previousViewControllerBackButton;
|
||||
|
||||
|
||||
// FB PhotoBrowser
|
||||
@synthesize screenshot, entranceImg;
|
||||
@synthesize screenshotView, entranceImgMask;
|
||||
|
||||
#pragma mark - NSObject
|
||||
|
||||
- (id)init {
|
||||
@@ -234,7 +252,7 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
_pagingScrollView.delegate = self;
|
||||
_pagingScrollView.showsHorizontalScrollIndicator = NO;
|
||||
_pagingScrollView.showsVerticalScrollIndicator = NO;
|
||||
_pagingScrollView.backgroundColor = [UIColor blackColor];
|
||||
_pagingScrollView.backgroundColor = [UIColor clearColor];
|
||||
_pagingScrollView.contentSize = [self contentSizeForPagingScrollView];
|
||||
[self.view addSubview:_pagingScrollView];
|
||||
|
||||
@@ -247,11 +265,42 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
}
|
||||
_toolbar.barStyle = UIBarStyleBlackTranslucent;
|
||||
_toolbar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
|
||||
_toolbar.hidden = YES;
|
||||
|
||||
// Toolbar Items
|
||||
_previousButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"MWPhotoBrowser.bundle/images/UIBarButtonItemArrowLeft.png"] style:UIBarButtonItemStylePlain target:self action:@selector(gotoPreviousPage)];
|
||||
_nextButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"MWPhotoBrowser.bundle/images/UIBarButtonItemArrowRight.png"] style:UIBarButtonItemStylePlain target:self action:@selector(gotoNextPage)];
|
||||
_actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actionButtonPressed:)];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// FB Photo Browser
|
||||
[_pagingScrollView setHidden:YES];
|
||||
|
||||
// Offset for screenshot without status bar
|
||||
screenshotView = [[UIView alloc] initWithFrame:screenshot.frame];
|
||||
[screenshotView shiftViewPositionY:20];
|
||||
[screenshot setTag:tagScreenshot];
|
||||
|
||||
entranceImgMask = [[UIView alloc] initWithFrame:CGRectMake(0, 0, entranceImg.frame.size.width, entranceImg.frame.size.height)];
|
||||
entranceImgMask.backgroundColor = [UIColor blackColor];
|
||||
[self.entranceImg addSubview:entranceImgMask];
|
||||
|
||||
[self.screenshotView addSubview:screenshot];
|
||||
[self.view insertSubview:screenshotView belowSubview:_pagingScrollView];
|
||||
|
||||
[self.view insertSubview:entranceImg aboveSubview:screenshot];
|
||||
|
||||
[self startAnimation];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Update
|
||||
[self reloadData];
|
||||
@@ -261,6 +310,135 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void) startAnimation
|
||||
{
|
||||
// Calculate new image size and position
|
||||
float scaleRatio = self.view.frame.size.width / entranceImg.image.size.width;
|
||||
float newHeight = scaleRatio * entranceImg.image.size.height;
|
||||
float originCenterY = entranceImg.center.y;
|
||||
|
||||
[entranceImg setHidden:YES];
|
||||
UIImageView *eImgCopy = [[UIImageView alloc] initWithFrame:entranceImg.frame];
|
||||
eImgCopy.image = entranceImg.image;
|
||||
eImgCopy.contentMode = UIViewContentModeScaleAspectFill;
|
||||
|
||||
[self.view addSubview:eImgCopy];
|
||||
|
||||
[UIView animateWithDuration:kAnimationDuration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||
screenshot.alpha = 0.0;
|
||||
[self pushDownBgView:YES];
|
||||
|
||||
[eImgCopy setContentMode:UIViewContentModeScaleAspectFill];
|
||||
[eImgCopy setFrame:CGRectMake(0, self.view.frame.size.height / 2 - newHeight / 2, self.view.frame.size.width, newHeight)];
|
||||
|
||||
} completion:^(BOOL finished) {
|
||||
|
||||
// Bounce animation
|
||||
[self bounceView:eImgCopy distance:(originCenterY - eImgCopy.center.y) completent:^{
|
||||
[eImgCopy removeFromSuperview];
|
||||
[_pagingScrollView setHidden:NO];
|
||||
|
||||
// Add original image to screenshot
|
||||
[entranceImg shiftViewPositionY:-20];
|
||||
[self.screenshotView addSubview:entranceImg];
|
||||
}];
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) exitBrowserView:(UIImageView *)currentImg
|
||||
{
|
||||
// Clone current image and perform animation
|
||||
UIImageView *tempImg = [[UIImageView alloc] initWithFrame:currentImg.frame];
|
||||
tempImg.contentMode = UIViewContentModeScaleAspectFill;
|
||||
tempImg.image = currentImg.image;
|
||||
tempImg.clipsToBounds = YES;
|
||||
|
||||
[_pagingScrollView setHidden:YES];
|
||||
currentImg.userInteractionEnabled = NO;
|
||||
|
||||
[self.view addSubview:tempImg];
|
||||
|
||||
CGRect tempImgFrame = entranceImg.frame;
|
||||
screenshotView.alpha = 1.0;
|
||||
|
||||
CGRect outScreenFrame = tempImg.frame;
|
||||
outScreenFrame.origin.y = tempImg.center.y > self.view.frame.size.height / 2 ? self.view.frame.size.height + outScreenFrame.size.height : -outScreenFrame.size.height;
|
||||
|
||||
if (currentImg.image != entranceImg.image)
|
||||
{
|
||||
|
||||
} else {
|
||||
tempImgFrame.origin.y += 20;
|
||||
}
|
||||
|
||||
|
||||
[UIView animateWithDuration:kAnimationDuration delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
if (currentImg.image == entranceImg.image)
|
||||
{
|
||||
[tempImg setFrame:tempImgFrame];
|
||||
} else {
|
||||
[tempImg setFrame:outScreenFrame];
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
// Back to timeline view when animation ended
|
||||
[self dismissViewControllerAnimated:NO completion:nil];
|
||||
}];
|
||||
|
||||
[self pushDownBgView:NO];
|
||||
|
||||
}
|
||||
|
||||
#pragma marks - Animations
|
||||
|
||||
- (void) pushDownBgView:(bool)push
|
||||
{
|
||||
CABasicAnimation *animation;
|
||||
animation=[CABasicAnimation animationWithKeyPath:@"transform.scale"];
|
||||
animation.delegate = self;
|
||||
animation.duration = kAnimationDuration;
|
||||
animation.repeatCount = 0;
|
||||
animation.removedOnCompletion = FALSE;
|
||||
animation.fillMode = kCAFillModeForwards;
|
||||
animation.fromValue = push ? [NSNumber numberWithFloat:1] : [NSNumber numberWithFloat:kBGpushBackRatio];
|
||||
animation.toValue = push ? [NSNumber numberWithFloat:kBGpushBackRatio] : [NSNumber numberWithFloat:1.0];
|
||||
|
||||
[screenshotView.layer addAnimation:animation forKey:nil];
|
||||
}
|
||||
|
||||
- (void) setTransparentForScreenshot:(float)alpha
|
||||
{
|
||||
self.screenshot.alpha = alpha;
|
||||
self.entranceImgMask.alpha = 1 - alpha;
|
||||
}
|
||||
|
||||
- (void) bounceView:(UIView *)view distance:(float)distance completent:(void (^)(void))completion
|
||||
{
|
||||
[CATransaction begin]; {
|
||||
[CATransaction setCompletionBlock:^{
|
||||
completion();
|
||||
}];
|
||||
|
||||
// Bound photo based on distance
|
||||
CABasicAnimation *animation;
|
||||
animation=[CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
|
||||
animation.delegate = self;
|
||||
animation.duration = kAnimationDuration / 2 ;
|
||||
animation.repeatCount = 0;
|
||||
animation.removedOnCompletion = YES;
|
||||
animation.fillMode = kCAFillModeForwards;
|
||||
animation.autoreverses = YES;
|
||||
animation.fromValue = [NSNumber numberWithFloat:0.0];
|
||||
animation.toValue = [NSNumber numberWithFloat:distance * -0.02];
|
||||
[view.layer addAnimation:animation forKey:@"transform.translation.y"];
|
||||
|
||||
} [CATransaction commit];
|
||||
}
|
||||
|
||||
// Photo Browser ended
|
||||
|
||||
|
||||
- (void)performLayout {
|
||||
|
||||
// Setup
|
||||
@@ -571,6 +749,7 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
}
|
||||
|
||||
- (MWCaptionView *)captionViewForPhotoAtIndex:(NSUInteger)index {
|
||||
|
||||
MWCaptionView *captionView = nil;
|
||||
if ([_delegate respondsToSelector:@selector(photoBrowser:captionViewForPhotoAtIndex:)]) {
|
||||
captionView = [_delegate photoBrowser:self captionViewForPhotoAtIndex:index];
|
||||
@@ -841,7 +1020,13 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
if (_currentPageIndex != previousCurrentPage) {
|
||||
[self didStartViewingPageAtIndex:index];
|
||||
}
|
||||
|
||||
|
||||
MWPhoto *curPhoto = [_photos objectAtIndex:_currentPageIndex];
|
||||
if ([curPhoto underlyingImage] != entranceImg.image)
|
||||
{
|
||||
[entranceImg setHidden:NO];
|
||||
} else [entranceImg setHidden:YES];
|
||||
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
|
||||
@@ -910,7 +1095,7 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
if ([UIApplication instancesRespondToSelector:@selector(setStatusBarHidden:withAnimation:)]) {
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:animated?UIStatusBarAnimationFade:UIStatusBarAnimationNone];
|
||||
} else {
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:hidden animated:animated];
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:UIStatusBarAnimationFade];
|
||||
}
|
||||
|
||||
// Get status bar height if visible
|
||||
@@ -937,6 +1122,7 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
[UIView beginAnimations:nil context:nil];
|
||||
[UIView setAnimationDuration:0.35];
|
||||
}
|
||||
|
||||
CGFloat alpha = hidden ? 0 : 1;
|
||||
[self.navigationController.navigationBar setAlpha:alpha];
|
||||
[_toolbar setAlpha:alpha];
|
||||
@@ -986,7 +1172,7 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
#pragma mark - Misc
|
||||
|
||||
- (void)doneButtonPressed:(id)sender {
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)actionButtonPressed:(id)sender {
|
||||
@@ -1136,7 +1322,7 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
emailer.modalPresentationStyle = UIModalPresentationPageSheet;
|
||||
}
|
||||
[self presentModalViewController:emailer animated:YES];
|
||||
[self presentViewController:emailer animated:YES completion:nil];
|
||||
[emailer release];
|
||||
[self hideProgressHUD:NO];
|
||||
}
|
||||
@@ -1151,7 +1337,12 @@ navigationBarBackgroundImageLandscapePhone = _navigationBarBackgroundImageLandsc
|
||||
delegate:nil cancelButtonTitle:NSLocalizedString(@"Dismiss", nil) otherButtonTitles:nil] autorelease];
|
||||
[alert show];
|
||||
}
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (UIScrollView *)getPagingScrollView
|
||||
{
|
||||
return _pagingScrollView;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
0
MWPhotoBrowser/Classes/MWPhotoProtocol.h
Normal file → Executable file
0
MWPhotoBrowser/Classes/MWPhotoProtocol.h
Normal file → Executable file
6
MWPhotoBrowser/Classes/MWTapDetectingImageView.h
Normal file → Executable file
6
MWPhotoBrowser/Classes/MWTapDetectingImageView.h
Normal file → Executable file
@@ -12,7 +12,13 @@
|
||||
|
||||
@interface MWTapDetectingImageView : UIImageView {
|
||||
id <MWTapDetectingImageViewDelegate> tapDelegate;
|
||||
|
||||
CGPoint startLocation;
|
||||
CGPoint imageStartOrigin;
|
||||
float lastDragPt;
|
||||
bool dragging;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) id <MWTapDetectingImageViewDelegate> tapDelegate;
|
||||
- (void)handleSingleTap:(UITouch *)touch;
|
||||
- (void)handleDoubleTap:(UITouch *)touch;
|
||||
|
||||
103
MWPhotoBrowser/Classes/MWTapDetectingImageView.m
Normal file → Executable file
103
MWPhotoBrowser/Classes/MWTapDetectingImageView.m
Normal file → Executable file
@@ -7,6 +7,11 @@
|
||||
//
|
||||
|
||||
#import "MWTapDetectingImageView.h"
|
||||
#import "MWPhotoBrowser.h"
|
||||
#import "MWZoomingScrollView.h"
|
||||
#import "UIView+viewController.h"
|
||||
|
||||
#define tagScreenshot 1000
|
||||
|
||||
@implementation MWTapDetectingImageView
|
||||
|
||||
@@ -33,9 +38,105 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIViewController*)viewController
|
||||
{
|
||||
for (UIView* next = [self superview]; next; next = next.superview)
|
||||
{
|
||||
UIResponder* nextResponder = [next nextResponder];
|
||||
|
||||
if ([nextResponder isKindOfClass:[UIViewController class]])
|
||||
{
|
||||
return (UIViewController*)nextResponder;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||
// Retrieve the touch point as image start location;
|
||||
CGPoint pt = [[touches anyObject] locationInView:self.superview];
|
||||
startLocation = pt;
|
||||
|
||||
// Get image start origin
|
||||
imageStartOrigin = self.frame.origin;
|
||||
dragging = YES;
|
||||
|
||||
// Disable scrollview
|
||||
if ([[self firstAvailableUIViewController] isKindOfClass:[MWPhotoBrowser class]])
|
||||
{
|
||||
[[(MWPhotoBrowser *)[self firstAvailableUIViewController] getPagingScrollView] setScrollEnabled:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||
// Move relative to the original touch point
|
||||
CGPoint pt = [[touches anyObject] locationInView:self.superview];
|
||||
CGRect frame = [self frame];
|
||||
|
||||
// Calculate the drag distance
|
||||
float newY = imageStartOrigin.y - ((float)startLocation.y - (float)pt.y);
|
||||
float dY = newY - imageStartOrigin.y;
|
||||
|
||||
// Bound drag distance and change alpha of background
|
||||
if (fabsf(dY) > self.frame.size.height / 4)
|
||||
{
|
||||
dY = self.frame.size.height / 4;
|
||||
}
|
||||
|
||||
float newAlpha = fabsf(dY) / (self.frame.size.height / 2);
|
||||
|
||||
[(MWPhotoBrowser *)[self firstAvailableUIViewController] setTransparentForScreenshot:newAlpha - 0.2];
|
||||
|
||||
// Get new location to image
|
||||
frame.origin.y = newY;
|
||||
[self setFrame:frame];
|
||||
}
|
||||
|
||||
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||
UITouch *touch = [touches anyObject];
|
||||
NSUInteger tapCount = touch.tapCount;
|
||||
NSUInteger tapCount = touch.tapCount;
|
||||
|
||||
// If touch event is ended dragging
|
||||
if (dragging)
|
||||
{
|
||||
dragging = NO;
|
||||
|
||||
// Enable scrollview
|
||||
if ([[self firstAvailableUIViewController] isKindOfClass:[MWPhotoBrowser class]])
|
||||
{
|
||||
[[(MWPhotoBrowser *)[self firstAvailableUIViewController] getPagingScrollView] setScrollEnabled:YES];
|
||||
}
|
||||
|
||||
// Calculate end point location
|
||||
CGPoint pt = [[touches anyObject] locationInView:self.superview];
|
||||
CGRect newFrame = [self frame];
|
||||
newFrame.origin.y = imageStartOrigin.y;
|
||||
|
||||
float newY = imageStartOrigin.y - ((float)startLocation.y - (float)pt.y);
|
||||
float dY = newY - imageStartOrigin.y;
|
||||
|
||||
// Action based on drag distance
|
||||
if (fabsf(dY) > self.frame.size.height / 3)
|
||||
{
|
||||
// Reset photo to timeline position and exit from browser view
|
||||
[[self firstAvailableUIViewController] performSelector:@selector(exitBrowserView:) withObject:self];
|
||||
} else
|
||||
{
|
||||
// Reset photo to center of scrollview
|
||||
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveLinear
|
||||
animations:^{
|
||||
[self setFrame:newFrame];
|
||||
[[(MWPhotoBrowser *)[self firstAvailableUIViewController] screenshot] setAlpha:0.0];
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch (tapCount) {
|
||||
case 1:
|
||||
[self handleSingleTap:touch];
|
||||
|
||||
0
MWPhotoBrowser/Classes/MWTapDetectingView.h
Normal file → Executable file
0
MWPhotoBrowser/Classes/MWTapDetectingView.h
Normal file → Executable file
0
MWPhotoBrowser/Classes/MWTapDetectingView.m
Normal file → Executable file
0
MWPhotoBrowser/Classes/MWTapDetectingView.m
Normal file → Executable file
0
MWPhotoBrowser/Classes/MWZoomingScrollView.h
Normal file → Executable file
0
MWPhotoBrowser/Classes/MWZoomingScrollView.h
Normal file → Executable file
6
MWPhotoBrowser/Classes/MWZoomingScrollView.m
Normal file → Executable file
6
MWPhotoBrowser/Classes/MWZoomingScrollView.m
Normal file → Executable file
@@ -38,14 +38,14 @@
|
||||
_tapView = [[MWTapDetectingView alloc] initWithFrame:self.bounds];
|
||||
_tapView.tapDelegate = self;
|
||||
_tapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
_tapView.backgroundColor = [UIColor blackColor];
|
||||
_tapView.backgroundColor = [UIColor clearColor];
|
||||
[self addSubview:_tapView];
|
||||
|
||||
// Image view
|
||||
_photoImageView = [[MWTapDetectingImageView alloc] initWithFrame:CGRectZero];
|
||||
_photoImageView.tapDelegate = self;
|
||||
_photoImageView.contentMode = UIViewContentModeCenter;
|
||||
_photoImageView.backgroundColor = [UIColor blackColor];
|
||||
_photoImageView.backgroundColor = [UIColor clearColor];
|
||||
[self addSubview:_photoImageView];
|
||||
|
||||
// Spinner
|
||||
@@ -56,7 +56,7 @@
|
||||
[self addSubview:_spinner];
|
||||
|
||||
// Setup
|
||||
self.backgroundColor = [UIColor blackColor];
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.delegate = self;
|
||||
self.showsHorizontalScrollIndicator = NO;
|
||||
self.showsVerticalScrollIndicator = NO;
|
||||
|
||||
19
MWPhotoBrowser/Classes/UIView+viewController.h
Normal file
19
MWPhotoBrowser/Classes/UIView+viewController.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// UIView+viewController.h
|
||||
// FB Gallery
|
||||
//
|
||||
// Created by Philip Yu on 5/3/13.
|
||||
// Copyright (c) 2013 Philip Yu. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIView (viewController)
|
||||
|
||||
- (UIViewController *) firstAvailableUIViewController;
|
||||
- (float) findViewOffsetToSuperviewClass:(Class)class;
|
||||
- (void) shiftViewPositionY:(float)offset;
|
||||
+ (UIImageView*)screenshotForScreen;
|
||||
+ (UIImageView*)screenshotForView:(UIView*) view;
|
||||
|
||||
@end
|
||||
110
MWPhotoBrowser/Classes/UIView+viewController.m
Normal file
110
MWPhotoBrowser/Classes/UIView+viewController.m
Normal file
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// UIView+viewController.m
|
||||
// FB Gallery
|
||||
//
|
||||
// Created by Philip Yu on 5/3/13.
|
||||
// Copyright (c) 2013 Philip Yu. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIView+viewController.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@implementation UIView (viewController)
|
||||
|
||||
- (UIViewController *) firstAvailableUIViewController {
|
||||
// convenience function for casting and to "mask" the recursive function
|
||||
return (UIViewController *)[self traverseResponderChainForUIViewController];
|
||||
}
|
||||
|
||||
- (id) traverseResponderChainForUIViewController {
|
||||
id nextResponder = [self nextResponder];
|
||||
if ([nextResponder isKindOfClass:[UIViewController class]]) {
|
||||
return nextResponder;
|
||||
} else if ([nextResponder isKindOfClass:[UIView class]]) {
|
||||
return [nextResponder traverseResponderChainForUIViewController];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (float) traverseViewChainForView:(UIView *)view toViewClass:(Class)class offset:(float)offset
|
||||
{
|
||||
if ([view.superview isKindOfClass:class])
|
||||
{
|
||||
return view.superview.frame.origin.y + offset;
|
||||
} else if ([view.superview isKindOfClass:[UIView class]]) {
|
||||
return [self traverseViewChainForView:view.superview toViewClass:class offset:view.superview.frame.origin.y + offset];
|
||||
} else {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
- (float) findViewOffsetToSuperviewClass:(Class)class
|
||||
{
|
||||
return [self traverseViewChainForView:self toViewClass:class offset:0];
|
||||
}
|
||||
|
||||
- (void) shiftViewPositionY:(float)offset
|
||||
{
|
||||
CGRect tempFrame = self.frame;
|
||||
tempFrame.origin.y += offset;
|
||||
[self setFrame:tempFrame];
|
||||
}
|
||||
|
||||
+ (UIImageView*)screenshotForScreen{
|
||||
UIView *view = [UIApplication sharedApplication].keyWindow;
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, [[UIScreen mainScreen] scale]);
|
||||
|
||||
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
CGFloat barHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
|
||||
|
||||
if ([UIApplication sharedApplication].statusBarHidden == NO) {
|
||||
|
||||
CGFloat scale = [[UIScreen mainScreen] scale];
|
||||
CGRect rect = CGRectMake(0, barHeight * scale, view.bounds.size.width * scale, (view.bounds.size.height - barHeight) * scale);
|
||||
CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, rect);
|
||||
image = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
|
||||
}
|
||||
|
||||
UIImageView* screenshot = [[UIImageView alloc] initWithImage:image];
|
||||
screenshot.frame = CGRectMake(0, 0, view.bounds.size.width, view.bounds.size.height - barHeight);
|
||||
|
||||
return screenshot;
|
||||
}
|
||||
|
||||
+ (UIImageView*)screenshotForView:(UIView*) view {
|
||||
|
||||
bool viewHidden = 0;
|
||||
|
||||
if (view.hidden == YES) {
|
||||
viewHidden = 1;
|
||||
[view setHidden:NO];
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, [[UIScreen mainScreen] scale]);
|
||||
|
||||
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
// if ([UIApplication sharedApplication].statusBarHidden == NO) {
|
||||
// CGFloat barHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
|
||||
// CGFloat scale = [[UIScreen mainScreen] scale];
|
||||
// CGRect rect = CGRectMake(0, barHeight * scale, view.bounds.size.width * scale, (view.bounds.size.height - barHeight) * scale);
|
||||
// CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, rect);
|
||||
// image = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
|
||||
// }
|
||||
|
||||
UIImageView* screenshot = [[UIImageView alloc] initWithImage:image];
|
||||
screenshot.frame = CGRectMake(0, 0, view.bounds.size.width, view.bounds.size.height);
|
||||
|
||||
if (viewHidden) [view setHidden:YES];
|
||||
|
||||
return screenshot;
|
||||
}
|
||||
|
||||
@end
|
||||
18
MWPhotoBrowserFBGallery.podspec
Normal file
18
MWPhotoBrowserFBGallery.podspec
Normal file
@@ -0,0 +1,18 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'MWPhotoBrowser'
|
||||
s.version = '1.0.1'
|
||||
s.license = 'MIT'
|
||||
s.summary = 'A simple iOS photo browser.'
|
||||
s.homepage = 'https://github.com/mwaterfall/MWPhotoBrowser'
|
||||
s.author = { 'Michael Waterfall' => 'mw@d3i.com' }
|
||||
s.source = { :git => 'https://github.com/zhigang1992/MWPhotoBrowser.git', :tag => '1.0.2' }
|
||||
s.platform = :ios
|
||||
|
||||
s.source_files = 'MWPhotoBrowser/Classes'
|
||||
s.resources = "MWPhotoBrowser/MWPhotoBrowser.bundle"
|
||||
|
||||
s.frameworks = 'MessageUI', 'ImageIO'
|
||||
|
||||
s.dependency 'SDWebImage','~>3.2'
|
||||
s.dependency 'MBProgressHUD'
|
||||
end
|
||||
Reference in New Issue
Block a user