├── .gitignore ├── LICENSE ├── README.md ├── SRPictureBrowser ├── SRPictureBrowser.h ├── SRPictureBrowser.m ├── SRPictureCell.h ├── SRPictureCell.m ├── SRPictureIndicator.h ├── SRPictureIndicator.m ├── SRPictureManager.h ├── SRPictureManager.m ├── SRPictureModel.h ├── SRPictureModel.m ├── SRPictureView.h └── SRPictureView.m ├── SRPictureBrowserDemo ├── SRPictureBrowserDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── SRPictureBrowserDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ └── Main.storyboard │ ├── GameofThrones │ ├── GameofThrones1.jpg │ ├── GameofThrones2.jpg │ ├── GameofThrones3.jpg │ ├── GameofThrones4.jpg │ ├── GameofThrones5.jpg │ ├── GameofThrones6.jpg │ ├── GameofThrones7.jpg │ ├── GameofThrones8.jpg │ └── GameofThrones9.jpg │ ├── GameofThrones1.jpg │ ├── GameofThrones2.jpg │ ├── GameofThrones3.jpg │ ├── GameofThrones4.jpg │ ├── GameofThrones5.jpg │ ├── GameofThrones6.jpg │ ├── GameofThrones7.jpg │ ├── GameofThrones8.jpg │ ├── GameofThrones9.jpg │ ├── Info.plist │ ├── LaunchScreen.storyboard │ ├── SRActionSheet.h │ ├── SRActionSheet.m │ ├── SRPictureHUD.h │ ├── SRPictureHUD.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m └── screenshots.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Willing Guo 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SRPictureBrowser 2 | 3 | Light-weight and easy-to-extend picture browser. Not rely on any third-party libraries to download and cache picture. 4 | 5 | ![image](./screenshots.png) 6 | 7 | ## Features 8 | 9 | * [x] There are zoom animation effects when showing or dismissing the picture browser. 10 | * [x] There is cyclic animation effect when loading the network picture. 11 | * [x] Support kneading or double tapping the view to zoom the picture. 12 | * [x] Support dragging down the picture to dismiss the picture browser. 13 | * [x] Support long pressing the picture to evoke other interactive options. 14 | 15 | ## APIs 16 | 17 | ````objc 18 | /** 19 | Displays a picture browser with pictureModels, currentIndex and delegate. 20 | 21 | @param pictureModels The models which contains SRPictureModel. 22 | @param currentIndex The index of model which will show firstly. 23 | @param delegate The receiver’s delegate object. 24 | */ 25 | + (void)sr_showPictureBrowserWithModels:(NSArray *)pictureModels currentIndex:(NSInteger)currentIndex delegate:(id)delegate; 26 | 27 | /** 28 | Creates and returns a model of picture information. 29 | 30 | @param picURLString The URL string of the picture. 31 | @param containerView The super view of the picture view. 32 | @param positionInContainer The picture view's position in its super view. 33 | @param index The index of this picture in all pictures. 34 | @return A picture model. 35 | */ 36 | + (instancetype)sr_pictureModelWithPicURLString:(NSString *)picURLString containerView:(UIView *)containerView positionInContainer:(CGRect)positionInContainer index:(NSInteger)index; 37 | ```` 38 | 39 | ## Usage 40 | 41 | ````objc 42 | UIImageView *tapedImageView = (UIImageView *)tapGestureRecognizer.view; 43 | NSMutableArray *imageBrowserModels = [[NSMutableArray alloc] init]; 44 | for (NSInteger i = 0; i < self.picURLStrings.count; i ++) { 45 | SRPictureModel *imageBrowserModel = [SRPictureModel sr_pictureModelWithPicURLString:self.picURLStrings[i] 46 | containerView:tapedImageView.superview 47 | positionInContainer:[self.imageViewFrames[i] CGRectValue] 48 | index:i]; 49 | [imageBrowserModels addObject:imageBrowserModel]; 50 | } 51 | [SRPictureBrowser sr_showPictureBrowserWithModels:imageBrowserModels currentIndex:tapedImageView.tag delegate:self]; 52 | ```` -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureBrowser.h: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureBrowser.h 3 | // SRPhotoBrowser 4 | // 5 | // Created by https://github.com/guowilling on 16/12/24. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class SRPictureBrowser; 12 | 13 | @protocol SRPictureBrowserDelegate 14 | 15 | @optional 16 | - (void)pictureBrowserDidShow:(SRPictureBrowser *)pictureBrowser; 17 | - (void)pictureBrowserDidLongPressPicture:(UIImage *)picture; 18 | - (void)pictureBrowserDidDismiss; 19 | 20 | @end 21 | 22 | @interface SRPictureBrowser : UIView 23 | 24 | /** 25 | Displays a picture browser with pictureModels, currentIndex and delegate. 26 | 27 | @param pictureModels The models which contains SRPictureModel. 28 | @param currentIndex The index of model which will show firstly. 29 | @param delegate The receiver’s delegate object. 30 | */ 31 | + (void)sr_showPictureBrowserWithModels:(NSArray *)pictureModels currentIndex:(NSInteger)currentIndex delegate:(id)delegate; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureBrowser.m: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureBrowser.m 3 | // SRPhotoBrowser 4 | // 5 | // Created by https://github.com/guowilling on 16/12/24. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import "SRPictureBrowser.h" 10 | #import "SRPictureCell.h" 11 | #import "SRPictureView.h" 12 | #import "SRPictureModel.h" 13 | #import "SRPictureManager.h" 14 | #import "SRPictureHUD.h" 15 | 16 | @interface SRPictureBrowser () 17 | 18 | @property (nonatomic, weak) id delegate; 19 | 20 | @property (nonatomic, copy) NSArray *pictureModels; 21 | 22 | @property (nonatomic, strong) UIImageView *screenImageView; 23 | 24 | @property (nonatomic, strong) UICollectionView *collectionView; 25 | @property (nonatomic, strong) UIPageControl *pageControl; 26 | 27 | @property (nonatomic, strong) SRPictureView *currentPictureView; 28 | 29 | @property (nonatomic, assign) NSInteger currentIndex; 30 | 31 | @end 32 | 33 | @implementation SRPictureBrowser 34 | 35 | + (void)sr_showPictureBrowserWithModels:(NSArray *)pictureModels currentIndex:(NSInteger)currentIndex delegate:(id)delegate { 36 | SRPictureBrowser *pictureBrowser = [[self alloc] initWithModels:pictureModels currentIndex:currentIndex delegate:delegate]; 37 | [pictureBrowser show]; 38 | } 39 | 40 | #pragma mark - Initialize 41 | 42 | - (id)initWithModels:(NSArray *)pictureModels currentIndex:(NSInteger)currentIndex delegate:(id)delegate { 43 | if (self = [super initWithFrame:[UIScreen mainScreen].bounds]) { 44 | _pictureModels = pictureModels; 45 | _currentIndex = currentIndex; 46 | _delegate = delegate; 47 | for (SRPictureModel *picModel in _pictureModels) { 48 | if (picModel.index == _currentIndex) { 49 | picModel.firstShow = YES; 50 | break; 51 | } 52 | } 53 | [self setup]; 54 | } 55 | return self; 56 | } 57 | 58 | - (void)setup { 59 | self.backgroundColor = [UIColor blackColor]; 60 | 61 | CGRect screenBounds = [UIScreen mainScreen].bounds; 62 | 63 | [self addSubview:({ 64 | UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].bounds.size, YES, [UIScreen mainScreen].scale); 65 | [[UIApplication sharedApplication].keyWindow.layer renderInContext:UIGraphicsGetCurrentContext()]; 66 | UIImage *currentScreenImage = UIGraphicsGetImageFromCurrentImageContext(); 67 | UIGraphicsEndImageContext(); 68 | _screenImageView = [[UIImageView alloc] initWithFrame:screenBounds]; 69 | _screenImageView.image = currentScreenImage; 70 | _screenImageView.hidden = YES; 71 | _screenImageView; 72 | })]; 73 | 74 | [self addSubview:({ 75 | CGFloat flowLayoutWidth = screenBounds.size.width + 10; 76 | UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init]; 77 | flowLayout.itemSize = CGSizeMake(flowLayoutWidth, screenBounds.size.height); 78 | flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal; 79 | flowLayout.minimumLineSpacing = 0.0f; 80 | flowLayout.sectionInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f); 81 | _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, flowLayoutWidth, screenBounds.size.height) collectionViewLayout:flowLayout]; 82 | _collectionView.backgroundColor = [UIColor clearColor]; 83 | _collectionView.delegate = self; 84 | _collectionView.dataSource = self; 85 | _collectionView.showsHorizontalScrollIndicator = NO; 86 | _collectionView.showsVerticalScrollIndicator = NO; 87 | _collectionView.pagingEnabled = YES; 88 | [_collectionView registerClass:[SRPictureCell class] forCellWithReuseIdentifier:pictureViewID]; 89 | [_collectionView setContentOffset:CGPointMake(self.currentIndex * flowLayoutWidth, 0.0f) animated:NO]; 90 | _collectionView; 91 | })]; 92 | 93 | [self addSubview:({ 94 | _pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, screenBounds.size.height - 40 - 10, screenBounds.size.width, 40)]; 95 | _pageControl.numberOfPages = self.pictureModels.count; 96 | _pageControl.currentPage = self.currentIndex; 97 | _pageControl.userInteractionEnabled = NO; 98 | if (_pictureModels.count == 1) { 99 | _pageControl.hidden = YES; 100 | } 101 | _pageControl; 102 | })]; 103 | } 104 | 105 | #pragma mark - Animation 106 | 107 | - (void)show { 108 | [[UIApplication sharedApplication] setStatusBarHidden:YES]; 109 | 110 | [[UIApplication sharedApplication].keyWindow addSubview:self]; 111 | 112 | if ([self.delegate respondsToSelector:@selector(pictureBrowserDidShow:)]) { 113 | [self.delegate pictureBrowserDidShow:self]; 114 | } 115 | } 116 | 117 | - (void)dismiss { 118 | [[UIApplication sharedApplication] setStatusBarHidden:NO]; 119 | 120 | _screenImageView.hidden = NO; 121 | _pageControl.hidden = YES; 122 | 123 | if (self.currentPictureView.zoomScale != 1.0) { 124 | self.currentPictureView.zoomScale = 1.0; 125 | } 126 | 127 | [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ 128 | self.currentPictureView.imageView.frame = self.currentPictureView.pictureModel.originPosition; 129 | } completion:^(BOOL finished) { 130 | if ([self.delegate respondsToSelector:@selector(pictureBrowserDidDismiss)]) { 131 | [self.delegate pictureBrowserDidDismiss]; 132 | } 133 | [self removeFromSuperview]; 134 | }]; 135 | } 136 | 137 | #pragma mark - UICollectionViewDataSource 138 | 139 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 140 | return self.pictureModels.count; 141 | } 142 | 143 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 144 | SRPictureCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:pictureViewID forIndexPath:indexPath]; 145 | cell.delegate = self; 146 | cell.pictureView.pictureViewDelegate = self; 147 | cell.pictureModel = self.pictureModels[indexPath.row]; 148 | if (!_currentPictureView) { 149 | _currentPictureView = cell.pictureView; 150 | } 151 | return cell; 152 | } 153 | 154 | #pragma mark - UIScrollViewDelegate 155 | 156 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { 157 | NSInteger index = scrollView.contentOffset.x / [UIScreen mainScreen].bounds.size.width; 158 | self.currentIndex = index; 159 | self.pageControl.currentPage = index; 160 | 161 | NSArray *cells = [self.collectionView visibleCells]; 162 | if (cells.count == 0) { 163 | return; 164 | } 165 | SRPictureCell *cell = [cells objectAtIndex:0]; 166 | if (self.currentPictureView == cell.pictureView) { 167 | return; 168 | } 169 | self.currentPictureView = cell.pictureView; 170 | 171 | if (self.currentIndex + 1 < self.pictureModels.count) { 172 | SRPictureModel *nextModel = [self.pictureModels objectAtIndex:self.currentIndex + 1]; 173 | [SRPictureManager prefetchDownloadPicture:nextModel.picURLString success:^(UIImage *picture) { 174 | nextModel.picture = picture; 175 | }]; 176 | } 177 | if (self.currentIndex - 1 >= 0) { 178 | SRPictureModel *preModel = [self.pictureModels objectAtIndex:self.currentIndex - 1]; 179 | [SRPictureManager prefetchDownloadPicture:preModel.picURLString success:^(UIImage *picture) { 180 | preModel.picture = picture; 181 | }]; 182 | } 183 | } 184 | 185 | #pragma mark - SRPictureCellDelegate 186 | 187 | - (void)pictureCellDidPanToAlpha:(CGFloat)alpha { 188 | self.backgroundColor = [UIColor colorWithWhite:0 alpha:alpha]; 189 | self.pageControl.alpha = alpha; 190 | } 191 | 192 | - (void)pictureCellDidPanToDismiss { 193 | [[UIApplication sharedApplication] setStatusBarHidden:NO]; 194 | if ([self.delegate respondsToSelector:@selector(pictureBrowserDidDismiss)]) { 195 | [self.delegate pictureBrowserDidDismiss]; 196 | } 197 | [self removeFromSuperview]; 198 | } 199 | 200 | #pragma mark - SRPictureViewDelegate 201 | 202 | - (void)pictureViewDidTap { 203 | [self dismiss]; 204 | } 205 | 206 | - (void)pictureViewDidLongPress { 207 | if ([self.delegate respondsToSelector:@selector(pictureBrowserDidLongPressPicture:)]) { 208 | [self.delegate pictureBrowserDidLongPressPicture:self.currentPictureView.imageView.image]; 209 | } 210 | } 211 | 212 | @end 213 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureCell.h 3 | // SRPhotoBrowser 4 | // 5 | // Created by https://github.com/guowilling on 16/12/24. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class SRPictureModel, SRPictureView; 12 | 13 | @protocol SRPictureCellDelegate 14 | 15 | @optional 16 | 17 | - (void)pictureCellDidPanToAlpha:(CGFloat)alpha; 18 | - (void)pictureCellDidPanToDismiss; 19 | 20 | @end 21 | 22 | static NSString * const pictureViewID = @"SRPictureView"; 23 | 24 | @interface SRPictureCell : UICollectionViewCell 25 | 26 | @property (nonatomic, weak) id delegate; 27 | 28 | @property (nonatomic, strong) SRPictureModel *pictureModel; 29 | 30 | @property (nonatomic, strong) SRPictureView *pictureView; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureCell.m 3 | // SRPhotoBrowser 4 | // 5 | // Created by https://github.com/guowilling on 16/12/24. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import "SRPictureCell.h" 10 | #import "SRPictureModel.h" 11 | #import "SRPictureView.h" 12 | 13 | #define kPanToDimissOffsetY 200 14 | 15 | @implementation SRPictureCell 16 | 17 | - (id)initWithFrame:(CGRect)frame { 18 | if (self = [super initWithFrame:frame]) { 19 | self.backgroundColor = [UIColor clearColor]; 20 | _pictureView = [[SRPictureView alloc] initWithFrame:[UIScreen mainScreen].bounds]; 21 | [_pictureView.panGestureRecognizer addTarget:self action:@selector(scrollViewPanAction:)]; 22 | [self.contentView addSubview:_pictureView]; 23 | } 24 | return self; 25 | } 26 | 27 | - (void)setPictureModel:(SRPictureModel *)pictureModel { 28 | _pictureModel = pictureModel; 29 | 30 | _pictureView.pictureModel = pictureModel; 31 | } 32 | 33 | - (void)scrollViewPanAction:(UIPanGestureRecognizer*)pan { 34 | if (_pictureView.zoomScale != 1.0) { 35 | return; 36 | } 37 | if (_pictureView.contentOffset.y > 0) { 38 | return; 39 | } 40 | if (pan.state == UIGestureRecognizerStateEnded) { 41 | if (ABS(_pictureView.contentOffset.y) < kPanToDimissOffsetY) { 42 | [UIView animateWithDuration:0.5 animations:^{ 43 | _pictureView.contentInset = UIEdgeInsetsZero; 44 | if ([self.delegate respondsToSelector:@selector(pictureCellDidPanToAlpha:)]) { 45 | [self.delegate pictureCellDidPanToAlpha:1.0]; 46 | } 47 | }]; 48 | } else { 49 | [UIView animateWithDuration:0.5 animations:^{ 50 | CGRect frame = _pictureView.imageView.frame; 51 | frame.origin.y = self.bounds.size.height; 52 | _pictureView.imageView.frame = frame; 53 | if ([self.delegate respondsToSelector:@selector(pictureCellDidPanToAlpha:)]) { 54 | [self.delegate pictureCellDidPanToAlpha:0]; 55 | } 56 | } completion:^(BOOL finished) { 57 | if ([self.delegate respondsToSelector:@selector(pictureCellDidPanToDismiss)]) { 58 | [self.delegate pictureCellDidPanToDismiss]; 59 | } 60 | }]; 61 | } 62 | } else { 63 | _pictureView.contentInset = UIEdgeInsetsMake(-_pictureView.contentOffset.y, 0, 0, 0); 64 | CGFloat alpha = 1 - ABS(_pictureView.contentOffset.y / (self.bounds.size.height)); 65 | if ([self.delegate respondsToSelector:@selector(pictureCellDidPanToAlpha:)]) { 66 | [self.delegate pictureCellDidPanToAlpha:alpha]; 67 | } 68 | } 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureIndicator.h: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureIndicator.h 3 | // SRPhotoBrowser 4 | // 5 | // Created by https://github.com/guowilling on 16/12/24. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SRPictureIndicator : UIView 12 | 13 | + (instancetype)showInView:(UIView *)view; 14 | 15 | - (void)hide; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureIndicator.m: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureIndicator.m 3 | // SRPhotoBrowser 4 | // 5 | // Created by https://github.com/guowilling on 16/12/24. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import "SRPictureIndicator.h" 10 | 11 | static NSString * const rotationAnimationKey = @"rotationAnimation"; 12 | static NSString * const strokeAnimationKey = @"strokeAnimation"; 13 | 14 | @interface SRPictureIndicator () 15 | 16 | @property (nonatomic, strong) CAShapeLayer *progressLayer; 17 | 18 | @property (nonatomic, assign, getter=isAnimating) BOOL animating; 19 | 20 | @end 21 | 22 | @implementation SRPictureIndicator 23 | 24 | - (void)dealloc { 25 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; 26 | } 27 | 28 | + (instancetype)showInView:(UIView *)view { 29 | if (!view) { 30 | view = [UIApplication sharedApplication].keyWindow; 31 | } 32 | SRPictureIndicator *pictureIndicator = [[SRPictureIndicator alloc] initWithFrame:CGRectMake(0, 0, 50, 50)]; 33 | [view addSubview:pictureIndicator]; 34 | [pictureIndicator startAnimating]; 35 | return pictureIndicator; 36 | } 37 | 38 | - (void)hide { 39 | [self stopAnimating]; 40 | [self removeFromSuperview]; 41 | } 42 | 43 | - (instancetype)initWithFrame:(CGRect)frame { 44 | if (self = [super initWithFrame:frame]) { 45 | self.center = [UIApplication sharedApplication].keyWindow.center; 46 | self.tintColor = [UIColor colorWithWhite:1.0 alpha:0.75]; 47 | _progressLayer = [CAShapeLayer layer]; 48 | _progressLayer.strokeColor = self.tintColor.CGColor; 49 | _progressLayer.fillColor = nil; 50 | _progressLayer.lineWidth = 2.0; 51 | [self.layer addSublayer:_progressLayer]; 52 | 53 | [[NSNotificationCenter defaultCenter] addObserver:self 54 | selector:@selector(applicationDidBecomeActive) 55 | name:UIApplicationDidBecomeActiveNotification 56 | object:nil]; 57 | } 58 | return self; 59 | } 60 | 61 | - (void)layoutSubviews { 62 | [super layoutSubviews]; 63 | 64 | self.progressLayer.frame = self.bounds; 65 | CGPoint center = CGPointMake(self.frame.size.width * 0.5, self.frame.size.height * 0.5); 66 | CGFloat radius = MIN(center.x, center.y) - self.progressLayer.lineWidth * 0.5; 67 | UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:2 * M_PI clockwise:YES]; 68 | self.progressLayer.path = path.CGPath; 69 | self.progressLayer.strokeStart = 0.0; 70 | self.progressLayer.strokeEnd = 0.0; 71 | } 72 | 73 | - (void)tintColorDidChange { 74 | [super tintColorDidChange]; 75 | 76 | self.progressLayer.strokeColor = self.tintColor.CGColor; 77 | } 78 | 79 | - (void)startAnimating { 80 | CABasicAnimation *animation = [CABasicAnimation animation]; 81 | animation.keyPath = @"transform.rotation"; 82 | animation.duration = 4.f; 83 | animation.fromValue = @(0.f); 84 | animation.toValue = @(2 * M_PI); 85 | animation.repeatCount = INFINITY; 86 | [self.progressLayer addAnimation:animation forKey:rotationAnimationKey]; 87 | 88 | CABasicAnimation *headAnimation = [CABasicAnimation animation]; 89 | headAnimation.keyPath = @"strokeStart"; 90 | headAnimation.duration = 1.f; 91 | headAnimation.fromValue = @(0.f); 92 | headAnimation.toValue = @(0.25f); 93 | headAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 94 | 95 | CABasicAnimation *tailAnimation = [CABasicAnimation animation]; 96 | tailAnimation.keyPath = @"strokeEnd"; 97 | tailAnimation.duration = 1.f; 98 | tailAnimation.fromValue = @(0.f); 99 | tailAnimation.toValue = @(1.f); 100 | tailAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 101 | 102 | CABasicAnimation *endHeadAnimation = [CABasicAnimation animation]; 103 | endHeadAnimation.keyPath = @"strokeStart"; 104 | endHeadAnimation.beginTime = 1.f; 105 | endHeadAnimation.duration = 0.5f; 106 | endHeadAnimation.fromValue = @(0.25f); 107 | endHeadAnimation.toValue = @(1.f); 108 | endHeadAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 109 | 110 | CABasicAnimation *endTailAnimation = [CABasicAnimation animation]; 111 | endTailAnimation.keyPath = @"strokeEnd"; 112 | endTailAnimation.beginTime = 1.f; 113 | endTailAnimation.duration = 0.5f; 114 | endTailAnimation.fromValue = @(1.f); 115 | endTailAnimation.toValue = @(1.f); 116 | endTailAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 117 | 118 | CAAnimationGroup *animations = [CAAnimationGroup animation]; 119 | animations.duration = 1.5; 120 | animations.animations = @[headAnimation, tailAnimation, endHeadAnimation, endTailAnimation]; 121 | animations.repeatCount = INFINITY; 122 | [self.progressLayer addAnimation:animations forKey:strokeAnimationKey]; 123 | } 124 | 125 | - (void)stopAnimating { 126 | [self.progressLayer removeAnimationForKey:rotationAnimationKey]; 127 | [self.progressLayer removeAnimationForKey:strokeAnimationKey]; 128 | } 129 | 130 | - (void)applicationDidBecomeActive { 131 | [self stopAnimating]; 132 | [self startAnimating]; 133 | } 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureManager.h 3 | // SRPictureBrowserDemo 4 | // 5 | // Created by https://github.com/guowilling on 17/5/3. 6 | // Copyright © 2017年 SR. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface SRPictureManager : NSObject 13 | 14 | + (UIImage *)pictureFromSandbox:(NSString *)URLString; 15 | 16 | + (void)downloadPicture:(NSString *)URLString success:(void (^)(UIImage *picture))success failure:(void (^)(NSError *error))failure; 17 | 18 | + (void)prefetchDownloadPicture:(NSString *)URLString success:(void (^)(UIImage *picture))success; 19 | 20 | + (void)clearCachedPictures; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureManager.m 3 | // SRPictureBrowserDemo 4 | // 5 | // Created by https://github.com/guowilling on 17/5/3. 6 | // Copyright © 2017年 SR. All rights reserved. 7 | // 8 | 9 | #import "SRPictureManager.h" 10 | 11 | #define SRPicturesDirectory [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] \ 12 | stringByAppendingPathComponent:NSStringFromClass([self class])] 13 | 14 | //#define SRPictureName(URLString) [URLString lastPathComponent] 15 | 16 | //#define SRPicturePath(URLString) [SRPicturesDirectory stringByAppendingPathComponent:SRPictureName(URLString)] 17 | 18 | @implementation SRPictureManager 19 | 20 | + (void)load { 21 | NSString *directory = SRPicturesDirectory; 22 | BOOL isDirectory = NO; 23 | NSFileManager *fileManager = [NSFileManager defaultManager]; 24 | BOOL isExists = [fileManager fileExistsAtPath:directory isDirectory:&isDirectory]; 25 | if (!isExists || !isDirectory) { 26 | [fileManager createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:nil]; 27 | } 28 | 29 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearCachedPictures) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; 30 | } 31 | 32 | + (NSString *)picturePath:(NSString *)URLString { 33 | NSString *pictureName = nil; 34 | NSString *query = [NSURL URLWithString:URLString].query; 35 | if (query) { 36 | pictureName = [URLString stringByReplacingOccurrencesOfString:query withString:@""]; 37 | pictureName = [pictureName stringByReplacingOccurrencesOfString:@"?" withString:@""]; 38 | } 39 | pictureName = pictureName.lastPathComponent; 40 | return [SRPicturesDirectory stringByAppendingPathComponent:pictureName]; 41 | } 42 | 43 | + (UIImage *)pictureFromSandbox:(NSString *)URLString { 44 | NSString *picturePath = [self picturePath:URLString]; 45 | NSData *data = [NSData dataWithContentsOfFile:picturePath]; 46 | if (data.length > 0 ) { 47 | return [UIImage imageWithData:data]; 48 | } else { 49 | [[NSFileManager defaultManager] removeItemAtPath:picturePath error:NULL]; 50 | } 51 | return nil; 52 | } 53 | 54 | + (void)downloadPicture:(NSString *)URLString success:(void (^)(UIImage *picture))success failure:(void (^)(NSError *error))failure { 55 | [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:URLString] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 56 | if (error) { 57 | if (failure) { 58 | failure(error); 59 | } 60 | return; 61 | } 62 | [data writeToFile:[self picturePath:URLString] atomically:YES]; 63 | UIImage *picture = [UIImage imageWithData:data]; 64 | dispatch_async(dispatch_get_main_queue(), ^{ 65 | if (success) { 66 | success(picture); 67 | } 68 | }); 69 | }] resume]; 70 | } 71 | 72 | + (void)prefetchDownloadPicture:(NSString *)URLString success:(void (^)(UIImage *picture))success { 73 | [self downloadPicture:URLString success:success failure:nil]; 74 | } 75 | 76 | + (void)clearCachedPictures { 77 | NSFileManager *fileManager = [NSFileManager defaultManager]; 78 | NSArray *fileNames = [fileManager contentsOfDirectoryAtPath:SRPicturesDirectory error:nil]; 79 | for (NSString *fileName in fileNames) { 80 | [fileManager removeItemAtPath:[SRPicturesDirectory stringByAppendingPathComponent:fileName] error:nil]; 81 | } 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureModel.h 3 | // SRPhotoBrowser 4 | // 5 | // Created by https://github.com/guowilling on 16/12/24. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SRPictureModel : UIView 12 | 13 | @property (nonatomic, copy) NSString *picURLString; 14 | 15 | @property (nonatomic, assign) CGRect originPosition; 16 | 17 | @property (nonatomic, assign, readonly) CGRect destinationPosition; 18 | 19 | @property (nonatomic, assign) NSInteger index; 20 | 21 | @property (nonatomic, assign, getter=isFirstShow) BOOL firstShow; 22 | 23 | @property (nonatomic, strong) UIImage *picture; 24 | 25 | /** 26 | Creates and returns a picture model with picURLString, containerView, positionInContainer and index. 27 | 28 | @param picURLString The URL string of the picture. 29 | @param containerView The super view of the picture view. 30 | @param positionInContainer The picture view's position in its super view. 31 | @param index The index of this picture in all pictures. 32 | @return A picture model. 33 | */ 34 | + (instancetype)sr_pictureModelWithPicURLString:(NSString *)picURLString containerView:(UIView *)containerView positionInContainer:(CGRect)positionInContainer index:(NSInteger)index; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureModel.m 3 | // SRPhotoBrowser 4 | // 5 | // Created by https://github.com/guowilling on 16/12/24. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import "SRPictureModel.h" 10 | #import "SRPictureManager.h" 11 | 12 | @interface SRPictureModel () 13 | 14 | @property (nonatomic, assign, readwrite) CGRect destinationPosition; 15 | 16 | @end 17 | 18 | @implementation SRPictureModel 19 | 20 | + (instancetype)sr_pictureModelWithPicURLString:(NSString *)picURLString containerView:(UIView *)containerView positionInContainer:(CGRect)positionInContainer index:(NSInteger)index { 21 | SRPictureModel *pictureModel = [[SRPictureModel alloc] init]; 22 | pictureModel.picURLString = picURLString; 23 | if (containerView) { 24 | pictureModel.originPosition = [containerView convertRect:positionInContainer toView:[UIApplication sharedApplication].keyWindow]; 25 | } else { 26 | pictureModel.originPosition = CGRectMake([UIScreen mainScreen].bounds.size.width * 0.5, [UIScreen mainScreen].bounds.size.height * 0.5, 0, 0); 27 | } 28 | pictureModel.index = index; 29 | [self calculateDestinationPositionWithPictureModel:pictureModel picture:nil]; 30 | return pictureModel; 31 | } 32 | 33 | + (void)calculateDestinationPositionWithPictureModel:(SRPictureModel *)pictureModel picture:(UIImage *)picture { 34 | if (!picture) { 35 | picture = [SRPictureManager pictureFromSandbox:pictureModel.picURLString]; 36 | pictureModel->_picture = picture; 37 | } 38 | if (!picture) { 39 | return; 40 | } 41 | CGFloat destinationPositionX = 0; 42 | CGFloat destinationPositionY = 0; 43 | CGFloat destinationPositionW = [UIScreen mainScreen].bounds.size.width; 44 | CGFloat destinationPositionH = destinationPositionW / picture.size.width * picture.size.height; 45 | if (destinationPositionH > [UIScreen mainScreen].bounds.size.height) { 46 | destinationPositionH = picture.size.height; 47 | } else { 48 | destinationPositionY = ([UIScreen mainScreen].bounds.size.height - destinationPositionH) * 0.5; 49 | } 50 | pictureModel.destinationPosition = CGRectMake(destinationPositionX, destinationPositionY, destinationPositionW, destinationPositionH); 51 | } 52 | 53 | - (void)setPicture:(UIImage *)picture { 54 | _picture = picture; 55 | 56 | [self.class calculateDestinationPositionWithPictureModel:self picture:picture]; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureView.h: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureView.h 3 | // SRPhotoBrowser 4 | // 5 | // Created by https://github.com/guowilling on 16/12/24. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class SRPictureModel; 12 | 13 | @protocol SRPictureViewDelegate 14 | 15 | @optional 16 | 17 | - (void)pictureViewDidTap; 18 | - (void)pictureViewDidLongPress; 19 | 20 | @end 21 | 22 | @interface SRPictureView : UIScrollView 23 | 24 | @property (nonatomic, weak) id pictureViewDelegate; 25 | 26 | @property (nonatomic, strong) SRPictureModel *pictureModel; 27 | 28 | @property (nonatomic, strong, readonly) UIImageView *imageView; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /SRPictureBrowser/SRPictureView.m: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureView.m 3 | // SRPhotoBrowser 4 | // 5 | // Created by https://github.com/guowilling on 16/12/24. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import "SRPictureView.h" 10 | #import "SRPictureModel.h" 11 | #import "SRPictureIndicator.h" 12 | #import "SRPictureManager.h" 13 | 14 | @interface SRPictureView () 15 | 16 | @property (nonatomic, strong) SRPictureIndicator *pictureIndicator; 17 | 18 | @end 19 | 20 | @implementation SRPictureView 21 | 22 | - (id)initWithFrame:(CGRect)frame { 23 | if (self = [super initWithFrame:frame]) { 24 | self.backgroundColor = [UIColor clearColor]; 25 | self.delegate = self; 26 | self.showsHorizontalScrollIndicator = NO; 27 | self.showsVerticalScrollIndicator = NO; 28 | self.maximumZoomScale = 2.0; 29 | self.minimumZoomScale = 1.0; 30 | self.alwaysBounceVertical = YES; 31 | 32 | _imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; 33 | _imageView.contentMode = UIViewContentModeScaleAspectFill; 34 | _imageView.clipsToBounds = YES; 35 | _imageView.userInteractionEnabled = YES; 36 | [self addSubview:_imageView]; 37 | 38 | [self setupGestures]; 39 | } 40 | return self; 41 | } 42 | 43 | - (void)setupGestures { 44 | UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; 45 | [self addGestureRecognizer:singleTap]; 46 | 47 | UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)]; 48 | doubleTap.numberOfTapsRequired = 2; 49 | [self.imageView addGestureRecognizer:doubleTap]; 50 | 51 | [singleTap requireGestureRecognizerToFail:doubleTap]; 52 | 53 | UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; 54 | [self addGestureRecognizer:longPress]; 55 | } 56 | 57 | - (void)setPictureModel:(SRPictureModel *)pictureModel { 58 | _pictureModel = pictureModel; 59 | 60 | self.zoomScale = 1.0; 61 | 62 | [self.pictureIndicator hide]; 63 | 64 | if (pictureModel.picture) { 65 | self.imageView.image = pictureModel.picture; 66 | if (pictureModel.isFirstShow) { 67 | self.imageView.frame = pictureModel.originPosition; 68 | self.contentSize = pictureModel.destinationPosition.size; 69 | [UIView animateWithDuration:0.3 delay:0.0 usingSpringWithDamping:0.7 initialSpringVelocity:0.0 options:0 animations:^{ 70 | self.imageView.frame = pictureModel.destinationPosition; 71 | } completion:nil]; 72 | } else { 73 | self.imageView.frame = pictureModel.destinationPosition; 74 | } 75 | } else { 76 | self.imageView.image = nil; 77 | self.pictureIndicator = [SRPictureIndicator showInView:self]; 78 | [SRPictureManager downloadPicture:pictureModel.picURLString success:^(UIImage *picture) { 79 | [self.pictureIndicator hide]; 80 | self.pictureModel.picture = picture; 81 | self.imageView.image = picture; 82 | self.imageView.frame = pictureModel.destinationPosition; 83 | self.contentSize = pictureModel.destinationPosition.size; 84 | } failure:^(NSError *error) { 85 | NSLog(@"downloadPicture error: %@", error); 86 | }]; 87 | } 88 | } 89 | 90 | #pragma mark - UIScrollViewDelegate 91 | 92 | - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { 93 | return self.imageView; 94 | } 95 | 96 | - (void)scrollViewDidZoom:(UIScrollView *)scrollView { 97 | CGFloat offsetX; 98 | if (scrollView.bounds.size.width > scrollView.contentSize.width) { 99 | offsetX = (scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5; 100 | } else { 101 | offsetX = 0; 102 | } 103 | 104 | CGFloat offsetY; 105 | if (scrollView.bounds.size.height > scrollView.contentSize.height) { 106 | offsetY = (scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5; 107 | } else { 108 | offsetY = 0; 109 | } 110 | 111 | self.imageView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, scrollView.contentSize.height * 0.5 + offsetY); 112 | } 113 | 114 | - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { 115 | [scrollView setZoomScale:scale animated:NO]; 116 | } 117 | 118 | #pragma mark - UIGestureRecognizerHandler 119 | 120 | - (void)handleSingleTap:(UITapGestureRecognizer *)gestureRecognizer { 121 | if (gestureRecognizer.numberOfTapsRequired == 1) { 122 | if ([self.pictureViewDelegate respondsToSelector:@selector(pictureViewDidTap)]) { 123 | [self.pictureViewDelegate pictureViewDidTap]; 124 | } 125 | } 126 | } 127 | 128 | - (void)handleDoubleTap:(UITapGestureRecognizer *)gestureRecognizer { 129 | if (gestureRecognizer.numberOfTapsRequired == 2) { 130 | if (self.zoomScale > 1) { 131 | CGRect zoomRect = [self zoomRectForScale:1.0 withCenter:[gestureRecognizer locationInView:self]]; 132 | [self zoomToRect:zoomRect animated:YES]; 133 | } else { 134 | CGRect zoomRect = [self zoomRectForScale:2.0 withCenter:[gestureRecognizer locationInView:self]]; 135 | [self zoomToRect:zoomRect animated:YES]; 136 | } 137 | } 138 | } 139 | 140 | - (void)handleLongPress:(UILongPressGestureRecognizer *)longPress { 141 | if (longPress.state == UIGestureRecognizerStateBegan) { 142 | if ([self.pictureViewDelegate respondsToSelector:@selector(pictureViewDidLongPress)]) { 143 | [self.pictureViewDelegate pictureViewDidLongPress]; 144 | } 145 | } 146 | } 147 | 148 | - (CGRect)zoomRectForScale:(CGFloat)scale withCenter:(CGPoint)center { 149 | CGRect zoomRect; 150 | zoomRect.size.width = self.frame.size.width / scale; 151 | zoomRect.size.height = self.frame.size.height / scale; 152 | zoomRect.origin.x = center.x - zoomRect.size.width * 0.5; 153 | zoomRect.origin.y = center.y - zoomRect.size.height * 0.5; 154 | return zoomRect; 155 | } 156 | 157 | @end 158 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 683A3F27214F426D0060194E /* GameofThrones5.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 683A3F1E214F426C0060194E /* GameofThrones5.jpg */; }; 11 | 683A3F28214F426D0060194E /* GameofThrones8.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 683A3F1F214F426C0060194E /* GameofThrones8.jpg */; }; 12 | 683A3F29214F426D0060194E /* GameofThrones1.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 683A3F20214F426C0060194E /* GameofThrones1.jpg */; }; 13 | 683A3F2A214F426D0060194E /* GameofThrones6.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 683A3F21214F426D0060194E /* GameofThrones6.jpg */; }; 14 | 683A3F2B214F426D0060194E /* GameofThrones7.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 683A3F22214F426D0060194E /* GameofThrones7.jpg */; }; 15 | 683A3F2C214F426D0060194E /* GameofThrones4.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 683A3F23214F426D0060194E /* GameofThrones4.jpg */; }; 16 | 683A3F2D214F426D0060194E /* GameofThrones2.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 683A3F24214F426D0060194E /* GameofThrones2.jpg */; }; 17 | 683A3F2E214F426D0060194E /* GameofThrones9.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 683A3F25214F426D0060194E /* GameofThrones9.jpg */; }; 18 | 683A3F2F214F426D0060194E /* GameofThrones3.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 683A3F26214F426D0060194E /* GameofThrones3.jpg */; }; 19 | 683A3F32214F45640060194E /* SRActionSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 683A3F30214F45640060194E /* SRActionSheet.m */; }; 20 | 68A23F0A1EBA003000EF0DEC /* SRPictureManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 68A23F091EBA003000EF0DEC /* SRPictureManager.m */; }; 21 | 68E825B21E11196E002FB39B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 68E825B11E11196E002FB39B /* main.m */; }; 22 | 68E825B51E11196E002FB39B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 68E825B41E11196E002FB39B /* AppDelegate.m */; }; 23 | 68E825B81E11196E002FB39B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68E825B71E11196E002FB39B /* ViewController.m */; }; 24 | 68E825BB1E11196E002FB39B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 68E825B91E11196E002FB39B /* Main.storyboard */; }; 25 | 68E825BD1E11196E002FB39B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 68E825BC1E11196E002FB39B /* Assets.xcassets */; }; 26 | 68E8262D1E111A45002FB39B /* SRPictureBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 68E826101E111A45002FB39B /* SRPictureBrowser.m */; }; 27 | 68E8262E1E111A45002FB39B /* SRPictureCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 68E826121E111A45002FB39B /* SRPictureCell.m */; }; 28 | 68E8262F1E111A45002FB39B /* SRPictureIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 68E826141E111A45002FB39B /* SRPictureIndicator.m */; }; 29 | 68E826301E111A45002FB39B /* SRPictureModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 68E826171E111A45002FB39B /* SRPictureModel.m */; }; 30 | 68E826311E111A45002FB39B /* SRPictureView.m in Sources */ = {isa = PBXBuildFile; fileRef = 68E826191E111A45002FB39B /* SRPictureView.m */; }; 31 | 6EBF581E1EB1165900B2B986 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6EBF581D1EB1165900B2B986 /* LaunchScreen.storyboard */; }; 32 | 6ECAF8CE1EC37BD60099BB21 /* SRPictureHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 6ECAF8CD1EC37BD60099BB21 /* SRPictureHUD.m */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 683A3F1E214F426C0060194E /* GameofThrones5.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = GameofThrones5.jpg; sourceTree = ""; }; 37 | 683A3F1F214F426C0060194E /* GameofThrones8.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = GameofThrones8.jpg; sourceTree = ""; }; 38 | 683A3F20214F426C0060194E /* GameofThrones1.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = GameofThrones1.jpg; sourceTree = ""; }; 39 | 683A3F21214F426D0060194E /* GameofThrones6.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = GameofThrones6.jpg; sourceTree = ""; }; 40 | 683A3F22214F426D0060194E /* GameofThrones7.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = GameofThrones7.jpg; sourceTree = ""; }; 41 | 683A3F23214F426D0060194E /* GameofThrones4.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = GameofThrones4.jpg; sourceTree = ""; }; 42 | 683A3F24214F426D0060194E /* GameofThrones2.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = GameofThrones2.jpg; sourceTree = ""; }; 43 | 683A3F25214F426D0060194E /* GameofThrones9.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = GameofThrones9.jpg; sourceTree = ""; }; 44 | 683A3F26214F426D0060194E /* GameofThrones3.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = GameofThrones3.jpg; sourceTree = ""; }; 45 | 683A3F30214F45640060194E /* SRActionSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRActionSheet.m; sourceTree = ""; }; 46 | 683A3F31214F45640060194E /* SRActionSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRActionSheet.h; sourceTree = ""; }; 47 | 68A23F081EBA003000EF0DEC /* SRPictureManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRPictureManager.h; sourceTree = ""; }; 48 | 68A23F091EBA003000EF0DEC /* SRPictureManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRPictureManager.m; sourceTree = ""; }; 49 | 68E825AD1E11196E002FB39B /* SRPictureBrowserDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SRPictureBrowserDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 68E825B11E11196E002FB39B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | 68E825B31E11196E002FB39B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 52 | 68E825B41E11196E002FB39B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 53 | 68E825B61E11196E002FB39B /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 54 | 68E825B71E11196E002FB39B /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 55 | 68E825BA1E11196E002FB39B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 56 | 68E825BC1E11196E002FB39B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 57 | 68E825C11E11196E002FB39B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 68E8260F1E111A45002FB39B /* SRPictureBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRPictureBrowser.h; sourceTree = ""; }; 59 | 68E826101E111A45002FB39B /* SRPictureBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRPictureBrowser.m; sourceTree = ""; }; 60 | 68E826111E111A45002FB39B /* SRPictureCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRPictureCell.h; sourceTree = ""; }; 61 | 68E826121E111A45002FB39B /* SRPictureCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRPictureCell.m; sourceTree = ""; }; 62 | 68E826131E111A45002FB39B /* SRPictureIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRPictureIndicator.h; sourceTree = ""; }; 63 | 68E826141E111A45002FB39B /* SRPictureIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRPictureIndicator.m; sourceTree = ""; }; 64 | 68E826161E111A45002FB39B /* SRPictureModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRPictureModel.h; sourceTree = ""; }; 65 | 68E826171E111A45002FB39B /* SRPictureModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRPictureModel.m; sourceTree = ""; }; 66 | 68E826181E111A45002FB39B /* SRPictureView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRPictureView.h; sourceTree = ""; }; 67 | 68E826191E111A45002FB39B /* SRPictureView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRPictureView.m; sourceTree = ""; }; 68 | 6EBF581D1EB1165900B2B986 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 69 | 6ECAF8CC1EC37BD60099BB21 /* SRPictureHUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRPictureHUD.h; sourceTree = ""; }; 70 | 6ECAF8CD1EC37BD60099BB21 /* SRPictureHUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRPictureHUD.m; sourceTree = ""; }; 71 | /* End PBXFileReference section */ 72 | 73 | /* Begin PBXFrameworksBuildPhase section */ 74 | 68E825AA1E11196E002FB39B /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | 683A3F1D214F42220060194E /* Resource */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 683A3F20214F426C0060194E /* GameofThrones1.jpg */, 88 | 683A3F24214F426D0060194E /* GameofThrones2.jpg */, 89 | 683A3F26214F426D0060194E /* GameofThrones3.jpg */, 90 | 683A3F23214F426D0060194E /* GameofThrones4.jpg */, 91 | 683A3F1E214F426C0060194E /* GameofThrones5.jpg */, 92 | 683A3F21214F426D0060194E /* GameofThrones6.jpg */, 93 | 683A3F22214F426D0060194E /* GameofThrones7.jpg */, 94 | 683A3F1F214F426C0060194E /* GameofThrones8.jpg */, 95 | 683A3F25214F426D0060194E /* GameofThrones9.jpg */, 96 | ); 97 | name = Resource; 98 | sourceTree = ""; 99 | }; 100 | 68E825A41E11196E002FB39B = { 101 | isa = PBXGroup; 102 | children = ( 103 | 68E825AF1E11196E002FB39B /* SRPictureBrowserDemo */, 104 | 68E825AE1E11196E002FB39B /* Products */, 105 | ); 106 | sourceTree = ""; 107 | }; 108 | 68E825AE1E11196E002FB39B /* Products */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 68E825AD1E11196E002FB39B /* SRPictureBrowserDemo.app */, 112 | ); 113 | name = Products; 114 | sourceTree = ""; 115 | }; 116 | 68E825AF1E11196E002FB39B /* SRPictureBrowserDemo */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 68E825E31E111A45002FB39B /* SRPictureBrowser */, 120 | 68E825B61E11196E002FB39B /* ViewController.h */, 121 | 68E825B71E11196E002FB39B /* ViewController.m */, 122 | 683A3F31214F45640060194E /* SRActionSheet.h */, 123 | 683A3F30214F45640060194E /* SRActionSheet.m */, 124 | 6ECAF8CC1EC37BD60099BB21 /* SRPictureHUD.h */, 125 | 6ECAF8CD1EC37BD60099BB21 /* SRPictureHUD.m */, 126 | 68E825B91E11196E002FB39B /* Main.storyboard */, 127 | 68E825B01E11196E002FB39B /* Supporting Files */, 128 | ); 129 | path = SRPictureBrowserDemo; 130 | sourceTree = ""; 131 | }; 132 | 68E825B01E11196E002FB39B /* Supporting Files */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 683A3F1D214F42220060194E /* Resource */, 136 | 68E825B11E11196E002FB39B /* main.m */, 137 | 68E825B31E11196E002FB39B /* AppDelegate.h */, 138 | 68E825B41E11196E002FB39B /* AppDelegate.m */, 139 | 6EBF581D1EB1165900B2B986 /* LaunchScreen.storyboard */, 140 | 68E825BC1E11196E002FB39B /* Assets.xcassets */, 141 | 68E825C11E11196E002FB39B /* Info.plist */, 142 | ); 143 | name = "Supporting Files"; 144 | sourceTree = ""; 145 | }; 146 | 68E825E31E111A45002FB39B /* SRPictureBrowser */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | 68E8260F1E111A45002FB39B /* SRPictureBrowser.h */, 150 | 68E826101E111A45002FB39B /* SRPictureBrowser.m */, 151 | 68E826161E111A45002FB39B /* SRPictureModel.h */, 152 | 68E826171E111A45002FB39B /* SRPictureModel.m */, 153 | 68E826111E111A45002FB39B /* SRPictureCell.h */, 154 | 68E826121E111A45002FB39B /* SRPictureCell.m */, 155 | 68E826181E111A45002FB39B /* SRPictureView.h */, 156 | 68E826191E111A45002FB39B /* SRPictureView.m */, 157 | 68E826131E111A45002FB39B /* SRPictureIndicator.h */, 158 | 68E826141E111A45002FB39B /* SRPictureIndicator.m */, 159 | 68A23F081EBA003000EF0DEC /* SRPictureManager.h */, 160 | 68A23F091EBA003000EF0DEC /* SRPictureManager.m */, 161 | ); 162 | name = SRPictureBrowser; 163 | path = ../../SRPictureBrowser; 164 | sourceTree = ""; 165 | }; 166 | /* End PBXGroup section */ 167 | 168 | /* Begin PBXNativeTarget section */ 169 | 68E825AC1E11196E002FB39B /* SRPictureBrowserDemo */ = { 170 | isa = PBXNativeTarget; 171 | buildConfigurationList = 68E825DA1E11196E002FB39B /* Build configuration list for PBXNativeTarget "SRPictureBrowserDemo" */; 172 | buildPhases = ( 173 | 68E825A91E11196E002FB39B /* Sources */, 174 | 68E825AA1E11196E002FB39B /* Frameworks */, 175 | 68E825AB1E11196E002FB39B /* Resources */, 176 | ); 177 | buildRules = ( 178 | ); 179 | dependencies = ( 180 | ); 181 | name = SRPictureBrowserDemo; 182 | productName = SRPictureBrowserDemo; 183 | productReference = 68E825AD1E11196E002FB39B /* SRPictureBrowserDemo.app */; 184 | productType = "com.apple.product-type.application"; 185 | }; 186 | /* End PBXNativeTarget section */ 187 | 188 | /* Begin PBXProject section */ 189 | 68E825A51E11196E002FB39B /* Project object */ = { 190 | isa = PBXProject; 191 | attributes = { 192 | LastUpgradeCheck = 0940; 193 | ORGANIZATIONNAME = SR; 194 | TargetAttributes = { 195 | 68E825AC1E11196E002FB39B = { 196 | CreatedOnToolsVersion = 8.1; 197 | DevelopmentTeam = L8C6M6B8E9; 198 | ProvisioningStyle = Manual; 199 | }; 200 | }; 201 | }; 202 | buildConfigurationList = 68E825A81E11196E002FB39B /* Build configuration list for PBXProject "SRPictureBrowserDemo" */; 203 | compatibilityVersion = "Xcode 3.2"; 204 | developmentRegion = English; 205 | hasScannedForEncodings = 0; 206 | knownRegions = ( 207 | en, 208 | Base, 209 | ); 210 | mainGroup = 68E825A41E11196E002FB39B; 211 | productRefGroup = 68E825AE1E11196E002FB39B /* Products */; 212 | projectDirPath = ""; 213 | projectRoot = ""; 214 | targets = ( 215 | 68E825AC1E11196E002FB39B /* SRPictureBrowserDemo */, 216 | ); 217 | }; 218 | /* End PBXProject section */ 219 | 220 | /* Begin PBXResourcesBuildPhase section */ 221 | 68E825AB1E11196E002FB39B /* Resources */ = { 222 | isa = PBXResourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | 683A3F29214F426D0060194E /* GameofThrones1.jpg in Resources */, 226 | 683A3F27214F426D0060194E /* GameofThrones5.jpg in Resources */, 227 | 683A3F2E214F426D0060194E /* GameofThrones9.jpg in Resources */, 228 | 683A3F2B214F426D0060194E /* GameofThrones7.jpg in Resources */, 229 | 683A3F2C214F426D0060194E /* GameofThrones4.jpg in Resources */, 230 | 68E825BD1E11196E002FB39B /* Assets.xcassets in Resources */, 231 | 68E825BB1E11196E002FB39B /* Main.storyboard in Resources */, 232 | 683A3F2A214F426D0060194E /* GameofThrones6.jpg in Resources */, 233 | 6EBF581E1EB1165900B2B986 /* LaunchScreen.storyboard in Resources */, 234 | 683A3F28214F426D0060194E /* GameofThrones8.jpg in Resources */, 235 | 683A3F2F214F426D0060194E /* GameofThrones3.jpg in Resources */, 236 | 683A3F2D214F426D0060194E /* GameofThrones2.jpg in Resources */, 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | }; 240 | /* End PBXResourcesBuildPhase section */ 241 | 242 | /* Begin PBXSourcesBuildPhase section */ 243 | 68E825A91E11196E002FB39B /* Sources */ = { 244 | isa = PBXSourcesBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | 68E825B81E11196E002FB39B /* ViewController.m in Sources */, 248 | 68E826311E111A45002FB39B /* SRPictureView.m in Sources */, 249 | 683A3F32214F45640060194E /* SRActionSheet.m in Sources */, 250 | 68E826301E111A45002FB39B /* SRPictureModel.m in Sources */, 251 | 6ECAF8CE1EC37BD60099BB21 /* SRPictureHUD.m in Sources */, 252 | 68E8262E1E111A45002FB39B /* SRPictureCell.m in Sources */, 253 | 68E8262D1E111A45002FB39B /* SRPictureBrowser.m in Sources */, 254 | 68E8262F1E111A45002FB39B /* SRPictureIndicator.m in Sources */, 255 | 68E825B51E11196E002FB39B /* AppDelegate.m in Sources */, 256 | 68A23F0A1EBA003000EF0DEC /* SRPictureManager.m in Sources */, 257 | 68E825B21E11196E002FB39B /* main.m in Sources */, 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | }; 261 | /* End PBXSourcesBuildPhase section */ 262 | 263 | /* Begin PBXVariantGroup section */ 264 | 68E825B91E11196E002FB39B /* Main.storyboard */ = { 265 | isa = PBXVariantGroup; 266 | children = ( 267 | 68E825BA1E11196E002FB39B /* Base */, 268 | ); 269 | name = Main.storyboard; 270 | sourceTree = ""; 271 | }; 272 | /* End PBXVariantGroup section */ 273 | 274 | /* Begin XCBuildConfiguration section */ 275 | 68E825D81E11196E002FB39B /* Debug */ = { 276 | isa = XCBuildConfiguration; 277 | buildSettings = { 278 | ALWAYS_SEARCH_USER_PATHS = NO; 279 | CLANG_ANALYZER_NONNULL = YES; 280 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 281 | CLANG_CXX_LIBRARY = "libc++"; 282 | CLANG_ENABLE_MODULES = YES; 283 | CLANG_ENABLE_OBJC_ARC = YES; 284 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 285 | CLANG_WARN_BOOL_CONVERSION = YES; 286 | CLANG_WARN_COMMA = YES; 287 | CLANG_WARN_CONSTANT_CONVERSION = YES; 288 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 289 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 290 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 291 | CLANG_WARN_EMPTY_BODY = YES; 292 | CLANG_WARN_ENUM_CONVERSION = YES; 293 | CLANG_WARN_INFINITE_RECURSION = YES; 294 | CLANG_WARN_INT_CONVERSION = YES; 295 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 296 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 297 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 298 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 299 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 300 | CLANG_WARN_STRICT_PROTOTYPES = YES; 301 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 302 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 303 | CLANG_WARN_UNREACHABLE_CODE = YES; 304 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 305 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 306 | COPY_PHASE_STRIP = NO; 307 | DEBUG_INFORMATION_FORMAT = dwarf; 308 | ENABLE_STRICT_OBJC_MSGSEND = YES; 309 | ENABLE_TESTABILITY = YES; 310 | GCC_C_LANGUAGE_STANDARD = gnu99; 311 | GCC_DYNAMIC_NO_PIC = NO; 312 | GCC_NO_COMMON_BLOCKS = YES; 313 | GCC_OPTIMIZATION_LEVEL = 0; 314 | GCC_PREPROCESSOR_DEFINITIONS = ( 315 | "DEBUG=1", 316 | "$(inherited)", 317 | ); 318 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 319 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 320 | GCC_WARN_UNDECLARED_SELECTOR = YES; 321 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 322 | GCC_WARN_UNUSED_FUNCTION = YES; 323 | GCC_WARN_UNUSED_VARIABLE = YES; 324 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 325 | MTL_ENABLE_DEBUG_INFO = YES; 326 | ONLY_ACTIVE_ARCH = YES; 327 | SDKROOT = iphoneos; 328 | }; 329 | name = Debug; 330 | }; 331 | 68E825D91E11196E002FB39B /* Release */ = { 332 | isa = XCBuildConfiguration; 333 | buildSettings = { 334 | ALWAYS_SEARCH_USER_PATHS = NO; 335 | CLANG_ANALYZER_NONNULL = YES; 336 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 337 | CLANG_CXX_LIBRARY = "libc++"; 338 | CLANG_ENABLE_MODULES = YES; 339 | CLANG_ENABLE_OBJC_ARC = YES; 340 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 341 | CLANG_WARN_BOOL_CONVERSION = YES; 342 | CLANG_WARN_COMMA = YES; 343 | CLANG_WARN_CONSTANT_CONVERSION = YES; 344 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 345 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 346 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 347 | CLANG_WARN_EMPTY_BODY = YES; 348 | CLANG_WARN_ENUM_CONVERSION = YES; 349 | CLANG_WARN_INFINITE_RECURSION = YES; 350 | CLANG_WARN_INT_CONVERSION = YES; 351 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 352 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 353 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 354 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 355 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 356 | CLANG_WARN_STRICT_PROTOTYPES = YES; 357 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 358 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 359 | CLANG_WARN_UNREACHABLE_CODE = YES; 360 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 361 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 362 | COPY_PHASE_STRIP = NO; 363 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 364 | ENABLE_NS_ASSERTIONS = NO; 365 | ENABLE_STRICT_OBJC_MSGSEND = YES; 366 | GCC_C_LANGUAGE_STANDARD = gnu99; 367 | GCC_NO_COMMON_BLOCKS = YES; 368 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 369 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 370 | GCC_WARN_UNDECLARED_SELECTOR = YES; 371 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 372 | GCC_WARN_UNUSED_FUNCTION = YES; 373 | GCC_WARN_UNUSED_VARIABLE = YES; 374 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 375 | MTL_ENABLE_DEBUG_INFO = NO; 376 | SDKROOT = iphoneos; 377 | VALIDATE_PRODUCT = YES; 378 | }; 379 | name = Release; 380 | }; 381 | 68E825DB1E11196E002FB39B /* Debug */ = { 382 | isa = XCBuildConfiguration; 383 | buildSettings = { 384 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 385 | DEVELOPMENT_TEAM = L8C6M6B8E9; 386 | INFOPLIST_FILE = SRPictureBrowserDemo/Info.plist; 387 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 388 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 389 | OTHER_LDFLAGS = ""; 390 | PRODUCT_BUNDLE_IDENTIFIER = com.willing.SRPictureBrowserDemo; 391 | PRODUCT_NAME = "$(TARGET_NAME)"; 392 | PROVISIONING_PROFILE = "ffb223b7-b498-46e0-af66-aa9a0a5e2883"; 393 | PROVISIONING_PROFILE_SPECIFIER = "PP For All"; 394 | }; 395 | name = Debug; 396 | }; 397 | 68E825DC1E11196E002FB39B /* Release */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 401 | DEVELOPMENT_TEAM = L8C6M6B8E9; 402 | INFOPLIST_FILE = SRPictureBrowserDemo/Info.plist; 403 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 404 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 405 | OTHER_LDFLAGS = ""; 406 | PRODUCT_BUNDLE_IDENTIFIER = com.willing.SRPictureBrowserDemo; 407 | PRODUCT_NAME = "$(TARGET_NAME)"; 408 | PROVISIONING_PROFILE = "ffb223b7-b498-46e0-af66-aa9a0a5e2883"; 409 | PROVISIONING_PROFILE_SPECIFIER = "PP For All"; 410 | }; 411 | name = Release; 412 | }; 413 | /* End XCBuildConfiguration section */ 414 | 415 | /* Begin XCConfigurationList section */ 416 | 68E825A81E11196E002FB39B /* Build configuration list for PBXProject "SRPictureBrowserDemo" */ = { 417 | isa = XCConfigurationList; 418 | buildConfigurations = ( 419 | 68E825D81E11196E002FB39B /* Debug */, 420 | 68E825D91E11196E002FB39B /* Release */, 421 | ); 422 | defaultConfigurationIsVisible = 0; 423 | defaultConfigurationName = Release; 424 | }; 425 | 68E825DA1E11196E002FB39B /* Build configuration list for PBXNativeTarget "SRPictureBrowserDemo" */ = { 426 | isa = XCConfigurationList; 427 | buildConfigurations = ( 428 | 68E825DB1E11196E002FB39B /* Debug */, 429 | 68E825DC1E11196E002FB39B /* Release */, 430 | ); 431 | defaultConfigurationIsVisible = 0; 432 | defaultConfigurationName = Release; 433 | }; 434 | /* End XCConfigurationList section */ 435 | }; 436 | rootObject = 68E825A51E11196E002FB39B /* Project object */; 437 | } 438 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // SRPictureBrowserDemo 4 | // 5 | // Created by Willing Guo on 16/12/26. 6 | // Copyright © 2016年 SR. 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 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // SRPictureBrowserDemo 4 | // 5 | // Created by Willing Guo on 16/12/26. 6 | // Copyright © 2016年 SR. 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 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/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 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones1.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones2.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones3.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones4.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones5.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones6.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones7.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones8.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones/GameofThrones9.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones1.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones2.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones3.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones4.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones5.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones6.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones7.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones8.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/SRPictureBrowserDemo/SRPictureBrowserDemo/GameofThrones9.jpg -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | NSPhotoLibraryAddUsageDescription 29 | 使用相册权限 30 | NSPhotoLibraryUsageDescription 31 | For Save Image. 32 | UILaunchStoryboardName 33 | LaunchScreen 34 | UIMainStoryboardFile 35 | Main 36 | UIRequiredDeviceCapabilities 37 | 38 | armv7 39 | 40 | UIStatusBarHidden 41 | 42 | UISupportedInterfaceOrientations 43 | 44 | UIInterfaceOrientationPortrait 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/SRActionSheet.h: -------------------------------------------------------------------------------- 1 | // 2 | // SRActionSheetView.h 3 | // SRActionSheet 4 | // 5 | // Created by https://github.com/guowilling on 16/7/5. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class SRActionSheet; 12 | 13 | typedef NS_ENUM(NSInteger, SROtherActionItemAlignment) { 14 | SROtherActionItemAlignmentLeft, 15 | SROtherActionItemAlignmentCenter 16 | }; 17 | 18 | @protocol SRActionSheetDelegate 19 | 20 | /** 21 | @param index The top is 0 and ++ to down, but cancel item's index is -1. 22 | */ 23 | - (void)actionSheet:(SRActionSheet *)actionSheet didSelectSheet:(NSInteger)index; 24 | 25 | @end 26 | 27 | /** 28 | @param index The same as the delegate. 29 | */ 30 | typedef void (^SRActionSheetDidSelectActionBlock)(SRActionSheet *actionSheet, NSInteger index); 31 | 32 | @interface SRActionSheet : UIView 33 | 34 | /** 35 | If no images default is SROtherActionItemAlignmentCenter otherwise default is SROtherActionItemAlignmentLeft. 36 | */ 37 | @property (nonatomic, assign) SROtherActionItemAlignment otherActionItemAlignment; 38 | 39 | + (instancetype)sr_actionSheetViewWithTitle:(NSString *)title 40 | cancelTitle:(NSString *)cancelTitle 41 | destructiveTitle:(NSString *)destructiveTitle 42 | otherTitles:(NSArray *)otherTitles 43 | otherImages:(NSArray *)otherImages 44 | selectActionBlock:(SRActionSheetDidSelectActionBlock)block; 45 | 46 | + (instancetype)sr_actionSheetViewWithTitle:(NSString *)title 47 | cancelTitle:(NSString *)cancelTitle 48 | destructiveTitle:(NSString *)destructiveTitle 49 | otherTitles:(NSArray *)otherTitles 50 | otherImages:(NSArray *)otherImages 51 | delegate:(id)delegate; 52 | 53 | - (void)show; 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/SRActionSheet.m: -------------------------------------------------------------------------------- 1 | // 2 | // SRActionSheetView.m 3 | // SRActionSheet 4 | // 5 | // Created by https://github.com/guowilling on 16/7/5. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import "SRActionSheet.h" 10 | 11 | #define SCREEN_BOUNDS [UIScreen mainScreen].bounds 12 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 13 | #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height 14 | #define SCREEN_ADJUST(Value) SCREEN_WIDTH * (Value) / 375.0 15 | 16 | #define kActionItemHeight SCREEN_ADJUST(50) 17 | #define kLineHeight 0.5 18 | #define kDividerHeight 7.5 19 | 20 | #define kTitleFontSize SCREEN_ADJUST(15) 21 | #define kActionItemFontSize SCREEN_ADJUST(17) 22 | 23 | #define kActionSheetColor [UIColor colorWithRed:245.0f/255.0f green:245.0f/255.0f blue:245.0f/255.0f alpha:1.0f] 24 | #define kTitleColor [UIColor colorWithRed:111.0f/255.0f green:111.0f/255.0f blue:111.0f/255.0f alpha:1.0f] 25 | #define kActionItemHighlightedColor [UIColor colorWithRed:242.0f/255.0f green:242.0f/255.0f blue:242.0f/255.0f alpha:1.0f] 26 | #define kDestructiveItemNormalColor [UIColor colorWithRed:255.0f/255.0f green:10.00f/255.0f blue:10.00f/255.0f alpha:1.0f] 27 | #define kDividerColor [UIColor colorWithRed:240.0f/255.0f green:240.0f/255.0f blue:240.0f/255.0f alpha:1.0f] 28 | 29 | @interface SRActionSheet () 30 | 31 | @property (nonatomic, weak) id delegate; 32 | 33 | @property (nonatomic, copy) SRActionSheetDidSelectActionBlock selectActionBlock; 34 | 35 | @property (nonatomic, weak) UIView *cover; 36 | @property (nonatomic, weak) UIView *actionSheet; 37 | 38 | @property (nonatomic, copy) NSString *title; 39 | @property (nonatomic, copy) NSString *cancelTitle; 40 | @property (nonatomic, copy) NSString *destructiveTitle; 41 | @property (nonatomic, copy) NSArray *otherTitles; 42 | @property (nonatomic, copy) NSArray *otherImages; 43 | 44 | @property (nonatomic, assign) CGFloat offsetY; 45 | @property (nonatomic, assign) CGFloat actionSheetHeight; 46 | 47 | @property (nonatomic, strong) UIImage *normalImage; 48 | @property (nonatomic, strong) UIImage *highlightedImage; 49 | 50 | @property (nonatomic, strong) NSMutableArray *otherActionItems; 51 | 52 | @end 53 | 54 | @implementation SRActionSheet 55 | 56 | - (NSMutableArray *)otherActionItems { 57 | 58 | if (!_otherActionItems) { 59 | _otherActionItems = [NSMutableArray array]; 60 | } 61 | return _otherActionItems; 62 | } 63 | 64 | - (UIImage *)normalImage { 65 | 66 | if (!_normalImage) { 67 | _normalImage = [self imageFromColor:[UIColor whiteColor]]; 68 | } 69 | return _normalImage; 70 | } 71 | 72 | - (UIImage *)highlightedImage { 73 | 74 | if (!_highlightedImage) { 75 | _highlightedImage = [self imageFromColor:kActionItemHighlightedColor]; 76 | } 77 | return _highlightedImage; 78 | } 79 | 80 | #pragma mark - BLOCK 81 | 82 | + (instancetype)sr_actionSheetViewWithTitle:(NSString *)title 83 | cancelTitle:(NSString *)cancelTitle 84 | destructiveTitle:(NSString *)destructiveTitle 85 | otherTitles:(NSArray *)otherTitles 86 | otherImages:(NSArray *)otherImages 87 | selectActionBlock:(SRActionSheetDidSelectActionBlock)block 88 | { 89 | return [[self alloc] initWithTitle:title 90 | cancelTitle:cancelTitle 91 | destructiveTitle:destructiveTitle 92 | otherTitles:otherTitles 93 | otherImages:otherImages 94 | selectActionBlock:block]; 95 | } 96 | 97 | - (instancetype)initWithTitle:(NSString *)title 98 | cancelTitle:(NSString *)cancelTitle 99 | destructiveTitle:(NSString *)destructiveTitle 100 | otherTitles:(NSArray *)otherTitles 101 | otherImages:(NSArray *)otherImages 102 | selectActionBlock:(SRActionSheetDidSelectActionBlock)selectActionBlock 103 | { 104 | if (self = [super initWithFrame:SCREEN_BOUNDS]) { 105 | _title = title; 106 | _cancelTitle = cancelTitle; 107 | _destructiveTitle = destructiveTitle; 108 | _otherTitles = otherTitles; 109 | _otherImages = otherImages; 110 | _selectActionBlock = selectActionBlock; 111 | [self setupCover]; 112 | [self setupActionSheet]; 113 | } 114 | return self; 115 | } 116 | 117 | #pragma mark - DELEGATE 118 | 119 | + (instancetype)sr_actionSheetViewWithTitle:(NSString *)title 120 | cancelTitle:(NSString *)cancelTitle 121 | destructiveTitle:(NSString *)destructiveTitle 122 | otherTitles:(NSArray *)otherTitles 123 | otherImages:(NSArray *)otherImages 124 | delegate:(id)delegate 125 | { 126 | return [[self alloc] initWithTitle:title 127 | cancelTitle:cancelTitle 128 | destructiveTitle:destructiveTitle 129 | otherTitles:otherTitles 130 | otherImages:otherImages 131 | delegate:delegate]; 132 | } 133 | 134 | - (instancetype)initWithTitle:(NSString *)title 135 | cancelTitle:(NSString *)cancelTitle 136 | destructiveTitle:(NSString *)destructiveTitle 137 | otherTitles:(NSArray *)otherTitles 138 | otherImages:(NSArray *)otherImages 139 | delegate:(id)delegate 140 | { 141 | if (self = [super initWithFrame:SCREEN_BOUNDS]) { 142 | _title = title; 143 | _cancelTitle = cancelTitle; 144 | _destructiveTitle = destructiveTitle; 145 | _otherTitles = otherTitles; 146 | _otherImages = otherImages; 147 | _delegate = delegate; 148 | [self setupCover]; 149 | [self setupActionSheet]; 150 | } 151 | return self; 152 | } 153 | 154 | #pragma mark - Setup UI 155 | 156 | - (void)setupCover { 157 | [self addSubview:({ 158 | UIView *cover = [[UIView alloc] init]; 159 | cover.frame = self.bounds; 160 | cover.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.33]; 161 | cover.alpha = 0; 162 | [cover addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismiss)]]; 163 | _cover = cover; 164 | })]; 165 | } 166 | 167 | - (void)setupActionSheet { 168 | [self addSubview:({ 169 | UIView *actionSheet = [[UIView alloc] init]; 170 | actionSheet.backgroundColor = kActionSheetColor; 171 | _actionSheet = actionSheet; 172 | })]; 173 | 174 | _offsetY = 0; 175 | 176 | [self setupTitleLabel]; 177 | 178 | [self setupOtherActionItems]; 179 | 180 | [self setupDestructiveActionItem]; 181 | 182 | [_actionSheet addSubview:({ 183 | UIView *dividerView = [[UIView alloc] initWithFrame:CGRectMake(0, _offsetY, self.frame.size.width, kDividerHeight)]; 184 | dividerView.backgroundColor = kDividerColor; 185 | dividerView; 186 | })]; 187 | 188 | [self setupCancelActionItem]; 189 | 190 | _actionSheet.frame = CGRectMake(0, CGRectGetHeight(self.frame), CGRectGetWidth(self.frame), _offsetY); 191 | _actionSheetHeight = _offsetY; 192 | } 193 | 194 | - (void)setupTitleLabel { 195 | if (!_title && _title.length == 0) { 196 | return; 197 | } 198 | [_actionSheet addSubview:({ 199 | UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, kActionItemHeight)]; 200 | titleLabel.backgroundColor = [UIColor whiteColor]; 201 | titleLabel.textColor = kTitleColor; 202 | titleLabel.textAlignment = NSTextAlignmentCenter; 203 | titleLabel.font = [UIFont systemFontOfSize:kTitleFontSize]; 204 | titleLabel.numberOfLines = 0; 205 | titleLabel.text = self.title; 206 | titleLabel; 207 | })]; 208 | _offsetY += kActionItemHeight + kLineHeight; 209 | } 210 | 211 | - (void)setupOtherActionItems { 212 | if (!_otherTitles || _otherTitles.count == 0) { 213 | return; 214 | } 215 | for (int i = 0; i < _otherTitles.count; i++) { 216 | [_actionSheet addSubview:({ 217 | UIButton *otherBtn = [[UIButton alloc] init]; 218 | otherBtn.frame = CGRectMake(0, _offsetY, self.frame.size.width, kActionItemHeight); 219 | otherBtn.backgroundColor = [UIColor whiteColor]; 220 | otherBtn.tag = i; 221 | [otherBtn setBackgroundImage:self.normalImage forState:UIControlStateNormal]; 222 | [otherBtn setBackgroundImage:self.highlightedImage forState:UIControlStateHighlighted]; 223 | [otherBtn addTarget:self action:@selector(didSelectSheet:) forControlEvents:UIControlEventTouchUpInside]; 224 | [otherBtn addSubview:({ 225 | UIView *otherItem = [[UIView alloc] init]; 226 | otherItem.backgroundColor = [UIColor clearColor]; 227 | otherItem.userInteractionEnabled = NO; 228 | CGSize maxTitleSize = [self maxSizeInStrings:_otherTitles]; 229 | if (_otherImages && _otherImages.count > 0) { 230 | UIImageView *icon = [[UIImageView alloc] init]; 231 | [otherItem addSubview:({ 232 | icon.frame = CGRectMake(0, 0, kActionItemHeight, kActionItemHeight); 233 | icon.image = _otherImages.count > i ? _otherImages[i] : nil; 234 | icon.contentMode = UIViewContentModeCenter; 235 | icon.tag = 2; 236 | icon; 237 | })]; 238 | [otherItem addSubview:({ 239 | UILabel *title = [[UILabel alloc] init]; 240 | title.frame = CGRectMake(CGRectGetMaxX(icon.frame), 0, maxTitleSize.width, kActionItemHeight); 241 | title.font = [UIFont systemFontOfSize:kActionItemFontSize]; 242 | title.tintColor = [UIColor blackColor]; 243 | title.text = _otherTitles[i]; 244 | title.tag = 1; 245 | title; 246 | })]; 247 | otherItem.frame = CGRectMake(10, 0, kActionItemHeight + maxTitleSize.width, kActionItemHeight); 248 | } else { 249 | [otherItem addSubview:({ 250 | UILabel *title = [[UILabel alloc] init]; 251 | title.frame = CGRectMake(0, 0, maxTitleSize.width, kActionItemHeight); 252 | title.font = [UIFont systemFontOfSize:kActionItemFontSize]; 253 | title.tintColor = [UIColor blackColor]; 254 | title.text = _otherTitles[i]; 255 | title.textAlignment = NSTextAlignmentCenter; 256 | title.tag = 1; 257 | title; 258 | })]; 259 | otherItem.frame = CGRectMake(self.frame.size.width * 0.5 - maxTitleSize.width * 0.5, 0, maxTitleSize.width, kActionItemHeight); 260 | } 261 | [self.otherActionItems addObject:otherItem]; 262 | otherItem; 263 | })]; 264 | if (i == _otherTitles.count - 1) { 265 | _offsetY += kActionItemHeight; 266 | } else { 267 | _offsetY += kActionItemHeight + kLineHeight; 268 | } 269 | otherBtn; 270 | })]; 271 | } 272 | } 273 | 274 | - (void)setupDestructiveActionItem { 275 | if (!_destructiveTitle && _destructiveTitle.length == 0) { 276 | return; 277 | } 278 | _offsetY += kLineHeight; 279 | [_actionSheet addSubview:({ 280 | UIButton *destructiveButton = [[UIButton alloc] init]; 281 | destructiveButton.frame = CGRectMake(0, _offsetY, self.frame.size.width, kActionItemHeight); 282 | destructiveButton.tag = _otherTitles.count ? _otherTitles.count : 0; 283 | destructiveButton.backgroundColor = [UIColor whiteColor]; 284 | destructiveButton.titleLabel.font = [UIFont systemFontOfSize:kActionItemFontSize]; 285 | [destructiveButton setTitleColor:kDestructiveItemNormalColor forState:UIControlStateNormal]; 286 | [destructiveButton setTitle:_destructiveTitle forState:UIControlStateNormal]; 287 | [destructiveButton setBackgroundImage:self.normalImage forState:UIControlStateNormal]; 288 | [destructiveButton setBackgroundImage:self.highlightedImage forState:UIControlStateHighlighted]; 289 | [destructiveButton addTarget:self action:@selector(didSelectSheet:) forControlEvents:UIControlEventTouchUpInside]; 290 | destructiveButton; 291 | })]; 292 | _offsetY += kActionItemHeight; 293 | } 294 | 295 | - (void)setupCancelActionItem { 296 | if (!_cancelTitle || _cancelTitle.length == 0) { 297 | return; 298 | } 299 | _offsetY += kDividerHeight; 300 | [_actionSheet addSubview:({ 301 | UIButton *cancelBtn = [[UIButton alloc] init]; 302 | cancelBtn.frame = CGRectMake(0, _offsetY, self.frame.size.width, kActionItemHeight); 303 | cancelBtn.tag = -1; 304 | cancelBtn.backgroundColor = [UIColor whiteColor]; 305 | cancelBtn.titleLabel.font = [UIFont systemFontOfSize:kActionItemFontSize]; 306 | [cancelBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 307 | [cancelBtn setTitle:_cancelTitle forState:UIControlStateNormal]; 308 | [cancelBtn setBackgroundImage:self.normalImage forState:UIControlStateNormal]; 309 | [cancelBtn setBackgroundImage:self.highlightedImage forState:UIControlStateHighlighted]; 310 | [cancelBtn addTarget:self action:@selector(didSelectSheet:) forControlEvents:UIControlEventTouchUpInside]; 311 | cancelBtn; 312 | })]; 313 | _offsetY += kActionItemHeight; 314 | } 315 | 316 | #pragma mark - Actions 317 | 318 | - (void)didSelectSheet:(UIButton *)button { 319 | if (_selectActionBlock) { 320 | _selectActionBlock(self, button.tag); 321 | } 322 | if ([_delegate respondsToSelector:@selector(actionSheet:didSelectSheet:)]) { 323 | [_delegate actionSheet:self didSelectSheet:button.tag]; 324 | } 325 | [self dismiss]; 326 | } 327 | 328 | #pragma mark - Animations 329 | 330 | - (void)show { 331 | [[UIApplication sharedApplication].keyWindow addSubview:self]; 332 | [UIView animateWithDuration:0.5 333 | delay:0.0 334 | usingSpringWithDamping:0.9 335 | initialSpringVelocity:0.7 336 | options:UIViewAnimationOptionCurveEaseInOut 337 | animations:^{ 338 | self.cover.alpha = 1.0; 339 | self.actionSheet.transform = CGAffineTransformMakeTranslation(0, -self.actionSheetHeight); 340 | } 341 | completion:nil]; 342 | } 343 | 344 | - (void)dismiss { 345 | [UIView animateWithDuration:0.5 346 | delay:0.0 347 | usingSpringWithDamping:0.9 348 | initialSpringVelocity:0.7 349 | options:UIViewAnimationOptionCurveEaseInOut 350 | animations:^{ 351 | self.cover.alpha = 0.0; 352 | self.actionSheet.transform = CGAffineTransformIdentity; 353 | } 354 | completion:^(BOOL finished) { 355 | [self removeFromSuperview]; 356 | }]; 357 | } 358 | 359 | #pragma mark - Assist Methods 360 | 361 | - (UIImage *)imageFromColor:(UIColor *)color { 362 | CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); 363 | UIGraphicsBeginImageContext(rect.size); 364 | CGContextRef context = UIGraphicsGetCurrentContext(); 365 | CGContextSetFillColorWithColor(context, [color CGColor]); 366 | CGContextFillRect(context, rect); 367 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 368 | UIGraphicsEndImageContext(); 369 | return image; 370 | } 371 | 372 | - (CGSize)maxSizeInStrings:(NSArray *)strings { 373 | CGSize maxSize = CGSizeZero; 374 | CGFloat maxWith = 0.0; 375 | for (NSString *string in strings) { 376 | CGSize size = [self sizeOfString:string withFont:[UIFont systemFontOfSize:kActionItemFontSize]]; 377 | if (maxWith < size.width) { 378 | maxWith = size.width; 379 | maxSize = size; 380 | } 381 | } 382 | return maxSize; 383 | } 384 | 385 | - (CGSize)sizeOfString:(NSString *)string withFont:(UIFont *)font { 386 | NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; 387 | attrs[NSFontAttributeName] = font; 388 | CGSize maxSize = CGSizeMake(MAXFLOAT, MAXFLOAT); 389 | return [string boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size; 390 | } 391 | 392 | #pragma mark - Public Methods 393 | 394 | - (void)setOtherActionItemAlignment:(SROtherActionItemAlignment)otherActionItemAlignment { 395 | _otherActionItemAlignment = otherActionItemAlignment; 396 | 397 | switch (otherActionItemAlignment) { 398 | case SROtherActionItemAlignmentLeft: 399 | { 400 | for (UIView *actionItem in self.otherActionItems) { 401 | UILabel *title = [actionItem viewWithTag:1]; 402 | title.textAlignment = NSTextAlignmentLeft; 403 | CGRect newFrame = actionItem.frame; 404 | newFrame.origin.x = 10; 405 | actionItem.frame = newFrame; 406 | } 407 | break; 408 | } 409 | case SROtherActionItemAlignmentCenter: 410 | { 411 | for (UIView *actionItem in self.otherActionItems) { 412 | UILabel *title = [actionItem viewWithTag:1]; 413 | title.textAlignment = NSTextAlignmentCenter; 414 | CGRect newFrame = actionItem.frame; 415 | newFrame.origin.x = self.frame.size.width * 0.5 - newFrame.size.width * 0.5; 416 | actionItem.frame = newFrame; 417 | } 418 | break; 419 | } 420 | } 421 | } 422 | 423 | @end 424 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/SRPictureHUD.h: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureHUD.h 3 | // SRPictureBrowserDemo 4 | // 5 | // Created by Willing Guo on 2017/5/11. 6 | // Copyright © 2017年 SR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SRPictureHUD : UIView 12 | 13 | @property (nonatomic, assign) BOOL autoDismiss; 14 | 15 | @property (nonatomic, assign) NSTimeInterval duration; 16 | 17 | + (instancetype)showHUDInView:(UIView *)view withMessage:(NSString *)message; 18 | 19 | - (void)hide; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/SRPictureHUD.m: -------------------------------------------------------------------------------- 1 | // 2 | // SRPictureHUD.m 3 | // SRPictureBrowserDemo 4 | // 5 | // Created by Willing Guo on 2017/5/11. 6 | // Copyright © 2017年 SR. All rights reserved. 7 | // 8 | 9 | #import "SRPictureHUD.h" 10 | 11 | @implementation SRPictureHUD 12 | 13 | + (instancetype)showHUDInView:(UIView *)view withMessage:(NSString *)message { 14 | if (view == nil) { 15 | view = [UIApplication sharedApplication].keyWindow; 16 | } 17 | SRPictureHUD *hud = [[SRPictureHUD alloc] initWithFrame:view.bounds mesasge:message]; 18 | [view addSubview:hud]; 19 | return hud; 20 | } 21 | 22 | - (instancetype)initWithFrame:(CGRect)frame mesasge:(NSString *)message { 23 | if (self = [super initWithFrame:frame]) { 24 | self.userInteractionEnabled = NO; 25 | _autoDismiss = YES; 26 | _duration = 1.5; 27 | [self setupHUDWithMessage:message]; 28 | } 29 | return self; 30 | } 31 | 32 | - (void)setupHUDWithMessage:(NSString *)message { 33 | CGSize messageSize = [message boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) 34 | options:NSStringDrawingUsesLineFragmentOrigin 35 | attributes:@{NSFontAttributeName: [UIFont boldSystemFontOfSize:17]} 36 | context:nil].size; 37 | CGFloat margin = 25; 38 | UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, messageSize.width + margin, messageSize.height + margin)]; 39 | container.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.5]; 40 | container.center = self.center; 41 | container.layer.cornerRadius = 5; 42 | container.layer.masksToBounds = YES; 43 | [self addSubview:container]; 44 | 45 | UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]; 46 | UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect]; 47 | effectView.frame = container.bounds; 48 | [container addSubview:effectView]; 49 | 50 | UILabel *hudLabel = [[UILabel alloc] initWithFrame:effectView.bounds]; 51 | hudLabel.text = message; 52 | hudLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1]; 53 | hudLabel.textAlignment = NSTextAlignmentCenter; 54 | hudLabel.font = [UIFont boldSystemFontOfSize:17]; 55 | [container addSubview:hudLabel]; 56 | 57 | [self performSelector:@selector(hide) withObject:nil afterDelay:_duration]; 58 | } 59 | 60 | - (void)setAutoDismiss:(BOOL)autoDismiss { 61 | _autoDismiss = autoDismiss; 62 | 63 | if (!autoDismiss) { 64 | [NSObject cancelPreviousPerformRequestsWithTarget:self]; 65 | } 66 | } 67 | 68 | - (void)setDuration:(NSTimeInterval)duration { 69 | _duration = duration; 70 | 71 | [NSObject cancelPreviousPerformRequestsWithTarget:self]; 72 | [self performSelector:@selector(hide) withObject:nil afterDelay:_duration]; 73 | } 74 | 75 | - (void)hide { 76 | [UIView animateWithDuration:0.3 animations:^{ 77 | self.alpha = 0.01; 78 | self.transform = CGAffineTransformMakeScale(0.01, 0.01); 79 | } completion:^(BOOL finished) { 80 | [self removeFromSuperview]; 81 | }]; 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // SRPictureBrowserDemo 4 | // 5 | // Created by Willing Guo on 16/12/26. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // SRPictureBrowserDemo 4 | // 5 | // Created by Willing Guo on 16/12/26. 6 | // Copyright © 2016年 SR. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "SRPictureBrowser.h" 11 | #import "SRPictureModel.h" 12 | #import "SRActionSheet.h" 13 | #import "SRPictureHUD.h" 14 | 15 | @interface ViewController () 16 | 17 | @property (nonatomic, strong) NSArray *picURLStrings; 18 | 19 | @property (nonatomic, strong) NSMutableArray *imageViewFrames; 20 | 21 | @end 22 | 23 | @implementation ViewController 24 | 25 | - (BOOL)prefersStatusBarHidden { 26 | return YES; 27 | } 28 | 29 | - (NSMutableArray *)imageViewFrames { 30 | if (!_imageViewFrames) { 31 | _imageViewFrames = [NSMutableArray array]; 32 | } 33 | return _imageViewFrames; 34 | } 35 | 36 | - (NSArray *)picURLStrings { 37 | if (!_picURLStrings) { 38 | _picURLStrings = @[@"https://yixunfiles-ali.yixun.arhieason.com/37f60c4f4489e5e9d68032344997dbc1_jpg.jpg?x-oss-process=image/format,png", 39 | @"https://yixunfiles-ali.yixun.arhieason.com/53dc63984fde3bc385c4d9158cbfbae1_jpg.jpg?x-oss-process=image/format,png", 40 | @"https://yixunfiles-ali.yixun.arhieason.com/e15612e17e541408884ae3a83264a1bc_jpg.jpg?x-oss-process=image/format,png", 41 | @"https://yixunfiles-ali.yixun.arhieason.com/2378646302510db4707ce140489777ab_jpg.jpg?x-oss-process=image/format,png", 42 | @"https://yixunfiles-ali.yixun.arhieason.com/af1e7c76740360800d796c11bf920562_jpg.jpg?x-oss-process=image/format,png", 43 | @"https://yixunfiles-ali.yixun.arhieason.com/075dccde0047e04c8087e422627b3057_jpg.jpg?x-oss-process=image/format,png", 44 | @"https://yixunfiles-ali.yixun.arhieason.com/d5e52ff8d2d32aacb1d9212149fd91bb_jpg.jpg?x-oss-process=image/format,png", 45 | @"https://yixunfiles-ali.yixun.arhieason.com/a6ae817ccd7270e9cb2ad110fd0e10b4_jpg.jpg?x-oss-process=image/format,png", 46 | @"https://yixunfiles-ali.yixun.arhieason.com/319d1a79606f3a1e5415faadd0e147d8_jpg.jpg?x-oss-process=image/format,png"]; 47 | } 48 | return _picURLStrings; 49 | } 50 | 51 | - (void)viewDidLoad { 52 | [super viewDidLoad]; 53 | 54 | UIView *container = [[UIView alloc] init]; 55 | container.backgroundColor = [UIColor whiteColor]; 56 | [self.view addSubview:({ 57 | container.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width); 58 | container.center = self.view.center; 59 | container; 60 | })]; 61 | 62 | CGFloat margin = 10; 63 | CGFloat imageViewWH = (self.view.frame.size.width - 4 * margin) / 3; 64 | for (int i = 0 ; i < self.picURLStrings.count; i++) { 65 | int col = i % 3; 66 | int row = i / 3; 67 | [container addSubview:({ 68 | UIImageView *imageView = [[UIImageView alloc] init]; 69 | imageView.tag = i; 70 | CGFloat imageViewX = margin + col * (margin + imageViewWH); 71 | CGFloat imageViewY = margin + row * (margin + imageViewWH); 72 | imageView.frame = CGRectMake(imageViewX, imageViewY, imageViewWH, imageViewWH); 73 | [self.imageViewFrames addObject:[NSValue valueWithCGRect:imageView.frame]]; 74 | imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"GameofThrones%d", i + 1]]; 75 | imageView.userInteractionEnabled = YES; 76 | UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageTapAction:)]; 77 | [imageView addGestureRecognizer:tapGestureRecognizer]; 78 | imageView.contentMode = UIViewContentModeScaleAspectFill; 79 | imageView.clipsToBounds = YES; 80 | imageView; 81 | })]; 82 | } 83 | } 84 | 85 | - (void)imageTapAction:(UITapGestureRecognizer *)tapGestureRecognizer { 86 | UIImageView *tapedImageView = (UIImageView *)tapGestureRecognizer.view; 87 | NSMutableArray *imageBrowserModels = [[NSMutableArray alloc] init]; 88 | for (NSInteger i = 0; i < self.picURLStrings.count; i ++) { 89 | SRPictureModel *imageBrowserModel = [SRPictureModel sr_pictureModelWithPicURLString:self.picURLStrings[i] 90 | containerView:tapedImageView.superview 91 | positionInContainer:[self.imageViewFrames[i] CGRectValue] 92 | index:i]; 93 | [imageBrowserModels addObject:imageBrowserModel]; 94 | } 95 | [SRPictureBrowser sr_showPictureBrowserWithModels:imageBrowserModels currentIndex:tapedImageView.tag delegate:self]; 96 | } 97 | 98 | - (void)pictureBrowserDidShow:(SRPictureBrowser *)pictureBrowser { 99 | NSLog(@"%s", __func__); 100 | } 101 | 102 | - (void)pictureBrowserDidLongPressPicture:(UIImage *)picture { 103 | [[SRActionSheet sr_actionSheetViewWithTitle:nil 104 | cancelTitle:@"Cancel" 105 | destructiveTitle:@"Sure" 106 | otherTitles:@[@"Save", @"More"] 107 | otherImages:nil 108 | selectActionBlock:^(SRActionSheet *actionSheet, NSInteger index) { 109 | if (index == 0) { 110 | UIImageWriteToSavedPhotosAlbum(picture, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL); 111 | } 112 | }] show]; 113 | } 114 | 115 | - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { 116 | if (error) { 117 | [SRPictureHUD showHUDInView:nil withMessage:@"Save Picture Failure!"]; 118 | } else { 119 | [SRPictureHUD showHUDInView:nil withMessage:@"Save Picture Success!"]; 120 | } 121 | } 122 | 123 | - (void)pictureBrowserDidDismiss { 124 | NSLog(@"%s", __func__); 125 | } 126 | 127 | @end 128 | -------------------------------------------------------------------------------- /SRPictureBrowserDemo/SRPictureBrowserDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SRPictureBrowserDemo 4 | // 5 | // Created by Willing Guo on 16/12/26. 6 | // Copyright © 2016年 SR. 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 | -------------------------------------------------------------------------------- /screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guowilling/SRPictureBrowser/48d337a88e56818f7abed8fd1677417f2c8f1141/screenshots.png --------------------------------------------------------------------------------