ios - UITableViewCell 中的自动播放视频
<p><p>我已经阅读了关于 <code>StackOverflow</code> 自动播放视频的大部分问题,并且我能够在 <code>UITableView</code> 中自动播放它们,但我遇到的问题如下所述</p>
<ol>
<li>视频开始时滚动暂停一秒钟</li>
<li>播放前视频闪烁</li>
<li>如果我向上滚动,视频不会自动播放</li>
</ol>
<p>我想要的是在不使用任何第三方库(如 <code>ASYNCDisplayKit</code>)的情况下自动播放视频(如 Facebook)的流畅体验。
所有视频 <code>urls</code> 均来自 <code>AWSS3</code> 云端 URL。
我还上传了这个问题的视频,以防有人想看。</p>
<p> <a href="https://www.dropbox.com/s/s3llb7wvtc724k4/AutoplayNew.mov?dl=0" rel="noreferrer noopener nofollow">Video Autoplay Hiccups</a> </p>
<p><strong>这是我的完整代码</strong></p>
<pre><code>- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
PostViewModel* model = self.posts;
Post* post = model.post;
PostItems* item = model.items;
if(item.itemType == nameAndPicture) {
//Removed code as it's not related to question
}
else if(item.itemType == textContent){
//Removed code as it's not related to question
}
else if(item.itemType == images){
//Removed code as it's not related to question
}
else if(item.itemType == videos){
VideoListCell *cell = nil;
cell = (VideoListCell*);
cell.delegate = self;
cell.indexPath = indexPath;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = ;
cell.videoThumbnail.image = nil;
;
if (post.medias.count > 0) {
MediaItem* item = post.medias;
if ( == VIDEO) {
NSString* thumbnailURL = item.thumbnailUrl;
;
;
dispatch_async(dispatch_get_main_queue(), ^{
;
});
}
}
cell.clipsToBounds = YES;
return cell;
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
//Check if the cell displayed is video cell then try to autoplay the video
if(]){
VideoListCell* videoCell = (VideoListCell*)cell;
dispatch_async(dispatch_get_main_queue(), ^{
;
});
PostViewModel* model = self.posts;
Post* post = model.post;
PostItems* item = model.items;
if(item.itemType == videos){
videoCell.videoThumbnail.image = nil;
;
if (post.medias.count > 0) {
MediaItem* item = post.medias;
if ( == VIDEO) {
//dispatch_async(dispatch_get_main_queue(), ^{
NSString* profilePic = item.thumbnailUrl;
;
;
;
}
}
}
}
}
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath {
if(]){
VideoListCell* videoCell = (VideoListCell*)cell;
;
videoCell.avLayer = nil;
videoCell.videoPlayer = nil;
;
}
}
</code></pre>
<p>//视频列表单元类</p>
<pre><code>#define kHeight 200
@implementation VideoListCell
- (void)awakeFromNib {
;
UIImage* icon = [ imageTintedWithColor:kSliderDarkYellowColor];
;
UIImage* pauseIcon = [ imageTintedWithColor:kSliderDarkYellowColor];
;
;
UITapGestureRecognizer *viewTap = [initWithTarget:self action:@selector(tapOnView)];
viewTap.numberOfTapsRequired = 1;
self.viewPlayer.userInteractionEnabled = YES;
;
self.counterView.hidden = YES;
self.counterView.layer.cornerRadius = 12.0f;
self.counterView.layer.masksToBounds = YES;
//Add Gesture to label
UITapGestureRecognizer *countGesture = [initWithTarget:self action:@selector(tapOnCounterView)];
countGesture.numberOfTapsRequired = 1;
self.counterView.userInteractionEnabled = YES;
;
;
self.btnFullScreen.hidden = NO;
UIImage* fullScreenImage = [ imageTintedWithColor:kSliderDarkYellowColor];
;
}
- (void)showThumbnail:(BOOL)yesOrNo {
self.videoThumbnail.hidden = !yesOrNo;
self.viewForVideo.hidden = yesOrNo;
}
- (void)hideVideoAndShowThumbnail {
;
;
self.btnPlay.selected = NO;
self.isPlaying = NO;
}
- (void)btnFSTapped:(UIButton*)sender {
if (self.delegate && ) {
;
}
}
- (void)layoutSubviews
{
;
// if (self.avLayer) {
// ;
// }
}
- (void)initNewPlayerItem {
// Pause the existing video (if there is one)
//;
if(self.asset){
;
}
// First we need to make sure we have a valid URL
if (!self.videoURL) {
return;
}
// Create a new AVAsset from the URL
self.asset = ;
// Now we need an AVPlayerItem to pass to the AVPlayer
AVPlayerItem* item= [ initWithAsset:self.asset];
if(item){
[ addObserver:self
selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:item];
}
//;
// Finally, we set this as the current AVPlayer item
completionHandler:^{
NSError* error = nil;
AVKeyValueStatus status = ;
if (status == AVKeyValueStatusFailed) {
;
self.btnPlay.hidden = NO;
self.btnPlay.selected = NO;
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
;
;
self.btnPlay.selected = YES;
self.btnPlay.hidden = YES;
;
;
self.isPlaying = YES;
});
}];
}
- (void)playerItemDidReachEnd:(NSNotification*)notif {
id object = ;
if (object && ]) {
AVPlayerItem* item = (AVPlayerItem*);
;
}
//;
;
self.btnPlay.selected = NO;
self.btnPlay.hidden = NO;
}
-(void)prepareForReuse {
// self.videoURL = nil;
// self.videoThumbnail.image = nil;
//;
self.videoThumbnail.image = nil;
if (self.avLayer.superlayer) {
;
}
if (self.viewForVideo.subviews.count > 0) {
for (UIView* v in self.viewForVideo.subviews) {
;
}
}
self.videoURL = nil;
self.player = nil;
self.userID = nil;
self.videoItem = nil;
self.videoPlayer = nil;
self.btnPlay.selected = NO;
;
}
- (void)tapOnView {
//if(self.counterView.hidden){
if (self.delegate && ) {
;
}
//}
// else
// {
// if (self.delegate && ) {
// ;
// }
// }
}
-(void)tapOnCounterView {
if (self.delegate && ) {
;
}
}
- (void)setCounter:(NSUInteger)count {
if (count > 1) {
self.counterView.hidden = NO;
self.lblCounter.text = ;
}
else{
self.counterView.hidden = YES;
}
}
- (IBAction)btnPlayTapped:(id)sender {
//;
//if(self.counterView.hidden){
if(self.btnPlay.selected){
;
self.btnPlay.selected = NO;
}else{
;
self.btnPlay.selected = YES;
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if(self.player.player.timeControlStatus == AVPlayerTimeControlStatusPlaying){
if(self.btnPlay.hidden){
self.btnPlay.hidden = NO;
}
}
}
- (void)playVideo {
//if (!self.player) {
if () {
//Call API here and update media item object URL
dispatch_async(dispatch_get_main_queue(), ^{
//Call API here
//URL is expired then give a call to our server to generate a new URL
;
});
}
else{
if (!self.videoURL) {
dispatch_async(dispatch_get_main_queue(), ^{
;
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
;
});
}
}
}
- (void)stopVideo {
if (self.player) {
self.isPlaying = NO;
self.btnPlay.hidden = NO;
;
}
}
- (void)setMediaItem:(MediaItem*)item withUserID:(NSNumber*)userId {
self.videoObject = item;
self.userID = userId;
;
}
- (void)generatePreSignedURLWithVideoThumbnail {
if (self.videoObject.mediaUrl && ) {
//Already have pre signed url check if URL is expired
//If URL expired then call our own server to generate a new presigned URL
dispatch_async(dispatch_get_main_queue(), ^{
self.videoURL = ;
;
});
}
else if(self.videoObject.mediaUrl && ){
AppDelegate* delegate = ;
AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = ;
getPreSignedURLRequest.bucket = S3BucketName;
getPreSignedURLRequest.key = kS3OutputVideoFileInternalPath(delegate.loggedInUser.userId,,self.videoObject.mediaUrl);
getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodGET;
getPreSignedURLRequest.expires = ;
[[ getPreSignedURL:getPreSignedURLRequest]
continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(@"Error: %@",task.error);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
self.videoURL = task.result;
;
});
}
return nil;
}];
}
else{
//Generate Pre signed URL
AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = ;
getPreSignedURLRequest.bucket = S3BucketName;
getPreSignedURLRequest.key = ;
getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodGET;
getPreSignedURLRequest.expires = ;
[[ getPreSignedURL:getPreSignedURLRequest]
continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(@"Error: %@",task.error);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
self.videoURL = task.result;
;
});
}
return nil;
}];
}
}
- (void)setupPlayer {
self.btnPlay.hidden = YES;
self.videoItem = nil;
self.videoPlayer = nil;
self.videoItem = [ initWithURL:self.videoURL];
if (self.avLayer.superlayer) {
;
}
if (self.viewForVideo.subviews.count > 0) {
for (UIView* v in self.viewForVideo.subviews) {
;
}
}
self.videoPlayer = [ initWithPlayerItem:self.videoItem];
self.avLayer = ;
self.avLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
self.player = [ init];
self.player.player = self.videoPlayer;
self.player.videoGravity = AVLayerVideoGravityResizeAspectFill;
self.player.showsPlaybackControls = NO;
// Insert the player into the cell view hierarchy and setup autolayout
self.player.view.translatesAutoresizingMaskIntoConstraints = false;
;
//Trailing
NSLayoutConstraint *trailing =[NSLayoutConstraint
constraintWithItem:self.player.view
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.viewForVideo
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:0.f];
//Leading
NSLayoutConstraint *leading = [NSLayoutConstraint
constraintWithItem:self.player.view
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.viewForVideo
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.f];
//Bottom
NSLayoutConstraint *bottom =[NSLayoutConstraint
constraintWithItem:self.player.view
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.viewForVideo
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.f];
//Height to be fixed for SubView same as AdHeight
NSLayoutConstraint *height = [NSLayoutConstraint
constraintWithItem:self.player.view
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0
constant:kHeight];
//Add constraints to the Parent
;
;
;
//Add height constraint to the subview, as subview owns it.
;
;
}
- (void)generateNewPreSignedURL {
if (self.videoObject) {
NSDictionary* postParams = @{kMediaId:self.videoObject.mediaId};
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
TBWebAPIConsumer *web = ;
[web generatePreSignedURL:postParams andCompletionBlock:^(NSError *error, id serverResponse) {
// Do something...
dispatch_async(dispatch_get_main_queue(), ^{
if (error == nil){
//Parse user data here
NSDictionary* data = (NSDictionary*)serverResponse;
if (!) {
self.videoObject.mediaUrl = ;
}
if (!) {
self.videoObject.videoSignedUrlExpiry = ;
}
;
}
});
}];
});
}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
;
// Configure the view for the selected state
}
</code></pre>
<p>有人可以帮我解决这个问题吗?</p></p>
<br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
<p><p>我有一些建议给你:</p>
<ol>
<li><p>在滚动过程中不要尝试调用播放/暂停。只需在滚动停止后立即执行此操作:<a href="https://gist.github.com/k06a/731654e3168277fb1fd0e64abc7d899e" rel="noreferrer noopener nofollow">https://gist.github.com/k06a/731654e3168277fb1fd0e64abc7d899e</a> </p></li>
<li><p>你可以尝试使用这个肮脏的技巧:<a href="https://gist.github.com/k06a/66f7815b0325f239411e26f498c75755" rel="noreferrer noopener nofollow">https://gist.github.com/k06a/66f7815b0325f239411e26f498c75755</a>要对 Apple Review Team 隐藏它,只需使用 <code>UAObfuscateString</code> 库混淆 keypath <code>@"_player.stateDispatchQueue"</code>。</p></li>
<li><p>我听说没有肮脏的黑客可以实现平稳的返回。我会请我的一个 friend 来回答你的问题。</p></li>
</ol></p>
<p style="font-size: 20px;">关于ios - UITableViewCell 中的自动播放视频,我们在Stack Overflow上找到一个类似的问题:
<a href="https://stackoverflow.com/questions/51787983/" rel="noreferrer noopener nofollow" style="color: red;">
https://stackoverflow.com/questions/51787983/
</a>
</p>
页:
[1]