You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
6.0 KiB
177 lines
6.0 KiB
![]()
2 years ago
|
/*
|
||
|
* Copyright 2016 Google LLC. All rights reserved.
|
||
|
*
|
||
|
*
|
||
|
* 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 "GooglePlacesDemos/Samples/PagingPhotoView.h"
|
||
|
|
||
|
/**
|
||
|
* Class to store the image and text views that display the image and attributions.
|
||
|
*/
|
||
|
@interface ImageViewAndAttribution : NSObject
|
||
|
|
||
|
@property(nonatomic, strong) UIImageView *imageView;
|
||
|
|
||
|
@property(nonatomic, strong) UITextView *attributionView;
|
||
|
|
||
|
@end
|
||
|
|
||
|
@implementation ImageViewAndAttribution
|
||
|
@end
|
||
|
|
||
|
@implementation AttributedPhoto
|
||
|
@end
|
||
|
|
||
|
@interface PagingPhotoView () <UITextViewDelegate>
|
||
|
@end
|
||
|
|
||
|
@implementation PagingPhotoView {
|
||
|
// An array of |ImageViewAndAttribution| objects representing the actual views that are
|
||
|
// being displayed.
|
||
|
NSMutableArray *_photoImageViews;
|
||
|
// Whether we should update the image and attribution view frames on the next |layoutSubviews|
|
||
|
// call. This should be set to YES whenever the frame is updated or the photos change.
|
||
|
BOOL _imageLayoutUpdateNeeded;
|
||
|
}
|
||
|
|
||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||
|
if ((self = [super initWithFrame:frame])) {
|
||
|
_photoImageViews = [NSMutableArray array];
|
||
|
self.backgroundColor = [UIColor whiteColor];
|
||
|
self.pagingEnabled = YES;
|
||
|
}
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
- (void)setPhotoList:(NSArray *)photoList {
|
||
|
// First, remove all of the existing image and attribution subviews.
|
||
|
for (ImageViewAndAttribution *photoView in _photoImageViews) {
|
||
|
[photoView.imageView removeFromSuperview];
|
||
|
[photoView.attributionView removeFromSuperview];
|
||
|
}
|
||
|
[_photoImageViews removeAllObjects];
|
||
|
|
||
|
// Add the new images and attributions as subviews.
|
||
|
_photoList = [photoList copy];
|
||
|
for (AttributedPhoto *photo in photoList) {
|
||
|
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectZero];
|
||
|
textView.delegate = self;
|
||
|
textView.editable = NO;
|
||
|
textView.attributedText = photo.attributions;
|
||
|
[self addSubview:textView];
|
||
|
|
||
|
UIImageView *imageView = [[UIImageView alloc] initWithImage:photo.image];
|
||
|
imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||
|
imageView.clipsToBounds = YES;
|
||
|
[self addSubview:imageView];
|
||
|
|
||
|
ImageViewAndAttribution *attributedView = [[ImageViewAndAttribution alloc] init];
|
||
|
attributedView.imageView = imageView;
|
||
|
attributedView.attributionView = textView;
|
||
|
[_photoImageViews addObject:attributedView];
|
||
|
}
|
||
|
[self updateContentSize];
|
||
|
_imageLayoutUpdateNeeded = YES;
|
||
|
}
|
||
|
|
||
|
- (void)setFrame:(CGRect)frame {
|
||
|
_imageLayoutUpdateNeeded = YES;
|
||
|
|
||
|
// We want to make sure that we are still scrolled to the same photo when the frame changes.
|
||
|
// Measure the current content offset and scroll to the same fraction along the content after the
|
||
|
// frame change.
|
||
|
CGFloat scrollOffsetFraction = 0;
|
||
|
if (self.contentSize.width != 0) {
|
||
|
scrollOffsetFraction = self.contentOffset.x / self.contentSize.width;
|
||
|
}
|
||
|
[super setFrame:frame];
|
||
|
[UIView performWithoutAnimation:^{
|
||
|
[self updateContentSize];
|
||
|
self.contentOffset =
|
||
|
CGPointMake(scrollOffsetFraction * self.contentSize.width, -self.contentInset.top);
|
||
|
}];
|
||
|
}
|
||
|
|
||
|
- (void)layoutSubviews {
|
||
|
[super layoutSubviews];
|
||
|
if (_imageLayoutUpdateNeeded) {
|
||
|
[self layoutImages];
|
||
|
_imageLayoutUpdateNeeded = NO;
|
||
|
|
||
|
// Re-adjust the content offset to ensure the photos are aligned properly horizontally.
|
||
|
if (self.contentSize.width != 0) {
|
||
|
CGFloat scrollOffset =
|
||
|
(CGFloat)round((self.contentOffset.x / self.contentSize.width) * 10.0f) / 10.0f;
|
||
|
self.contentOffset =
|
||
|
CGPointMake(scrollOffset * self.contentSize.width, -self.contentInset.top);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#pragma mark - UITextViewDelegate
|
||
|
|
||
|
- (BOOL)textView:(UITextView *)textView
|
||
|
shouldInteractWithURL:(NSURL *)url
|
||
|
inRange:(NSRange)characterRange {
|
||
|
// Make links clickable.
|
||
|
return YES;
|
||
|
}
|
||
|
|
||
|
#pragma mark - Helper methods
|
||
|
|
||
|
/**
|
||
|
* Update the content size of the scroll view based on the number of photos and the view's width.
|
||
|
* This should be called whenever the frame changes or the number of photos has changed.
|
||
|
*/
|
||
|
- (void)updateContentSize {
|
||
|
CGRect insetBounds = UIEdgeInsetsInsetRect(self.bounds, self.contentInset);
|
||
|
CGFloat usableScrollViewHeight = insetBounds.size.height;
|
||
|
|
||
|
self.contentSize =
|
||
|
CGSizeMake(_photoImageViews.count * self.frame.size.width, usableScrollViewHeight);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Updates the frames of the images and attributions.
|
||
|
*/
|
||
|
- (void)layoutImages {
|
||
|
CGFloat contentWidth = 0;
|
||
|
CGFloat scrollViewWidth = self.bounds.size.width;
|
||
|
CGRect insetBounds = UIEdgeInsetsInsetRect(self.bounds, self.contentInset);
|
||
|
CGFloat usableScrollViewHeight = insetBounds.size.height;
|
||
|
|
||
|
// Lay out the images one after the other horizontally.
|
||
|
for (ImageViewAndAttribution *attributedImageView in _photoImageViews) {
|
||
|
UITextView *attributionView = attributedImageView.attributionView;
|
||
|
UIImageView *imageView = attributedImageView.imageView;
|
||
|
[attributionView sizeToFit];
|
||
|
CGFloat attributionHeight = attributionView.frame.size.height;
|
||
|
CGFloat imageHeight = usableScrollViewHeight - attributionHeight;
|
||
|
CGFloat safeAreaX = 0.0f;
|
||
|
|
||
|
// Take into account the safe areas of the device screen and do not use that space for the
|
||
|
// attribution text.
|
||
|
imageHeight -= self.safeAreaInsets.bottom;
|
||
|
safeAreaX = self.safeAreaInsets.left;
|
||
|
|
||
|
// Put the attribution view aligned to the same left edge as the photo, in the bottom left
|
||
|
// corner of the screen.
|
||
|
attributionView.frame = CGRectMake(contentWidth + safeAreaX, imageHeight,
|
||
|
scrollViewWidth - (2 * safeAreaX), attributionHeight);
|
||
|
imageView.frame = CGRectMake(contentWidth, 0, scrollViewWidth, imageHeight);
|
||
|
contentWidth += imageView.frame.size.width;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@end
|