123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713 |
- /*
-
- MIT License (MIT)
-
- Copyright (c) 2015 Clement CN Tsang
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-
- */
- #import <PureLayout/PureLayout.h>
- #import "CTAssetScrollView.h"
- #import "CTAssetPlayButton.h"
- #import "PHAsset+CTAssetsPickerController.h"
- #import "NSBundle+CTAssetsPickerController.h"
- #import "UIImage+CTAssetsPickerController.h"
- NSString * const CTAssetScrollViewDidTapNotification = @"CTAssetScrollViewDidTapNotification";
- NSString * const CTAssetScrollViewPlayerWillPlayNotification = @"CTAssetScrollViewPlayerWillPlayNotification";
- NSString * const CTAssetScrollViewPlayerWillPauseNotification = @"CTAssetScrollViewPlayerWillPauseNotification";
- @interface CTAssetScrollView ()
- <UIScrollViewDelegate, UIGestureRecognizerDelegate>
- @property (nonatomic, strong) PHAsset *asset;
- @property (nonatomic, strong) UIImage *image;
- @property (nonatomic, strong) AVPlayer *player;
- @property (nonatomic, assign) BOOL didLoadPlayerItem;
- @property (nonatomic, assign) CGFloat perspectiveZoomScale;
- @property (nonatomic, strong) UIImageView *imageView;
- @property (nonatomic, strong) UIProgressView *progressView;
- @property (nonatomic, strong) UIActivityIndicatorView *activityView;
- @property (nonatomic, strong) CTAssetPlayButton *playButton;
- @property (nonatomic, strong) CTAssetSelectionButton *selectionButton;
- @property (nonatomic, assign) BOOL shouldUpdateConstraints;
- @property (nonatomic, assign) BOOL didSetupConstraints;
- @end
- @implementation CTAssetScrollView
- - (instancetype)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
-
- if (self)
- {
- _shouldUpdateConstraints = YES;
- self.allowsSelection = NO;
- self.showsVerticalScrollIndicator = NO;
- self.showsHorizontalScrollIndicator = NO;
- self.bouncesZoom = YES;
- self.decelerationRate = UIScrollViewDecelerationRateFast;
- self.delegate = self;
-
- [self setupViews];
- [self addGestureRecognizers];
- }
-
- return self;
- }
- - (void)dealloc
- {
- [self removePlayerNotificationObserver];
- [self removePlayerLoadedTimeRangesObserver];
- [self removePlayerRateObserver];
- }
- #pragma mark - Setup
- - (void)setupViews
- {
- UIImageView *imageView = [UIImageView new];
- imageView.isAccessibilityElement = YES;
- imageView.accessibilityTraits = UIAccessibilityTraitImage;
- self.imageView = imageView;
- [self addSubview:self.imageView];
-
- UIProgressView *progressView =
- [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
- self.progressView = progressView;
- [self addSubview:self.progressView];
-
- UIActivityIndicatorView *activityView =
- [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
- self.activityView = activityView;
- [self addSubview:self.activityView];
-
- CTAssetPlayButton *playButton = [CTAssetPlayButton newAutoLayoutView];
- self.playButton = playButton;
- [self addSubview:self.playButton];
-
- CTAssetSelectionButton *selectionButton = [CTAssetSelectionButton newAutoLayoutView];
- self.selectionButton = selectionButton;
- [self addSubview:self.selectionButton];
- }
- #pragma mark - Update auto layout constraints
- - (void)updateConstraints
- {
- if (!self.didSetupConstraints)
- {
- [self updateSelectionButtonIfNeeded];
- [self autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsZero];
- [self updateProgressConstraints];
- [self updateActivityConstraints];
- [self updateButtonsConstraints];
-
- self.didSetupConstraints = YES;
- }
- [self updateContentFrame];
- [super updateConstraints];
- }
- - (void)updateSelectionButtonIfNeeded
- {
- if (!self.allowsSelection)
- {
- [self.selectionButton removeFromSuperview];
- self.selectionButton = nil;
- }
- }
- - (void)updateProgressConstraints
- {
- [NSLayoutConstraint autoSetPriority:UILayoutPriorityDefaultLow forConstraints:^{
- [self.progressView autoConstrainAttribute:ALAttributeLeading toAttribute:ALAttributeLeading ofView:self.superview withMultiplier:1 relation:NSLayoutRelationEqual];
- [self.progressView autoConstrainAttribute:ALAttributeTrailing toAttribute:ALAttributeTrailing ofView:self.superview withMultiplier:1 relation:NSLayoutRelationEqual];
- [self.progressView autoConstrainAttribute:ALAttributeBottom toAttribute:ALAttributeBottom ofView:self.superview withMultiplier:1 relation:NSLayoutRelationEqual];
- }];
-
- [NSLayoutConstraint autoSetPriority:UILayoutPriorityDefaultHigh forConstraints:^{
- [self.progressView autoConstrainAttribute:ALAttributeLeading toAttribute:ALAttributeLeading ofView:self.imageView withMultiplier:1 relation:NSLayoutRelationGreaterThanOrEqual];
- [self.progressView autoConstrainAttribute:ALAttributeTrailing toAttribute:ALAttributeTrailing ofView:self.imageView withMultiplier:1 relation:NSLayoutRelationLessThanOrEqual];
- [self.progressView autoConstrainAttribute:ALAttributeBottom toAttribute:ALAttributeBottom ofView:self.imageView withMultiplier:1 relation:NSLayoutRelationLessThanOrEqual];
- }];
- }
- - (void)updateActivityConstraints
- {
- [self.activityView autoAlignAxis:ALAxisVertical toSameAxisOfView:self.superview];
- [self.activityView autoAlignAxis:ALAxisHorizontal toSameAxisOfView:self.superview];
- }
- - (void)updateButtonsConstraints
- {
- [self.playButton autoAlignAxis:ALAxisVertical toSameAxisOfView:self.superview];
- [self.playButton autoAlignAxis:ALAxisHorizontal toSameAxisOfView:self.superview];
-
- [NSLayoutConstraint autoSetPriority:UILayoutPriorityDefaultLow forConstraints:^{
- [self.selectionButton autoConstrainAttribute:ALAttributeTrailing toAttribute:ALAttributeTrailing ofView:self.superview withOffset:-self.layoutMargins.right relation:NSLayoutRelationEqual];
- [self.selectionButton autoConstrainAttribute:ALAttributeBottom toAttribute:ALAttributeBottom ofView:self.superview withOffset:-self.layoutMargins.bottom relation:NSLayoutRelationEqual];
- }];
-
- [NSLayoutConstraint autoSetPriority:UILayoutPriorityDefaultHigh forConstraints:^{
- [self.selectionButton autoConstrainAttribute:ALAttributeTrailing toAttribute:ALAttributeTrailing ofView:self.imageView withOffset:-self.layoutMargins.right relation:NSLayoutRelationLessThanOrEqual];
- [self.selectionButton autoConstrainAttribute:ALAttributeBottom toAttribute:ALAttributeBottom ofView:self.imageView withOffset:-self.layoutMargins.bottom relation:NSLayoutRelationLessThanOrEqual];
- }];
- }
- - (void)updateContentFrame
- {
- CGSize boundsSize = self.bounds.size;
-
- CGFloat w = self.zoomScale * self.asset.pixelWidth;
- CGFloat h = self.zoomScale * self.asset.pixelHeight;
-
- CGFloat dx = (boundsSize.width - w) / 2.0;
- CGFloat dy = (boundsSize.height - h) / 2.0;
- self.contentOffset = CGPointZero;
- self.imageView.frame = CGRectMake(dx, dy, w, h);
- }
- #pragma mark - Start/stop loading animation
- - (void)startActivityAnimating
- {
- [self.playButton setHidden:YES];
- [self.selectionButton setHidden:YES];
- [self.activityView startAnimating];
- [self postPlayerWillPlayNotification];
- }
- - (void)stopActivityAnimating
- {
- [self.playButton setHidden:NO];
- [self.selectionButton setHidden:NO];
- [self.activityView stopAnimating];
- [self postPlayerWillPauseNotification];
- }
- #pragma mark - Set progress
- - (void)setProgress:(CGFloat)progress
- {
- #if !defined(CT_APP_EXTENSIONS)
- [UIApplication sharedApplication].networkActivityIndicatorVisible = progress < 1;
- #endif
- [self.progressView setProgress:progress animated:(progress < 1)];
- self.progressView.hidden = progress == 1;
- }
- // To mimic image downloading progress
- // as PHImageRequestOptions does not work as expected
- - (void)mimicProgress
- {
- CGFloat progress = self.progressView.progress;
- if (progress < 0.95)
- {
- int lowerbound = progress * 100 + 1;
- int upperbound = 95;
-
- int random = lowerbound + arc4random() % (upperbound - lowerbound);
- CGFloat randomProgress = random / 100.0f;
- [self setProgress:randomProgress];
-
- NSInteger randomDelay = 1 + arc4random() % (3 - 1);
- [self performSelector:@selector(mimicProgress) withObject:nil afterDelay:randomDelay];
- }
- }
- #pragma mark - asset size
- - (CGSize)assetSize
- {
- return CGSizeMake(self.asset.pixelWidth, self.asset.pixelHeight);
- }
- #pragma mark - Bind asset image
- - (void)bind:(PHAsset *)asset image:(UIImage *)image requestInfo:(NSDictionary *)info
- {
- self.asset = asset;
- self.imageView.accessibilityLabel = asset.accessibilityLabel;
- self.playButton.hidden = [asset ctassetsPickerIsPhoto];
-
- BOOL isDegraded = [info[PHImageResultIsDegradedKey] boolValue];
-
- if (self.image == nil || !isDegraded)
- {
- BOOL zoom = (!self.image);
- self.image = image;
- self.imageView.image = image;
-
- if (isDegraded)
- [self mimicProgress];
- else
- [self setProgress:1];
- [self setNeedsUpdateConstraints];
- [self updateConstraintsIfNeeded];
- [self updateZoomScalesAndZoom:zoom];
- }
- }
- #pragma mark - Bind player item
- - (void)bind:(AVPlayerItem *)playerItem requestInfo:(NSDictionary *)info
- {
- [self unbindPlayerItem];
-
- AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
- AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
- playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
- CALayer *layer = self.imageView.layer;
- [layer addSublayer:playerLayer];
- playerLayer.frame = layer.bounds;
-
- self.player = player;
- [self addPlayerNotificationObserver];
- [self addPlayerLoadedTimeRangesObserver];
- }
- - (void)unbindPlayerItem
- {
- [self removePlayerNotificationObserver];
- [self removePlayerLoadedTimeRangesObserver];
- for (CALayer *layer in self.imageView.layer.sublayers)
- [layer removeFromSuperlayer];
-
- self.player = nil;
- }
- #pragma mark - Upate zoom scales
- - (void)updateZoomScalesAndZoom:(BOOL)zoom
- {
- if (!self.asset)
- return;
-
- CGSize assetSize = [self assetSize];
- CGSize boundsSize = self.bounds.size;
-
- CGFloat xScale = boundsSize.width / assetSize.width; //scale needed to perfectly fit the image width-wise
- CGFloat yScale = boundsSize.height / assetSize.height; //scale needed to perfectly fit the image height-wise
-
- CGFloat minScale = MIN(xScale, yScale);
- CGFloat maxScale = 3.0 * minScale;
-
- if ([self.asset ctassetsPickerIsVideo])
- {
- self.minimumZoomScale = minScale;
- self.maximumZoomScale = minScale;
- }
-
- else
- {
- self.minimumZoomScale = minScale;
- self.maximumZoomScale = maxScale;
- }
-
- // update perspective zoom scale
- self.perspectiveZoomScale = (boundsSize.width > boundsSize.height) ? xScale : yScale;
-
- if (zoom)
- [self zoomToInitialScale];
- }
- #pragma mark - Zoom
- - (void)zoomToInitialScale
- {
- if ([self canPerspectiveZoom])
- [self zoomToPerspectiveZoomScaleAnimated:NO];
- else
- [self zoomToMinimumZoomScaleAnimated:NO];
- }
- - (void)zoomToMinimumZoomScaleAnimated:(BOOL)animated
- {
- [self setZoomScale:self.minimumZoomScale animated:animated];
- }
- - (void)zoomToMaximumZoomScaleWithGestureRecognizer:(UITapGestureRecognizer *)recognizer
- {
- CGRect zoomRect = [self zoomRectWithScale:self.maximumZoomScale withCenter:[recognizer locationInView:recognizer.view]];
- self.shouldUpdateConstraints = NO;
-
- [UIView animateWithDuration:0.3 animations:^{
- [self zoomToRect:zoomRect animated:NO];
-
- CGRect frame = self.imageView.frame;
- frame.origin.x = 0;
- frame.origin.y = 0;
- self.imageView.frame = frame;
- }];
- }
- #pragma mark - Perspective zoom
- - (BOOL)canPerspectiveZoom
- {
- CGSize assetSize = [self assetSize];
- CGSize boundsSize = self.bounds.size;
-
- CGFloat assetRatio = assetSize.width / assetSize.height;
- CGFloat boundsRatio = boundsSize.width / boundsSize.height;
-
- // can perform perspective zoom when the difference of aspect ratios is smaller than 20%
- return (fabs( (assetRatio - boundsRatio) / boundsRatio ) < 0.2f);
- }
- - (void)zoomToPerspectiveZoomScaleAnimated:(BOOL)animated;
- {
- CGRect zoomRect = [self zoomRectWithScale:self.perspectiveZoomScale];
- [self zoomToRect:zoomRect animated:animated];
- }
- - (CGRect)zoomRectWithScale:(CGFloat)scale
- {
- CGSize targetSize;
- targetSize.width = self.bounds.size.width / scale;
- targetSize.height = self.bounds.size.height / scale;
-
- CGPoint targetOrigin;
- targetOrigin.x = (self.asset.pixelWidth - targetSize.width) / 2.0;
- targetOrigin.y = (self.asset.pixelHeight - targetSize.height) / 2.0;
-
- CGRect zoomRect;
- zoomRect.origin = targetOrigin;
- zoomRect.size = targetSize;
- return zoomRect;
- }
- #pragma mark - Zoom with gesture recognizer
- - (void)zoomWithGestureRecognizer:(UITapGestureRecognizer *)recognizer
- {
- if (self.minimumZoomScale == self.maximumZoomScale)
- return;
-
- if ([self canPerspectiveZoom])
- {
- if ((self.zoomScale >= self.minimumZoomScale && self.zoomScale < self.perspectiveZoomScale) ||
- (self.zoomScale <= self.maximumZoomScale && self.zoomScale > self.perspectiveZoomScale))
- [self zoomToPerspectiveZoomScaleAnimated:YES];
- else
- [self zoomToMaximumZoomScaleWithGestureRecognizer:recognizer];
-
- return;
- }
-
- if (self.zoomScale < self.maximumZoomScale)
- [self zoomToMaximumZoomScaleWithGestureRecognizer:recognizer];
- else
- [self zoomToMinimumZoomScaleAnimated:YES];
- }
- - (CGRect)zoomRectWithScale:(CGFloat)scale withCenter:(CGPoint)center
- {
- center = [self.imageView convertPoint:center fromView:self];
-
- CGRect zoomRect;
-
- zoomRect.size.height = self.imageView.frame.size.height / scale;
- zoomRect.size.width = self.imageView.frame.size.width / scale;
-
- zoomRect.origin.x = center.x - ((zoomRect.size.width / 2.0));
- zoomRect.origin.y = center.y - ((zoomRect.size.height / 2.0));
-
- return zoomRect;
- }
- #pragma mark - Gesture recognizers
- - (void)addGestureRecognizers
- {
- UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapping:)];
- UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapping:)];
-
- doubleTap.numberOfTapsRequired = 2.0;
- [singleTap requireGestureRecognizerToFail:doubleTap];
-
- singleTap.delegate = self;
- doubleTap.delegate = self;
-
- [self addGestureRecognizer:singleTap];
- [self addGestureRecognizer:doubleTap];
- }
- #pragma mark - Handle tappings
- - (void)handleTapping:(UITapGestureRecognizer *)recognizer
- {
- [[NSNotificationCenter defaultCenter] postNotificationName:CTAssetScrollViewDidTapNotification object:recognizer];
-
- if (recognizer.numberOfTapsRequired == 2)
- [self zoomWithGestureRecognizer:recognizer];
- }
- #pragma mark - Scroll view delegate
- - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
- {
- return self.imageView;
- }
- - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
- {
- self.shouldUpdateConstraints = YES;
- }
- - (void)scrollViewDidZoom:(UIScrollView *)scrollView
- {
- self.scrollEnabled = self.zoomScale != self.perspectiveZoomScale;
-
- if (self.shouldUpdateConstraints)
- {
- [self setNeedsUpdateConstraints];
- [self updateConstraintsIfNeeded];
- }
- }
- #pragma mark - Gesture recognizer delegate
- - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
- {
- return !([touch.view isDescendantOfView:self.playButton] || [touch.view isDescendantOfView:self.selectionButton]);
- }
- #pragma mark - Notification observer
- - (void)addPlayerNotificationObserver
- {
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
-
- [center addObserver:self
- selector:@selector(applicationWillResignActive:)
- name:UIApplicationWillResignActiveNotification
- object:nil];
- }
- - (void)removePlayerNotificationObserver
- {
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- [center removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
- }
- #pragma mark - Video player item key-value observer
- - (void)addPlayerLoadedTimeRangesObserver
- {
- [self.player addObserver:self
- forKeyPath:@"currentItem.loadedTimeRanges"
- options:NSKeyValueObservingOptionNew
- context:nil];
- }
- - (void)removePlayerLoadedTimeRangesObserver
- {
- @try {
- [self.player removeObserver:self forKeyPath:@"currentItem.loadedTimeRanges"];
- }
- @catch (NSException *exception) {
- // do nothing
- }
- }
- - (void)addPlayerRateObserver
- {
- [self.player addObserver:self
- forKeyPath:@"rate"
- options:NSKeyValueObservingOptionNew
- context:nil];
- }
- - (void)removePlayerRateObserver
- {
- @try {
- [self.player removeObserver:self forKeyPath:@"rate"];
- }
- @catch (NSException *exception) {
- // do nothing
- }
- }
- #pragma mark - Video playback Key-Value changed
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
- {
- if (object == self.player && [keyPath isEqual:@"currentItem.loadedTimeRanges"])
- {
- NSArray *timeRanges = change[NSKeyValueChangeNewKey];
- if (timeRanges && timeRanges.count)
- {
- CMTimeRange timeRange = [timeRanges.firstObject CMTimeRangeValue];
-
- if (CMTIME_COMPARE_INLINE(timeRange.duration, ==, self.player.currentItem.duration))
- [self performSelector:@selector(playerDidLoadItem:) withObject:object];
- }
- }
-
- if (object == self.player && [keyPath isEqual:@"rate"])
- {
- CGFloat rate = [[change valueForKey:NSKeyValueChangeNewKey] floatValue];
-
- if (rate > 0)
- [self performSelector:@selector(playerDidPlay:) withObject:object];
-
- if (rate == 0)
- [self performSelector:@selector(playerDidPause:) withObject:object];
- }
- }
- #pragma mark - Notifications
- - (void)postPlayerWillPlayNotification
- {
- [[NSNotificationCenter defaultCenter] postNotificationName:CTAssetScrollViewPlayerWillPlayNotification object:nil];
- }
- - (void)postPlayerWillPauseNotification
- {
- [[NSNotificationCenter defaultCenter] postNotificationName:CTAssetScrollViewPlayerWillPauseNotification object:nil];
- }
- #pragma mark - Playback events
- - (void)applicationWillResignActive:(NSNotification *)notification
- {
- [self pauseVideo];
- }
- - (void)playerDidPlay:(id)sender
- {
- [self setProgress:1];
- [self.playButton setHidden:YES];
- [self.selectionButton setHidden:YES];
- [self.activityView stopAnimating];
- }
- - (void)playerDidPause:(id)sender
- {
- [self.playButton setHidden:NO];
- [self.selectionButton setHidden:NO];
- }
- - (void)playerDidLoadItem:(id)sender
- {
- if (!self.didLoadPlayerItem)
- {
- [self setDidLoadPlayerItem:YES];
- [self addPlayerRateObserver];
-
- [self.activityView stopAnimating];
- [self playVideo];
- }
- }
- #pragma mark - Playback
- - (void)playVideo
- {
- if (self.didLoadPlayerItem)
- {
- if (CMTIME_COMPARE_INLINE(self.player.currentTime, == , self.player.currentItem.duration))
- [self.player seekToTime:kCMTimeZero];
-
- [self postPlayerWillPlayNotification];
- [self.player play];
- }
- }
- - (void)pauseVideo
- {
- if (self.didLoadPlayerItem)
- {
- [self postPlayerWillPauseNotification];
- [self.player pause];
- }
- else
- {
- [self stopActivityAnimating];
- [self unbindPlayerItem];
- }
- }
- @end
|