123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- /*
- * 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
|