VideoPlayerView.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /* Copyright (C) 2012 IGN Entertainment, Inc. */
  2. #import "VideoPlayerView.h"
  3. #define PLAYER_CONTROL_BAR_HEIGHT 40
  4. #define LABEL_PADDING 10
  5. #define CURRENT_POSITION_WIDTH 56
  6. #define TIME_LEFT_WIDTH 59
  7. #define ALIGNMENT_FUZZ 2
  8. #define ROUTE_BUTTON_ALIGNMENT_FUZZ 8
  9. @interface VideoPlayerView ()
  10. @property (readwrite, strong) UILabel *titleLabel;
  11. @property (readwrite, strong) UIView *playerControlBar;
  12. @property (readwrite, strong) AirplayActiveView *airplayIsActiveView;
  13. @property (readwrite, strong) UIButton *airplayButton;
  14. @property (readwrite, strong) MPVolumeView *volumeView;
  15. @property (readwrite, strong) UIButton *fullScreenButton;
  16. @property (readwrite, strong) UIButton *playPauseButton;
  17. @property (readwrite, strong) UISlider *videoScrubber;
  18. @property (readwrite, strong) UILabel *currentPositionLabel;
  19. @property (readwrite, strong) UILabel *timeLeftLabel;
  20. @property (readwrite, strong) UIProgressView *progressView;
  21. @property (readwrite, strong) UIActivityIndicatorView *activityIndicator;
  22. @property (readwrite, strong) UIButton *shareButton;
  23. @end
  24. @implementation VideoPlayerView
  25. - (id)initWithFrame:(CGRect)frame
  26. {
  27. if (self = [super initWithFrame:frame]) {
  28. _airplayIsActiveView = [[AirplayActiveView alloc] initWithFrame:CGRectZero];
  29. [_airplayIsActiveView setHidden:YES];
  30. [self addSubview:_airplayIsActiveView];
  31. _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  32. [_titleLabel setFont:[UIFont fontWithName:@"Forza-Medium" size:16.0f]];
  33. [_titleLabel setTextColor:[UIColor whiteColor]];
  34. [_titleLabel setBackgroundColor:[UIColor clearColor]];
  35. [_titleLabel setNumberOfLines:2];
  36. [_titleLabel setLineBreakMode:NSLineBreakByWordWrapping];
  37. [self addSubview:_titleLabel];
  38. _playerControlBar = [[UIView alloc] init];
  39. [_playerControlBar setOpaque:NO];
  40. [_playerControlBar setBackgroundColor:[[UIColor blackColor] colorWithAlphaComponent:0.8]];
  41. _playPauseButton = [[UIButton alloc] init];
  42. [_playPauseButton setImage:[UIImage imageNamed:@"play-button"] forState:UIControlStateNormal];
  43. [_playPauseButton setShowsTouchWhenHighlighted:YES];
  44. [_playerControlBar addSubview:_playPauseButton];
  45. _fullScreenButton = [[UIButton alloc] init];
  46. [_fullScreenButton setImage:[UIImage imageNamed:@"fullscreen-button"] forState:UIControlStateNormal];
  47. [_fullScreenButton setShowsTouchWhenHighlighted:YES];
  48. [_playerControlBar addSubview:_fullScreenButton];
  49. _progressView = [[UIProgressView alloc] init];
  50. _progressView.progressTintColor = [UIColor colorWithRed:31.0/255.0 green:31.0/255.0 blue:31.0/255.0 alpha:1.0];
  51. _progressView.trackTintColor = [UIColor darkGrayColor];
  52. [_playerControlBar addSubview:_progressView];
  53. _videoScrubber = [[UISlider alloc] init];
  54. [_videoScrubber setMinimumTrackTintColor:[UIColor redColor]];
  55. [_videoScrubber setMaximumTrackImage:[UIImage imageNamed:@"transparentBar"] forState:UIControlStateNormal];
  56. [_videoScrubber setThumbTintColor:[UIColor whiteColor]];
  57. [_playerControlBar addSubview:_videoScrubber];
  58. _volumeView = [[MPVolumeView alloc] init];
  59. [_volumeView setShowsRouteButton:YES];
  60. [_volumeView setShowsVolumeSlider:NO];
  61. [_playerControlBar addSubview:_volumeView];
  62. // Listen to alpha changes to know when other routes are available
  63. for (UIButton *button in [_volumeView subviews]) {
  64. if (![button isKindOfClass:[UIButton class]]) {
  65. continue;
  66. }
  67. [button addObserver:self forKeyPath:@"alpha" options:NSKeyValueObservingOptionNew context:nil];
  68. [self setAirplayButton:button];
  69. }
  70. _currentPositionLabel = [[UILabel alloc] init];
  71. [_currentPositionLabel setBackgroundColor:[UIColor clearColor]];
  72. [_currentPositionLabel setTextColor:[UIColor whiteColor]];
  73. [_currentPositionLabel setFont:[UIFont systemFontOfSize:14.0f]];
  74. [_currentPositionLabel setTextAlignment:NSTextAlignmentCenter];
  75. [_playerControlBar addSubview:_currentPositionLabel];
  76. _timeLeftLabel = [[UILabel alloc] init];
  77. [_timeLeftLabel setBackgroundColor:[UIColor clearColor]];
  78. [_timeLeftLabel setTextColor:[UIColor whiteColor]];
  79. [_timeLeftLabel setFont:[UIFont systemFontOfSize:14.0f]];
  80. [_timeLeftLabel setTextAlignment:NSTextAlignmentCenter];
  81. [_playerControlBar addSubview:_timeLeftLabel];
  82. _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
  83. [self addSubview:_activityIndicator];
  84. _shareButton = [[UIButton alloc] init];
  85. [_shareButton setImage:[UIImage imageNamed:@"share-button"] forState:UIControlStateNormal];
  86. [_shareButton setShowsTouchWhenHighlighted:YES];
  87. // Hide the Share Button by default after removing ShareThis
  88. _shareButton.hidden = YES;
  89. [self addSubview:_shareButton];
  90. self.controlsEdgeInsets = UIEdgeInsetsZero;
  91. }
  92. return self;
  93. }
  94. - (void)dealloc
  95. {
  96. [_airplayButton removeObserver:self forKeyPath:@"alpha"];
  97. }
  98. - (void)layoutSubviews
  99. {
  100. [super layoutSubviews];
  101. CGRect bounds = [self bounds];
  102. CGRect insetBounds = CGRectInset(UIEdgeInsetsInsetRect(bounds, self.controlsEdgeInsets), _padding, _padding);
  103. CGSize titleLabelSize = [[_titleLabel text] sizeWithFont:[_titleLabel font]
  104. constrainedToSize:CGSizeMake(insetBounds.size.width, CGFLOAT_MAX)
  105. lineBreakMode:NSLineBreakByCharWrapping];
  106. UIImage *shareImage = [UIImage imageNamed:@"share-button"];
  107. if (!_fullscreen) {
  108. CGSize twoLineSize = [@"M\nM" sizeWithFont:[_titleLabel font]
  109. constrainedToSize:CGSizeMake(insetBounds.size.width, CGFLOAT_MAX)
  110. lineBreakMode:UILineBreakModeWordWrap];
  111. self.autoresizingMask = UIViewAutoresizingNone;
  112. [_titleLabel setFrame:CGRectMake(insetBounds.origin.x + LABEL_PADDING,
  113. insetBounds.origin.y,
  114. insetBounds.size.width,
  115. titleLabelSize.height)];
  116. CGRect playerFrame = CGRectMake(0,
  117. 0,
  118. bounds.size.width,
  119. bounds.size.height - twoLineSize.height - _padding - _padding);
  120. [_airplayIsActiveView setFrame:playerFrame];
  121. [_shareButton setFrame:CGRectMake(insetBounds.size.width - shareImage.size.width, insetBounds.origin.y, shareImage.size.width, shareImage.size.height)];
  122. } else {
  123. self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  124. [_titleLabel setFrame:CGRectMake(insetBounds.origin.x + LABEL_PADDING,
  125. insetBounds.origin.y,
  126. insetBounds.size.width,
  127. titleLabelSize.height)];
  128. [_airplayIsActiveView setFrame:bounds];
  129. [_shareButton setFrame:CGRectMake(insetBounds.size.width - shareImage.size.width, insetBounds.origin.y, shareImage.size.width, shareImage.size.height)];
  130. }
  131. [_playerControlBar setFrame:CGRectMake(bounds.origin.x,
  132. bounds.size.height - PLAYER_CONTROL_BAR_HEIGHT,
  133. bounds.size.width,
  134. PLAYER_CONTROL_BAR_HEIGHT)];
  135. [_activityIndicator setFrame:CGRectMake((bounds.size.width - _activityIndicator.frame.size.width)/2.0,
  136. (bounds.size.height - _activityIndicator.frame.size.width)/2.0,
  137. _activityIndicator.frame.size.width,
  138. _activityIndicator.frame.size.height)];
  139. [_playPauseButton setFrame:CGRectMake(0,
  140. 0,
  141. PLAYER_CONTROL_BAR_HEIGHT,
  142. PLAYER_CONTROL_BAR_HEIGHT)];
  143. CGRect fullScreenButtonFrame = CGRectMake(bounds.size.width - PLAYER_CONTROL_BAR_HEIGHT,
  144. 0,
  145. PLAYER_CONTROL_BAR_HEIGHT,
  146. PLAYER_CONTROL_BAR_HEIGHT);
  147. [_fullScreenButton setFrame:fullScreenButtonFrame];
  148. CGRect routeButtonRect = CGRectZero;
  149. _volumeView.hidden = YES;
  150. if (NO/*[_airplayButton alpha] > 0*/) {
  151. if ([_volumeView respondsToSelector:@selector(routeButtonRectForBounds:)]) {
  152. routeButtonRect = [_volumeView routeButtonRectForBounds:bounds];
  153. } else {
  154. routeButtonRect = CGRectMake(0, 0, 24, 18);
  155. }
  156. [_volumeView setFrame:CGRectMake(CGRectGetMinX(fullScreenButtonFrame) - routeButtonRect.size.width
  157. - ROUTE_BUTTON_ALIGNMENT_FUZZ,
  158. PLAYER_CONTROL_BAR_HEIGHT / 2 - routeButtonRect.size.height / 2,
  159. routeButtonRect.size.width,
  160. routeButtonRect.size.height)];
  161. }
  162. [_currentPositionLabel setFrame:CGRectMake(PLAYER_CONTROL_BAR_HEIGHT,
  163. ALIGNMENT_FUZZ,
  164. CURRENT_POSITION_WIDTH,
  165. PLAYER_CONTROL_BAR_HEIGHT)];
  166. [_timeLeftLabel setFrame:CGRectMake(bounds.size.width - PLAYER_CONTROL_BAR_HEIGHT - TIME_LEFT_WIDTH
  167. - routeButtonRect.size.width,
  168. ALIGNMENT_FUZZ,
  169. TIME_LEFT_WIDTH,
  170. PLAYER_CONTROL_BAR_HEIGHT)];
  171. CGRect scrubberRect = CGRectMake(PLAYER_CONTROL_BAR_HEIGHT + CURRENT_POSITION_WIDTH,
  172. 0,
  173. bounds.size.width - (PLAYER_CONTROL_BAR_HEIGHT * 2) - TIME_LEFT_WIDTH -
  174. CURRENT_POSITION_WIDTH - (TIME_LEFT_WIDTH - CURRENT_POSITION_WIDTH)
  175. - routeButtonRect.size.width,
  176. PLAYER_CONTROL_BAR_HEIGHT);
  177. [_videoScrubber setFrame:scrubberRect];
  178. CGRect progressViewFrameWithOffset = [_videoScrubber trackRectForBounds:scrubberRect];
  179. progressViewFrameWithOffset.origin.y += 3;
  180. [_progressView setFrame:progressViewFrameWithOffset];
  181. }
  182. - (void)setTitle:(NSString *)title
  183. {
  184. [_titleLabel setText:title];
  185. [self setNeedsLayout];
  186. }
  187. - (void)setFullscreen:(BOOL)fullscreen
  188. {
  189. if (_fullscreen == fullscreen) {
  190. return;
  191. }
  192. _fullscreen = fullscreen;
  193. [self setNeedsLayout];
  194. }
  195. - (CGFloat)heightForWidth:(CGFloat)width
  196. {
  197. CGSize titleLabelSize = [@"M\nM" sizeWithFont:[_titleLabel font]
  198. constrainedToSize:CGSizeMake(width - _padding - _padding, CGFLOAT_MAX)];
  199. return (width / 16 * 9) + titleLabelSize.height;
  200. }
  201. - (AVPlayer *)player
  202. {
  203. return [(AVPlayerLayer *)[self layer] player];
  204. }
  205. + (Class)layerClass
  206. {
  207. return [AVPlayerLayer class];
  208. }
  209. - (void)setPlayer:(AVPlayer *)player
  210. {
  211. [(AVPlayerLayer *)self.layer setPlayer:player];
  212. [_airplayIsActiveView setHidden:YES];
  213. [self addSubview:self.playerControlBar];
  214. }
  215. - (void)observeValueForKeyPath:(NSString *)keyPath
  216. ofObject:(id)object
  217. change:(NSDictionary *)change
  218. context:(void *)context
  219. {
  220. if (object == _airplayButton && [keyPath isEqualToString:@"alpha"]) {
  221. [self setNeedsLayout];
  222. }
  223. }
  224. @end