Этот занимался моей работой уже несколько месяцев - так что пора проглотить мою гордость и протянуть руку помощи. На данный момент это делается в UIWebView как управляемая система HTML5 / JS. Но UIWebview откровенно лаконичен и надеется сделать этот последний компонент родным.
У меня есть коллекция видео и в определенные моменты времени во время видео, я вызываю страницу инструкций, которые относятся к временному периоду в видео. Элементы управления видео также действуют в качестве контроллера для страниц инструкций. Таким образом, в любой момент времени соответствующая страница анимируется на место.
Я просмотрел множество вариантов, наиболее близкий из которых - потоковое видео http и использование синхронизированных метаданных для запуска просмотра, но я храню видео локально на устройстве. И, пока еще не могу найти ничего, что выглядит так, как оно будет работать Кажется, в принципе все достаточно просто, но будь я проклят, если найду достойное решение ...
Есть идеи / указатели?
Вот последняя попытка стать нативным с этим до того, как выпадет оставшаяся часть моих волос - я думаю, что я могу видеть, куда я направляюсь в неправильном направлении, но если бы вы могли сэкономить несколько минут, я был бы очень признателен это!
ЦЕЛЬ - иметь крик, который живет под видео и содержит страницу с инструкциями. Через x секунд контент будет обновляться, чтобы соответствовать этой части видео, и сохраняться до следующего выкрики для свежего контента. Этого мне удалось добиться успешно. Когда я падаю (много), это когда я вычищаю видео назад к предыдущему разделу, контент shoutOut остается в той позиции, с которой я вычистил, и остается там навсегда. Или, если код приведен ниже, просто не появляется снова, так как для него задана видимая длительность по времени.
В любом случае, вот код ...
Заголовок:
// START:import
#import <UIKit/UIKit.h>
// START_HIGHLIGHT
#import <MediaPlayer/MPMoviePlayerController.h>
#import "CommentView.h"
// END_HIGHLIGHT
// START:def
// START:wiring
@interface MoviePlayerViewController : UIViewController {
UIView *viewForMovie;
// END:wiring
// START_HIGHLIGHT
MPMoviePlayerController *player;
// END_HIGHLIGHT
// START:wiring
UILabel *onScreenDisplayLabel;
UIScrollView *myScrollView;
NSMutableArray *keyframeTimes;
NSArray *shoutOutTexts;
NSArray *shoutOutTimes;
}
@property (nonatomic, retain) IBOutlet UIView *viewForMovie;
// END:wiring
// START_HIGHLIGHT
@property (nonatomic, retain) MPMoviePlayerController *player;
// END_HIGHLIGHT
@property (nonatomic, retain) IBOutlet UILabel *onScreenDisplayLabel;
@property (nonatomic, retain) IBOutlet UIScrollView *myScrollView;
@property (nonatomic, retain) NSMutableArray *keyframeTimes;
// START_HIGHLIGHT
-(NSURL *)movieURL;
- (void)timerAction:(NSTimer*)theTimer;
- (void) playerThumbnailImageRequestDidFinish:(NSNotification*)notification;
- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer;
- (IBAction) getInfo:(id)sender;
- (void)removeView:(NSTimer*)theTimer;
// END_HIGHLIGHT
// START:wiring
@end
// END:def
// END:wiring
// END:import
Main:
@implementation MoviePlayerViewController
// START:synth
@synthesize player;
@synthesize viewForMovie;
@synthesize onScreenDisplayLabel;
@synthesize myScrollView;
@synthesize keyframeTimes;
// END:synth
// Implement loadView to create a view hierarchy programmatically, without using a nib.
// START:viewDidLoad
// START:viewDidLoad1
- (void)viewDidLoad {
[super viewDidLoad];
keyframeTimes = [[NSMutableArray alloc] init];
shoutOutTexts = [[NSArray
arrayWithObjects:@"This is a test\nLabel at 2 secs ",
@"This is a test\nLabel at 325 secs",
nil] retain];
shoutOutTimes = [[NSArray
arrayWithObjects:[[NSNumber alloc] initWithInt: 2],
[[NSNumber alloc] initWithInt: 325],
nil] retain];
self.player = [[MPMoviePlayerController alloc] init];
self.player.contentURL = [self movieURL];
// END:viewDidLoad1
self.player.view.frame = self.viewForMovie.bounds;
self.player.view.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self.viewForMovie addSubview:player.view];
[self.player play];
// START_HIGHLIGHT
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
// END_HIGHLIGHT
// START:viewDidLoad1
[self.view addSubview:self.myScrollView];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(movieDurationAvailable:)
name:MPMovieDurationAvailableNotification
object:nil];
}
// END:viewDidLoad
// END:viewDidLoad1
// START:movieURL
-(NSURL *)movieURL
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *moviePath =
[bundle
pathForResource:@"BigBuckBunny_640x360"
ofType:@"m4v"];
if (moviePath) {
return [NSURL fileURLWithPath:moviePath];
} else {
return nil;
}
}
// END:movieURL
int position = 0;
- (void)timerAction:(NSTimer*)theTimer {
NSLog(@"hi");
int count = [shoutOutTimes count];
NSLog(@"count is at %d", count);
if (position < count) {
NSNumber *timeObj = [shoutOutTimes objectAtIndex:position];
int time = [timeObj intValue];
NSLog(@"time is at %d", time);
if (self.player.currentPlaybackTime >= time) {
CommentView *cview = [[CommentView alloc]
initWithText:[shoutOutTexts objectAtIndex:position]];
[self.player.view addSubview:cview];
position++;
[NSTimer scheduledTimerWithTimeInterval:4.0f target:self selector:@selector(removeView:) userInfo:cview repeats:NO];
}
}
}
- (void)removeView:(NSTimer*)theTimer {
UIView *view = [theTimer userInfo];
[view removeFromSuperview];
}
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
- (void) movieDurationAvailable:(NSNotification*)notification {
MPMoviePlayerController *moviePlayer = [notification object];
int duration = [moviePlayer duration];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(playerThumbnailImageRequestDidFinish:)
name:MPMoviePlayerThumbnailImageRequestDidFinishNotification
object:nil];
NSMutableArray *times = [[NSMutableArray alloc] init];
for(int i = 0; i < 20; i++) {
[times addObject:[NSNumber numberWithInt:5+i*((duration)/20)]];
}
[self.player requestThumbnailImagesAtTimes:times timeOption: MPMovieTimeOptionNearestKeyFrame];
}
int p = 0;
int ll=0;
- (void) playerThumbnailImageRequestDidFinish:(NSNotification*)notification {
NSDictionary *userInfo;
userInfo = [notification userInfo];
NSNumber *timecode;
timecode = [userInfo objectForKey: @"MPMoviePlayerThumbnailTimeKey"];
[keyframeTimes addObject: timecode];
UIImage *image;
image = [userInfo objectForKey: @"MPMoviePlayerThumbnailImageKey"];
int width = image.size.width;
int height = image.size.height;
float newwidth = 75 * ((float)width / (float)height);
self.myScrollView.contentSize = CGSizeMake((newwidth + 2) * 20, 75);
UIImageView *imgv = [[UIImageView alloc] initWithImage:image];
[imgv setUserInteractionEnabled:YES];
[imgv setFrame:CGRectMake(ll, 0, newwidth, 75.0f)];
ll+=newwidth + 2;
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(handleTapFrom:)];
[tapRecognizer setNumberOfTapsRequired:1];
[imgv addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
[myScrollView addSubview:imgv];
}
- (void) getInfo:(id)sender
{
MPMovieMediaTypeMask mask = self.player.movieMediaTypes;
NSMutableString *mediaTypes = [[NSMutableString alloc] init];
if (mask == MPMovieMediaTypeMaskNone) {
[mediaTypes appendString:@"Unknown Media Type"];
} else {
if (mask & MPMovieMediaTypeMaskAudio) {
[mediaTypes appendString:@"Audio"];
}
if (mask & MPMovieMediaTypeMaskVideo) {
[mediaTypes appendString:@"Video"];
}
}
MPMovieSourceType type = self.player.movieSourceType;
NSMutableString *sourceType = [[NSMutableString alloc] initWithString:@""];
if (type == MPMovieSourceTypeUnknown) {
[sourceType appendString:@"Source Unknown"];
} else if (type == MPMovieSourceTypeFile) {
[sourceType appendString:@"File"];
} else if (type == MPMovieSourceTypeStreaming) {
[sourceType appendString:@"Streaming"];
}
CGSize size = self.player.naturalSize;
onScreenDisplayLabel.text = [NSString stringWithFormat:@"[Type: %@] [Source: %@] [Time: %.1f of %.f secs] [Playback: %.0fx] [Size: %.0fx%.0f]",
mediaTypes,
sourceType,
self.player.currentPlaybackTime,
self.player.duration,
self.player.currentPlaybackRate,
size.width,
size.height];
}
- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer {
NSArray *subviews = [myScrollView subviews];
for (int i = 0; i < 20; i++) {
if (recognizer.view == [subviews objectAtIndex:i]) {
NSNumber *num = [keyframeTimes objectAtIndex:i];
self.player.currentPlaybackTime = [num intValue];
return;
}
}
}
@end
Заголовок представления комментария:
#import <UIKit/UIKit.h>
@interface CommentView : UIView {
}
- (id)initWithFrame:(CGRect)frame andText:(NSString *) text;
- (id)initWithText:(NSString *) text;
@end
The View View Main:
#import "CommentView.h"
@implementation CommentView
- (id)initWithFrame:(CGRect)frame andText:(NSString *) text {
if ((self = [super initWithFrame:frame])) {
UIImage *image = [UIImage imageNamed:@"comment.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[self addSubview:imageView];
CGRect rect = CGRectMake(20, 20, 200.0f, 90.0f);
UILabel *label = [[UILabel alloc] initWithFrame:rect];
label.text = text;
label.numberOfLines = 3;
label.adjustsFontSizeToFitWidth = YES;
label.textAlignment = UITextAlignmentCenter;
label.backgroundColor = [UIColor clearColor];
[self addSubview:label];
}
return self;
}
- (id)initWithText:(NSString *) text {
if ((self = [super init])) {
UIImage *image = [UIImage imageNamed:@"comment.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[self addSubview:imageView];
CGRect rect = CGRectMake(20, 20, 200.0f, 90.0f);
UILabel *label = [[UILabel alloc] initWithFrame:rect];
label.text = text;
label.numberOfLines = 3;
label.adjustsFontSizeToFitWidth = YES;
label.textAlignment = UITextAlignmentCenter;
label.backgroundColor = [UIColor clearColor];
[self addSubview:label];
}
return self;
}
- (void)dealloc {
[super dealloc];
}
@end
Кто-нибудь думает?
Ура!