VideoPlayerView.m 12 KB

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