This repository has been archived by the owner on May 24, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
NIPhotoAlbumScrollView.m
221 lines (179 loc) · 7.87 KB
/
NIPhotoAlbumScrollView.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//
// Copyright 2011-2014 NimbusKit
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "NIPhotoAlbumScrollView.h"
#import "NIPagingScrollView+Subclassing.h"
#import "NIPhotoScrollView.h"
#import "NIPhotoAlbumScrollViewDataSource.h"
#import "NimbusCore.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "Nimbus requires ARC support."
#endif
@implementation NIPhotoAlbumScrollView {
// Configurable Properties
UIImage* _loadingImage;
BOOL _zoomingIsEnabled;
BOOL _zoomingAboveOriginalSizeIsEnabled;
}
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Default state.
self.zoomingIsEnabled = YES;
self.zoomingAboveOriginalSizeIsEnabled = YES;
}
return self;
}
- (void)setBackgroundColor:(UIColor *)backgroundColor {
[super setBackgroundColor:backgroundColor];
self.scrollView.backgroundColor = backgroundColor;
}
- (void)notifyDelegatePhotoDidLoadAtIndex:(NSInteger)photoIndex {
if (photoIndex == (self.centerPageIndex + 1)
&& [self.delegate respondsToSelector:@selector(photoAlbumScrollViewDidLoadNextPhoto:)]) {
[self.delegate photoAlbumScrollViewDidLoadNextPhoto:self];
} else if (photoIndex == (self.centerPageIndex - 1)
&& [self.delegate respondsToSelector:@selector(photoAlbumScrollViewDidLoadPreviousPhoto:)]) {
[self.delegate photoAlbumScrollViewDidLoadPreviousPhoto:self];
}
}
#pragma mark - Visible Page Management
- (void)willDisplayPage:(NIPhotoScrollView *)page {
// When we ask the data source for the image we expect the following to happen:
// 1) If the data source has any image at this index, it should return it and set the
// photoSize accordingly.
// 2) If the returned photo is not the highest quality available, the data source should
// start loading the high quality photo and set isLoading to YES.
// 3) If no photo was available, then the data source should start loading the photo
// at its highest available quality and nil should be returned. The loadingImage property
// will be displayed until the image is loaded. isLoading should be set to YES.
NIPhotoScrollViewPhotoSize photoSize = NIPhotoScrollViewPhotoSizeUnknown;
BOOL isLoading = NO;
CGSize originalPhotoDimensions = CGSizeZero;
UIImage* image = [self.dataSource photoAlbumScrollView: self
photoAtIndex: page.pageIndex
photoSize: &photoSize
isLoading: &isLoading
originalPhotoDimensions: &originalPhotoDimensions];
page.photoDimensions = originalPhotoDimensions;
// Only mark the view as loading if the center image is loading.
page.loading = (page.pageIndex == self.centerPageIndex) && isLoading;
if (nil == image) {
page.zoomingIsEnabled = NO;
[page setImage:self.loadingImage photoSize:NIPhotoScrollViewPhotoSizeUnknown];
} else {
BOOL updateImage = photoSize > page.photoSize;
if (updateImage) {
[page setImage:image photoSize:photoSize];
}
// Configure this after the image is set otherwise if the page's image isn't there
// e.g. (after prepareForReuse), zooming will always be disabled
page.zoomingIsEnabled = ([self isZoomingEnabled]
&& (NIPhotoScrollViewPhotoSizeOriginal == photoSize));
if (updateImage && NIPhotoScrollViewPhotoSizeOriginal == photoSize) {
[self notifyDelegatePhotoDidLoadAtIndex:page.pageIndex];
}
}
}
- (void)didRecyclePage:(UIView<NIPagingScrollViewPage> *)page {
// Give the data source the opportunity to kill any asynchronous operations for this
// now-recycled page.
if ([self.dataSource respondsToSelector:
@selector(photoAlbumScrollView:stopLoadingPhotoAtIndex:)]) {
[self.dataSource photoAlbumScrollView: self
stopLoadingPhotoAtIndex: page.pageIndex];
}
}
#pragma mark - NIPhotoScrollViewDelegate
- (void)photoScrollViewDidDoubleTapToZoom: (NIPhotoScrollView *)photoScrollView
didZoomIn: (BOOL)didZoomIn {
if ([self.delegate respondsToSelector:@selector(photoAlbumScrollView:didZoomIn:)]) {
[self.delegate photoAlbumScrollView:self didZoomIn:didZoomIn];
}
}
#pragma mark - Public
- (UIView<NIPagingScrollViewPage> *)pagingScrollView:(NIPagingScrollView *)pagingScrollView
pageViewForIndex:(NSInteger)pageIndex {
UIView<NIPagingScrollViewPage>* pageView = nil;
NSString* reuseIdentifier = @"photo";
pageView = [pagingScrollView dequeueReusablePageWithIdentifier:reuseIdentifier];
if (nil == pageView) {
pageView = [[NIPhotoScrollView alloc] init];
pageView.reuseIdentifier = reuseIdentifier;
pageView.backgroundColor = self.photoViewBackgroundColor;
}
NIPhotoScrollView* photoScrollView = (NIPhotoScrollView *)pageView;
photoScrollView.photoScrollViewDelegate = self;
photoScrollView.zoomingAboveOriginalSizeIsEnabled = [self isZoomingAboveOriginalSizeEnabled];
return pageView;
}
- (void)didLoadPhoto: (UIImage *)image
atIndex: (NSInteger)pageIndex
photoSize: (NIPhotoScrollViewPhotoSize)photoSize {
// This modifies the UI and therefor MUST be executed on the main thread.
NIDASSERT([NSThread isMainThread]);
for (NIPhotoScrollView* page in self.visiblePages) {
if (page.pageIndex == pageIndex) {
// Only replace the photo if it's of a higher quality than one we're already showing.
if (photoSize > page.photoSize) {
page.loading = NO;
[page setImage:image photoSize:photoSize];
page.zoomingIsEnabled = ([self isZoomingEnabled]
&& (NIPhotoScrollViewPhotoSizeOriginal == photoSize));
// Notify the delegate that the photo has been loaded.
if (NIPhotoScrollViewPhotoSizeOriginal == photoSize) {
[self notifyDelegatePhotoDidLoadAtIndex:pageIndex];
}
}
break;
}
}
}
- (void)setZoomingAboveOriginalSizeIsEnabled:(BOOL)enabled {
_zoomingAboveOriginalSizeIsEnabled = enabled;
for (NIPhotoScrollView* page in self.visiblePages) {
page.zoomingAboveOriginalSizeIsEnabled = enabled;
}
}
- (void)setPhotoViewBackgroundColor:(UIColor *)photoViewBackgroundColor {
if (_photoViewBackgroundColor != photoViewBackgroundColor) {
_photoViewBackgroundColor = photoViewBackgroundColor;
for (UIView<NIPagingScrollViewPage>* page in self.visiblePages) {
page.backgroundColor = photoViewBackgroundColor;
}
}
}
- (BOOL)hasNext {
return (self.centerPageIndex < self.numberOfPages - 1);
}
- (BOOL)hasPrevious {
return self.centerPageIndex > 0;
}
- (id<NIPhotoAlbumScrollViewDataSource>)dataSource {
NIDASSERT([[super dataSource] conformsToProtocol:@protocol(NIPhotoAlbumScrollViewDataSource)]);
return (id<NIPhotoAlbumScrollViewDataSource>)[super dataSource];
}
- (void)setDataSource:(id<NIPhotoAlbumScrollViewDataSource>)dataSource {
[super setDataSource:(id<NIPagingScrollViewDataSource>)dataSource];
}
- (id<NIPhotoAlbumScrollViewDelegate>)delegate {
id<NIPagingScrollViewDelegate> superDelegate = [super delegate];
NIDASSERT(nil == superDelegate
|| [superDelegate conformsToProtocol:@protocol(NIPhotoAlbumScrollViewDelegate)]);
return (id<NIPhotoAlbumScrollViewDelegate>)superDelegate;
}
- (void)setDelegate:(id<NIPhotoAlbumScrollViewDelegate>)delegate {
[super setDelegate:(id<NIPhotoAlbumScrollViewDelegate>)delegate];
}
@end