Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use scrolling UITextView for captions #88

Merged
merged 25 commits into from
Jan 8, 2016
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0bdbe40
Add an example photo with extremely long caption
cdzombak Oct 30, 2015
b1319cd
Attach font sizes to captions in Example app
cdzombak Oct 30, 2015
0fdaf3a
Use UITextView for NYTPhotoCaptionView
cdzombak Oct 30, 2015
389b562
Reduce caption margins since UITextView has line fragment padding bui…
cdzombak Oct 30, 2015
1e825d9
First pass at PhotoCaptionView intrinsic content size with a text view
cdzombak Oct 30, 2015
cefbcb3
Second pass at calculating caption content size
cdzombak Oct 30, 2015
294848f
Give caption views a hint about their layout widths
cdzombak Oct 30, 2015
ee159d3
Extract NYTPhotoCaptionViewLayoutWidthHinting protocol to its own file
cdzombak Oct 30, 2015
3070605
`pod install` in Example app
cdzombak Oct 30, 2015
a9e7aa5
Use relative, not hardcoded, max caption height
cdzombak Oct 30, 2015
bee2378
Add caption max height constraint from _our_ caption class
cdzombak Oct 30, 2015
055ca60
Mark PhotoCaptionView as requiring constraint-based layout
cdzombak Nov 2, 2015
e7230df
PhotoCaptionView takes only 30% of height
cdzombak Nov 2, 2015
f88bad8
Resolve iOS 8.x gradient-layer layout bug
cdzombak Nov 2, 2015
f29731d
Eliminate added vertical padding on PhotoCaptionView
cdzombak Nov 2, 2015
11b47eb
Merge remote-tracking branch 'origin/develop' into cdz/scroll-captions
cdzombak Nov 2, 2015
81c1014
Standardize PhotoCaptionView.preferredMaxLayoutWidth on setting it
cdzombak Nov 2, 2015
20eca18
Use textContainerInsets for padding PhotoCaptionView
cdzombak Nov 2, 2015
a5a5441
[minor] update forgotten header comments
cdzombak Nov 2, 2015
7c59992
[minor] fix misspelled constant in PhotosViewController
cdzombak Nov 2, 2015
162e0ba
Check for protocol conformance, not a specific method, before casting
cdzombak Nov 2, 2015
4acbeeb
Use an enum for example photo indices
cdzombak Nov 3, 2015
5d1a27d
Merge remote-tracking branch 'origin/develop' into cdz/scroll-captions
cdzombak Jan 4, 2016
211d897
Resolve warning about unhandled case in Example project
cdzombak Jan 4, 2016
0cd6a1e
Merge remote-tracking branch 'origin/develop' into cdz/scroll-captions
cdzombak Jan 7, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions Example/NYTPhotoViewer/NYTViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import "NYTExamplePhoto.h"

static const NSUInteger NYTViewControllerCustomEverythingPhotoIndex = 1;
static const NSUInteger NYTViewControllerLongCaptionPhotoIndex = 2;
static const NSUInteger NYTViewControllerDefaultLoadingSpinnerPhotoIndex = 3;
static const NSUInteger NYTViewControllerNoReferenceViewPhotoIndex = 4;
static const NSUInteger NYTViewControllerCustomMaxZoomScalePhotoIndex = 5;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just curious as to why not just make these static ints an enum.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

¯_(ツ)_/¯ they were static ints before, and slowly we've added a few more special cases.

Expand Down Expand Up @@ -62,10 +63,28 @@ + (NSArray *)newTestPhotos {
if (i == NYTViewControllerCustomEverythingPhotoIndex) {
photo.placeholderImage = [UIImage imageNamed:@"NYTimesBuildingPlaceholder"];
}

NSString *caption = @"summary";
if (i == NYTViewControllerCustomEverythingPhotoIndex) {
caption = @"photo with custom everything";
}
else if (i == NYTViewControllerLongCaptionPhotoIndex) {
caption = @"photo with long caption. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum maximus laoreet vehicula. Maecenas elit quam, pellentesque at tempor vel, tempus non sem. Vestibulum ut aliquam elit. Vivamus rhoncus sapien turpis, at feugiat augue luctus id. Nulla mi urna, viverra sed augue malesuada, bibendum bibendum massa. Cras urna nibh, lacinia vitae feugiat eu, consectetur a tellus. Morbi venenatis nunc sit amet varius pretium. Duis eget sem nec nulla lobortis finibus. Nullam pulvinar gravida est eget tristique. Curabitur faucibus nisl eu diam ullamcorper, at pharetra eros dictum. Suspendisse nibh urna, ultrices a augue a, euismod mattis felis. Ut varius tortor ac efficitur pellentesque. Mauris sit amet rhoncus dolor. Proin vel porttitor mi. Pellentesque lobortis interdum turpis, vitae tincidunt purus vestibulum vel. Phasellus tincidunt vel mi sit amet congue.";
}
else if (i == NYTViewControllerDefaultLoadingSpinnerPhotoIndex) {
caption = @"photo with loading spinner";
}
else if (i == NYTViewControllerNoReferenceViewPhotoIndex) {
caption = @"photo without reference view";
}
else if (i == NYTViewControllerCustomMaxZoomScalePhotoIndex) {
caption = @"photo with custom maximum zoom scale";
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again mostly curious, but this seems like a good place for a switch statement to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, especially if these were an enum.


photo.attributedCaptionTitle = [[NSAttributedString alloc] initWithString:@(i + 1).stringValue attributes:@{NSForegroundColorAttributeName: [UIColor whiteColor]}];
photo.attributedCaptionSummary = [[NSAttributedString alloc] initWithString:@"summary" attributes:@{NSForegroundColorAttributeName: [UIColor grayColor]}];
photo.attributedCaptionCredit = [[NSAttributedString alloc] initWithString:@"credit" attributes:@{NSForegroundColorAttributeName: [UIColor darkGrayColor]}];
photo.attributedCaptionTitle = [[NSAttributedString alloc] initWithString:@(i + 1).stringValue attributes:@{NSForegroundColorAttributeName: [UIColor whiteColor], NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleBody]}];
photo.attributedCaptionSummary = [[NSAttributedString alloc] initWithString:caption attributes:@{NSForegroundColorAttributeName: [UIColor lightGrayColor], NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleBody]}];
photo.attributedCaptionCredit = [[NSAttributedString alloc] initWithString:@"credit" attributes:@{NSForegroundColorAttributeName: [UIColor grayColor], NSFontAttributeName: [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1]}];

[photos addObject:photo];
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1,206 changes: 605 additions & 601 deletions Example/Pods/Pods.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 2 additions & 6 deletions Pod/Classes/ios/NYTPhotoCaptionView.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,12 @@
//

@import UIKit;

/**
* The left and right margin around the content.
*/
extern const CGFloat NYTPhotoCaptionViewHorizontalMargin;
#import "NYTPhotoCaptionViewLayoutWidthHinting.h"

/**
* A view used to display the caption for a photo.
*/
@interface NYTPhotoCaptionView : UIView
@interface NYTPhotoCaptionView : UIView <NYTPhotoCaptionViewLayoutWidthHinting>

/**
* Designated initializer that takes all the caption attributed strings as arguments.
Expand Down
74 changes: 56 additions & 18 deletions Pod/Classes/ios/NYTPhotoCaptionView.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

#import "NYTPhotoCaptionView.h"

const CGFloat NYTPhotoCaptionViewHorizontalMargin = 16.0;
static const CGFloat NYTPhotoCaptionViewVerticalMargin = 12.0;
static const CGFloat NYTPhotoCaptionViewHorizontalMargin = 8.0;
static const CGFloat NYTPhotoCaptionViewVerticalMargin = 7.0;

@interface NYTPhotoCaptionView ()

Expand All @@ -19,13 +19,15 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
@property (nonatomic, readonly) NSAttributedString *attributedSummary;
@property (nonatomic, readonly) NSAttributedString *attributedCredit;

@property (nonatomic) UILabel *textLabel;
@property (nonatomic) UITextView *textView;
@property (nonatomic) CAGradientLayer *gradientLayer;

@end

@implementation NYTPhotoCaptionView

@synthesize preferredMaxLayoutWidth = _preferredMaxLayoutWidth;

#pragma mark - UIView

- (instancetype)initWithFrame:(CGRect)frame {
Expand All @@ -42,10 +44,42 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder {
return self;
}

+ (BOOL)requiresConstraintBasedLayout {
return YES;
}

- (void)didMoveToSuperview {
[super didMoveToSuperview];

NSLayoutConstraint *maxHeightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.superview attribute:NSLayoutAttributeHeight multiplier:0.3f constant:0.0f];
[self.superview addConstraint:maxHeightConstraint];
}

- (void)layoutSubviews {
[super layoutSubviews];

self.gradientLayer.frame = self.layer.bounds;

// On iOS 8.x, when this view is height-constrained, neither `self.bounds` nor `self.layer.bounds` reflects the new layout height immediately after `[super layoutSubviews]`. Both of those properties appear correct in the next runloop.
// This problem doesn't affect iOS 9 and there may be a better solution; PRs welcome.
dispatch_async(dispatch_get_main_queue(), ^{
self.gradientLayer.frame = self.layer.bounds;
});
}

- (CGSize)intrinsicContentSize {
CGSize contentSize = [self.textView sizeThatFits:CGSizeMake(self.preferredMaxLayoutWidth, CGFLOAT_MAX)];
CGFloat width = (CGFloat)self.preferredMaxLayoutWidth;
CGFloat height = (CGFloat)ceil(contentSize.height);

return CGSizeMake(width, height);
}

- (void)setPreferredMaxLayoutWidth:(CGFloat)preferredMaxLayoutWidth {
preferredMaxLayoutWidth = (CGFloat)ceil(preferredMaxLayoutWidth);

if (ABS(_preferredMaxLayoutWidth - preferredMaxLayoutWidth) > 0.1) {
_preferredMaxLayoutWidth = preferredMaxLayoutWidth;
[self invalidateIntrinsicContentSize];
}
}

#pragma mark - NYTPhotoCaptionView
Expand All @@ -67,21 +101,25 @@ - (instancetype)initWithAttributedTitle:(NSAttributedString *)attributedTitle at
- (void)commonInit {
self.translatesAutoresizingMaskIntoConstraints = NO;

[self setupTextLabel];
[self updateTextLabelAttributedText];
[self setupTextView];
[self updateTextViewAttributedText];
[self setupGradient];
}

- (void)setupTextLabel {
self.textLabel = [[UILabel alloc] init];
self.textLabel.numberOfLines = 0;
self.textLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:self.textLabel];
- (void)setupTextView {
self.textView = [[UITextView alloc] initWithFrame:CGRectZero textContainer:nil];
self.textView.translatesAutoresizingMaskIntoConstraints = NO;
self.textView.editable = NO;
self.textView.dataDetectorTypes = UIDataDetectorTypeNone;
self.textView.backgroundColor = [UIColor clearColor];
self.textView.textContainerInset = UIEdgeInsetsMake(NYTPhotoCaptionViewVerticalMargin, NYTPhotoCaptionViewHorizontalMargin, NYTPhotoCaptionViewVerticalMargin, NYTPhotoCaptionViewHorizontalMargin);

[self addSubview:self.textView];

NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:NYTPhotoCaptionViewVerticalMargin];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-NYTPhotoCaptionViewVerticalMargin];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:-NYTPhotoCaptionViewHorizontalMargin * 2.0];
NSLayoutConstraint *horizontalPositionConstraint = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.textView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:self.textView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.textView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0];
NSLayoutConstraint *horizontalPositionConstraint = [NSLayoutConstraint constraintWithItem:self.textView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0];

[self addConstraints:@[topConstraint, bottomConstraint, widthConstraint, horizontalPositionConstraint]];
}
Expand All @@ -93,7 +131,7 @@ - (void)setupGradient {
[self.layer insertSublayer:self.gradientLayer atIndex:0];
}

- (void)updateTextLabelAttributedText {
- (void)updateTextViewAttributedText {
NSMutableAttributedString *attributedLabelText = [[NSMutableAttributedString alloc] init];

if (self.attributedTitle) {
Expand All @@ -116,7 +154,7 @@ - (void)updateTextLabelAttributedText {
[attributedLabelText appendAttributedString:self.attributedCredit];
}

self.textLabel.attributedText = attributedLabelText;
self.textView.attributedText = attributedLabelText;
}

@end
5 changes: 5 additions & 0 deletions Pod/Classes/ios/NYTPhotosOverlayView.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

#import "NYTPhotosOverlayView.h"
#import "NYTPhotoCaptionViewLayoutWidthHinting.h"

@interface NYTPhotosOverlayView ()

Expand Down Expand Up @@ -49,6 +50,10 @@ - (void)layoutSubviews {
}];

[super layoutSubviews];

if ([self.captionView conformsToProtocol:@protocol(NYTPhotoCaptionViewLayoutWidthHinting)]) {
[(id<NYTPhotoCaptionViewLayoutWidthHinting>) self.captionView setPreferredMaxLayoutWidth:self.bounds.size.width];
}
}

#pragma mark - NYTPhotosOverlayView
Expand Down
2 changes: 1 addition & 1 deletion Pod/Classes/ios/NYTPhotosViewController.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// NYTPhotosViewController.h
// NYTNewsReader
// NYTPhotoViewer
//
// Created by Brian Capps on 2/10/15.
// Copyright (c) 2015 NYTimes. All rights reserved.
Expand Down
9 changes: 4 additions & 5 deletions Pod/Classes/ios/NYTPhotosViewController.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// NYTPhotosViewController.m
// NYTNewsReader
// NYTPhotoViewer
//
// Created by Brian Capps on 2/10/15.
// Copyright (c) 2015 NYTimes. All rights reserved.
Expand All @@ -23,7 +23,7 @@

static const CGFloat NYTPhotosViewControllerOverlayAnimationDuration = 0.2;
static const CGFloat NYTPhotosViewControllerInterPhotoSpacing = 16.0;
static const UIEdgeInsets NYTPhotosViewControllerCloseButtinImageInsets = {3, 0, -3, 0};
static const UIEdgeInsets NYTPhotosViewControllerCloseButtonImageInsets = {3, 0, -3, 0};

@interface NYTPhotosViewController () <UIPageViewControllerDataSource, UIPageViewControllerDelegate, NYTPhotoViewControllerDelegate>

Expand Down Expand Up @@ -171,10 +171,9 @@ - (void)commonInitWithPhotos:(NSArray *)photos initialPhoto:(id <NYTPhoto>)initi
self.transitioningDelegate = _transitionController;
self.modalPresentationCapturesStatusBarAppearance = YES;

// iOS 7 has an issue with constraints that could evaluate to be negative, so we set the width to the margins' size.
_overlayView = [[NYTPhotosOverlayView alloc] initWithFrame:CGRectMake(0, 0, NYTPhotoCaptionViewHorizontalMargin * 2.0, 0)];
_overlayView = [[NYTPhotosOverlayView alloc] initWithFrame:CGRectZero];
_overlayView.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"NYTPhotoViewerCloseButtonX" inBundle:[NSBundle nyt_photoViewerResourceBundle] compatibleWithTraitCollection:nil] landscapeImagePhone:[UIImage imageNamed:@"NYTPhotoViewerCloseButtonXLandscape" inBundle:[NSBundle nyt_photoViewerResourceBundle] compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(doneButtonTapped:)];
_overlayView.leftBarButtonItem.imageInsets = NYTPhotosViewControllerCloseButtinImageInsets;
_overlayView.leftBarButtonItem.imageInsets = NYTPhotosViewControllerCloseButtonImageInsets;
_overlayView.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actionButtonTapped:)];

_notificationCenter = [[NSNotificationCenter alloc] init];
Expand Down
2 changes: 1 addition & 1 deletion Pod/Classes/ios/Protocols/NYTPhoto.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// NYTPhoto.h
// NYTNewsReader
// NYTPhotoViewer
//
// Created by Brian Capps on 2/10/15.
// Copyright (c) 2015 NYTimes. All rights reserved.
Expand Down
29 changes: 29 additions & 0 deletions Pod/Classes/ios/Protocols/NYTPhotoCaptionViewLayoutWidthHinting.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// NYTPhotoCaptionViewLayoutWidthHinting.h
// NYTPhotoViewer
//
// Created by Chris Dzombak on 10/30/15.
//
//

@import Foundation;
@import UIKit;

/**
* Allows a view to opt-in to receiving a hint of its layout width. This aids in calculating an appropriate intrinsic content size.
*/
@protocol NYTPhotoCaptionViewLayoutWidthHinting <NSObject>

/**
* The preferred maximum width, in points, of this caption view.
*
* This property works exactly as it does on `UILabel`.
*
* This property affects the size of the view when layout constraints are applied to it. During layout, if the text extends beyond the width specified by this property, the additional text is flowed to one or more new lines, thereby increasing the height of the view.
*/
@property (nonatomic) CGFloat preferredMaxLayoutWidth;

@end

@interface UILabel (NYTPhotoCaptionViewLayoutWidthHinting) <NYTPhotoCaptionViewLayoutWidthHinting>
@end
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// NYTPhotosViewControllerDataSource.h
// NYTNewsReader
// NYTPhotoViewer
//
// Created by Brian Capps on 2/10/15.
// Copyright (c) 2015 NYTimes. All rights reserved.
Expand Down