问题
I have read most of the questions on StackOverflow
for autoplaying videos and I'm able to autoplay them in UITableView
, but I'm having few issues like mentioned below
- scrolling hangs for a second when video starts
- Video flashes before playing
- Video does not auto play if I scroll Up
What I want is a smooth experience for autoplay of videos like Facebook without using any third party library like ASYNCDisplayKit
.
All videos urls
are from AWSS3
cloud-front URLS.
I have also uploaded video of the issue in case someone want to have a look.
Video Autoplay Hiccups
Here is my complete code
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
PostViewModel* model = self.posts[indexPath.section];
Post* post = model.post;
PostItems* item = model.items[indexPath.row];
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*)[tableView dequeueReusableCellWithIdentifier:kFeedVideoListCellIdentifier forIndexPath:indexPath];
cell.delegate = self;
cell.indexPath = indexPath;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = [UIColor clearColor];
cell.videoThumbnail.image = nil;
[cell setCounter:post.medias.count];
if (post.medias.count > 0) {
MediaItem* item = post.medias[0];
if ([item getMediaType] == VIDEO) {
NSString* thumbnailURL = item.thumbnailUrl;
[cell.videoThumbnail downloadImageWithURL:thumbnailURL andPlaceholderImage:self.timelinePlaceholder indicatorStyle:UIActivityIndicatorViewStyleWhiteLarge cachePolicy:NSURLRequestReturnCacheDataElseLoad andTimeOut:120];
[cell hideVideoAndShowThumbnail];
dispatch_async(dispatch_get_main_queue(), ^{
[cell setMediaItem:item withUserID:post.userId];
});
}
}
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([cell isKindOfClass:[VideoListCell class]]){
VideoListCell* videoCell = (VideoListCell*)cell;
dispatch_async(dispatch_get_main_queue(), ^{
[videoCell hideVideoAndShowThumbnail];
});
PostViewModel* model = self.posts[indexPath.section];
Post* post = model.post;
PostItems* item = model.items[indexPath.row];
if(item.itemType == videos){
videoCell.videoThumbnail.image = nil;
[videoCell setCounter:post.medias.count];
if (post.medias.count > 0) {
MediaItem* item = post.medias[0];
if ([item getMediaType] == VIDEO) {
//dispatch_async(dispatch_get_main_queue(), ^{
NSString* profilePic = item.thumbnailUrl;
[videoCell.videoThumbnail downloadImageWithURL:profilePic andPlaceholderImage:self.timelinePlaceholder indicatorStyle:UIActivityIndicatorViewStyleWhiteLarge cachePolicy:NSURLRequestReturnCacheDataElseLoad andTimeOut:120];
[videoCell setMediaItem:item withUserID:post.userId];
[videoCell playVideo];
}
}
}
}
}
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath {
if([cell isKindOfClass:[VideoListCell class]]){
VideoListCell* videoCell = (VideoListCell*)cell;
[videoCell stopVideo];
videoCell.avLayer = nil;
videoCell.videoPlayer = nil;
[videoCell hideVideoAndShowThumbnail];
}
}
//Video List Cell Class
#define kHeight 200
@implementation VideoListCell
- (void)awakeFromNib {
[super awakeFromNib];
UIImage* icon = [[UIImage imageNamed:@"play-icon"] imageTintedWithColor:kSliderDarkYellowColor];
[self.btnPlay setImage:icon forState:UIControlStateNormal];
UIImage* pauseIcon = [[UIImage imageNamed:@"pause-icon"] imageTintedWithColor:kSliderDarkYellowColor];
[self.btnPlay setImage:icon forState:UIControlStateNormal];
[self.btnPlay setImage:pauseIcon forState:UIControlStateSelected];
UITapGestureRecognizer *viewTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapOnView)];
viewTap.numberOfTapsRequired = 1;
self.viewPlayer.userInteractionEnabled = YES;
[self.viewPlayer addGestureRecognizer:viewTap];
self.counterView.hidden = YES;
self.counterView.layer.cornerRadius = 12.0f;
self.counterView.layer.masksToBounds = YES;
//Add Gesture to label
UITapGestureRecognizer *countGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapOnCounterView)];
countGesture.numberOfTapsRequired = 1;
self.counterView.userInteractionEnabled = YES;
[self.counterView addGestureRecognizer:countGesture];
[self.btnFullScreen addTarget:self action:@selector(btnFSTapped:) forControlEvents:UIControlEventTouchUpInside];
self.btnFullScreen.hidden = NO;
UIImage* fullScreenImage = [[UIImage imageNamed:@"fullScreenIcon"] imageTintedWithColor:kSliderDarkYellowColor];
[self.btnFullScreen setImage:fullScreenImage forState:UIControlStateNormal];
}
- (void)showThumbnail:(BOOL)yesOrNo {
self.videoThumbnail.hidden = !yesOrNo;
self.viewForVideo.hidden = yesOrNo;
}
- (void)hideVideoAndShowThumbnail {
[self stopVideo];
[self showThumbnail:YES];
self.btnPlay.selected = NO;
self.isPlaying = NO;
}
- (void)btnFSTapped:(UIButton*)sender {
if (self.delegate && [self.delegate respondsToSelector:@selector(fullScreenButtonTapped:andURL:andPlayer:)]) {
[self.delegate fullScreenButtonTapped:self.indexPath andURL:self.videoURL andPlayer:self.player.player];
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
// if (self.avLayer) {
// [self.avLayer setFrame:CGRectMake(self.viewForVideo.frame.origin.x, self.viewForVideo.frame.origin.y, self.viewForVideo.frame.size.width, self.viewForVideo.frame.size.height)];
// }
}
- (void)initNewPlayerItem {
// Pause the existing video (if there is one)
//[self stopVideo];
if(self.asset){
[self.asset cancelLoading];
}
// First we need to make sure we have a valid URL
if (!self.videoURL) {
return;
}
// Create a new AVAsset from the URL
self.asset = [AVAsset assetWithURL:self.videoURL];
// Now we need an AVPlayerItem to pass to the AVPlayer
AVPlayerItem* item = [[AVPlayerItem alloc] initWithAsset:self.asset];
if(item){
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:item];
}
//[self.player.player replaceCurrentItemWithPlayerItem:item];
// Finally, we set this as the current AVPlayer item
[self.asset loadValuesAsynchronouslyForKeys:@[@"duration"] completionHandler:^{
NSError* error = nil;
AVKeyValueStatus status = [self.asset statusOfValueForKey:@"duration" error:&error];
if (status == AVKeyValueStatusFailed) {
[self.playerSetupLoading stopAnimating];
self.btnPlay.hidden = NO;
self.btnPlay.selected = NO;
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.playerSetupLoading stopAnimating];
[self.player.player replaceCurrentItemWithPlayerItem:item];
self.btnPlay.selected = YES;
self.btnPlay.hidden = YES;
[self showThumbnail:NO];
[self.player.player play];
self.isPlaying = YES;
});
}];
}
- (void)playerItemDidReachEnd:(NSNotification*)notif {
id object = [notif object];
if (object && [object isKindOfClass:[AVPlayerItem class]]) {
AVPlayerItem* item = (AVPlayerItem*)[notif object];
[item seekToTime:kCMTimeZero];
}
//[self stopVideo];
[self showThumbnail:YES];
self.btnPlay.selected = NO;
self.btnPlay.hidden = NO;
}
-(void)prepareForReuse {
// self.videoURL = nil;
// self.videoThumbnail.image = nil;
//[self.player pauseContent];
self.videoThumbnail.image = nil;
if (self.avLayer.superlayer) {
[self.avLayer removeFromSuperlayer];
}
if (self.viewForVideo.subviews.count > 0) {
for (UIView* v in self.viewForVideo.subviews) {
[v removeFromSuperview];
}
}
self.videoURL = nil;
self.player = nil;
self.userID = nil;
self.videoItem = nil;
self.videoPlayer = nil;
self.btnPlay.selected = NO;
[super prepareForReuse];
}
- (void)tapOnView {
//if(self.counterView.hidden){
if (self.delegate && [self.delegate respondsToSelector:@selector(fullScreenButtonTapped:andURL:andPlayer:)]) {
[self.delegate fullScreenButtonTapped:self.indexPath andURL:self.videoURL andPlayer:self.player.player];
}
//}
// else
// {
// if (self.delegate && [self.delegate respondsToSelector:@selector(playVideo:withURL:)]) {
// [self.delegate playVideo:self.indexPath withURL:nil];
// }
// }
}
-(void)tapOnCounterView {
if (self.delegate && [self.delegate respondsToSelector:@selector(playVideo:withURL:)]) {
[self.delegate playVideo:self.indexPath withURL:nil];
}
}
- (void)setCounter:(NSUInteger)count {
if (count > 1) {
self.counterView.hidden = NO;
self.lblCounter.text = [NSString stringWithFormat:@"+%lu more",(unsigned long)count-1];
}
else{
self.counterView.hidden = YES;
}
}
- (IBAction)btnPlayTapped:(id)sender {
//[self playVideo];
//if(self.counterView.hidden){
if(self.btnPlay.selected){
[self stopVideo];
self.btnPlay.selected = NO;
}else{
[self playVideo];
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 ([self.videoObject doesPreSignedURLExpired]) {
//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
[self generateNewPreSignedURL];
});
}
else{
if (!self.videoURL) {
dispatch_async(dispatch_get_main_queue(), ^{
[self generatePreSignedURLWithVideoThumbnail];
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
[self setupPlayer];
});
}
}
}
- (void)stopVideo {
if (self.player) {
self.isPlaying = NO;
self.btnPlay.hidden = NO;
[self.player.player pause];
}
}
- (void)setMediaItem:(MediaItem*)item withUserID:(NSNumber*)userId {
self.videoObject = item;
self.userID = userId;
[self showThumbnail:YES];
}
- (void)generatePreSignedURLWithVideoThumbnail {
if (self.videoObject.mediaUrl && [self.videoObject hasPreSignedURL]) {
//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 = [NSURL URLWithString:self.videoObject.mediaUrl];
[self setupPlayer];
});
}
else if(self.videoObject.mediaUrl && [self.videoObject hasPlayListURL]){
AppDelegate* delegate = [AppDelegate applicationDelegate];
AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = [AWSS3GetPreSignedURLRequest new];
getPreSignedURLRequest.bucket = S3BucketName;
getPreSignedURLRequest.key = kS3OutputVideoFileInternalPath(delegate.loggedInUser.userId,[self.videoObject getVideoFolderName],self.videoObject.mediaUrl);
getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodGET;
getPreSignedURLRequest.expires = [NSDate dateWithTimeIntervalSinceNow:Hour*24*5];
[[[AWSS3PreSignedURLBuilder defaultS3PreSignedURLBuilder] getPreSignedURL:getPreSignedURLRequest]
continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(@"Error: %@",task.error);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
self.videoURL = task.result;
[self setupPlayer];
});
}
return nil;
}];
}
else{
//Generate Pre signed URL
AWSS3GetPreSignedURLRequest *getPreSignedURLRequest = [AWSS3GetPreSignedURLRequest new];
getPreSignedURLRequest.bucket = S3BucketName;
getPreSignedURLRequest.key = [kS3InputVideoFilePath(self.userID) stringByAppendingString:self.videoObject.mediaUrl];
getPreSignedURLRequest.HTTPMethod = AWSHTTPMethodGET;
getPreSignedURLRequest.expires = [NSDate dateWithTimeIntervalSinceNow:Hour*24*5];
[[[AWSS3PreSignedURLBuilder defaultS3PreSignedURLBuilder] getPreSignedURL:getPreSignedURLRequest]
continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(@"Error: %@",task.error);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
self.videoURL = task.result;
[self setupPlayer];
});
}
return nil;
}];
}
}
- (void)setupPlayer {
self.btnPlay.hidden = YES;
self.videoItem = nil;
self.videoPlayer = nil;
self.videoItem = [[AVPlayerItem alloc] initWithURL:self.videoURL];
if (self.avLayer.superlayer) {
[self.avLayer removeFromSuperlayer];
}
if (self.viewForVideo.subviews.count > 0) {
for (UIView* v in self.viewForVideo.subviews) {
[v removeFromSuperview];
}
}
self.videoPlayer = [[AVPlayer alloc] initWithPlayerItem:self.videoItem];
self.avLayer = [AVPlayerLayer playerLayerWithPlayer:self.videoPlayer];
self.avLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
self.player = [[AVPlayerViewController alloc] 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;
[self.viewForVideo insertSubview:self.player.view atIndex:0];
//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
[self.viewForVideo addConstraint:trailing];
[self.viewForVideo addConstraint:bottom];
[self.viewForVideo addConstraint:leading];
//Add height constraint to the subview, as subview owns it.
[self.player.view addConstraint:height];
[self initNewPlayerItem];
}
- (void)generateNewPreSignedURL {
if (self.videoObject) {
NSDictionary* postParams = @{kMediaId:self.videoObject.mediaId};
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
TBWebAPIConsumer *web = [TBWebAPIConsumer sharedWebAPIManager];
[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 (![data valueForKeyIsNull:@"mediaUrl"]) {
self.videoObject.mediaUrl = [data valueForKey:@"mediaUrl"];
}
if (![data valueForKeyIsNull:@"videoSignedUrlExpiry"]) {
self.videoObject.videoSignedUrlExpiry = [data valueForKey:@"videoSignedUrlExpiry"];
}
[self generatePreSignedURLWithVideoThumbnail];
}
});
}];
});
}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
Could someone help me out in this ?
回答1:
I have a few tips for you:
Do not try to call play/pause during scrolling. Just perform this actions right after scrolling stops: https://gist.github.com/k06a/731654e3168277fb1fd0e64abc7d899e
You can try to use this dirty hacks: https://gist.github.com/k06a/66f7815b0325f239411e26f498c75755 To hide it from Apple Review Team just obfustace keypath
@"_player.stateDispatchQueue"
withUAObfuscateString
library.I heard smooth payback can be achieved without dirty hacks. I'll ask a friend of mine to answer your question.
回答2:
So I achieved this smooth scrolling with Texturekit. In case anyone wants to achieve the smooth scrolling here is what I did.
I have created a new UItableViewCell -
#import <UIKit/UIKit.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface AutoplayVideoTableViewCell : UITableViewCell {
ASVideoPlayerNode *_videoPlayerNode;
ASControlNode *_likeButtonNode;
ASButtonNode *_muteButtonNode;
UIImage* _fsIcon;
}
- (void)setVideoURL:(NSString*)aVideoURL;
@end
#import "AutoplayVideoTableViewCell.h"
#import "UIImage+Tint.h"
#define AVATAR_IMAGE_HEIGHT 30
#define HORIZONTAL_BUFFER 10
#define VERTICAL_BUFFER 5
@interface AutoplayVideoTableViewCell () <ASVideoPlayerNodeDelegate>
@end
@implementation AutoplayVideoTableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
_muteButtonNode = [[ASButtonNode alloc] init];
_muteButtonNode.style.width = ASDimensionMakeWithPoints(16.0);
_muteButtonNode.style.height = ASDimensionMakeWithPoints(22.0);
[_muteButtonNode addTarget:self action:@selector(didTapMuteButton) forControlEvents:ASControlNodeEventTouchUpInside];
_videoPlayerNode = [[ASVideoPlayerNode alloc] init];
_videoPlayerNode.delegate = self;
_videoPlayerNode.backgroundColor = [UIColor blackColor];
[self.contentView addSubnode:_videoPlayerNode];
[self setMuteButtonIcon];
_fsIcon = [[UIImage imageNamed:@"fullScreenIcon"] imageTintedWithColor:[UIColor whiteColor]];
}
- (void)setVideoURL:(NSString*)aVideoURL {
//ASVideoNode *videoNode = [[ASVideoNode alloc] init];
CGFloat fullWidth = [UIScreen mainScreen].bounds.size.width;
_videoPlayerNode.view.frame = CGRectMake(0, 0, fullWidth, 200);
[_videoPlayerNode setAssetURL:[NSURL URLWithString:aVideoURL]];
[_videoPlayerNode setGravity:AVLayerVideoGravityResizeAspectFill];
[_videoPlayerNode setShouldAutoPlay:YES];
[_videoPlayerNode setShouldAutoRepeat:NO];
[_videoPlayerNode play];
}
- (void)videoPlayerNodeDidPlayToEnd:(ASVideoPlayerNode *)videoPlayer {
[videoPlayer seekToTime:0];
}
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
{
CGFloat fullWidth = [UIScreen mainScreen].bounds.size.width;
_videoPlayerNode.style.width = ASDimensionMakeWithPoints(fullWidth);
// _videoPlayerNode.style.height = ASDimensionMakeWithPoints(200);
ASStackLayoutSpec *bottomControlsStack = [ASStackLayoutSpec horizontalStackLayoutSpec];
bottomControlsStack.spacing = HORIZONTAL_BUFFER;
bottomControlsStack.alignItems = ASStackLayoutAlignItemsCenter;
bottomControlsStack.children = @[_likeButtonNode];
UIEdgeInsets bottomControlsInsets = UIEdgeInsetsMake(HORIZONTAL_BUFFER, HORIZONTAL_BUFFER, HORIZONTAL_BUFFER, HORIZONTAL_BUFFER);
ASInsetLayoutSpec *bottomControlsInset = [ASInsetLayoutSpec insetLayoutSpecWithInsets:bottomControlsInsets child:bottomControlsStack];
ASStackLayoutSpec *verticalStack = [ASStackLayoutSpec verticalStackLayoutSpec];
verticalStack.alignItems = ASStackLayoutAlignItemsStretch;
verticalStack.children = @[_videoPlayerNode, bottomControlsInset];
return verticalStack;
}
- (void)setMuteButtonIcon
{
if (_videoPlayerNode.muted) {
[_muteButtonNode setImage:[UIImage imageNamed:@"ico-mute1"] forState:UIControlStateNormal];
} else {
[_muteButtonNode setImage:[UIImage imageNamed:@"ico-unmute1"] forState:UIControlStateNormal];
}
}
- (void)didTapMuteButton
{
_videoPlayerNode.muted = !_videoPlayerNode.muted;
[self setMuteButtonIcon];
}
#pragma mark - ASVideoPlayerNodeDelegate
- (void)didTapVideoPlayerNode:(ASVideoPlayerNode *)videoPlayer
{
if (_videoPlayerNode.playerState == ASVideoNodePlayerStatePlaying) {
_videoPlayerNode.controlsDisabled = !_videoPlayerNode.controlsDisabled;
[_videoPlayerNode pause];
} else {
[_videoPlayerNode play];
}
}
- (NSDictionary *)videoPlayerNodeCustomControls:(ASVideoPlayerNode *)videoPlayer
{
return @{
@"muteControl" : _muteButtonNode
};
}
- (UIImage *)videoPlayerNodeFullScreenButtonImage:(ASVideoPlayerNode *)videoPlayer {
return _fsIcon;
}
- (NSArray *)controlsForControlBar:(NSDictionary *)availableControls
{
NSMutableArray *controls = [[NSMutableArray alloc] init];
if (availableControls[ @(ASVideoPlayerNodeControlTypePlaybackButton) ]) {
[controls addObject:availableControls[ @(ASVideoPlayerNodeControlTypePlaybackButton) ]];
}
if (availableControls[ @(ASVideoPlayerNodeControlTypeElapsedText) ]) {
[controls addObject:availableControls[ @(ASVideoPlayerNodeControlTypeElapsedText) ]];
}
if (availableControls[ @(ASVideoPlayerNodeControlTypeScrubber) ]) {
[controls addObject:availableControls[ @(ASVideoPlayerNodeControlTypeScrubber) ]];
}
if (availableControls[ @(ASVideoPlayerNodeControlTypeDurationText) ]) {
[controls addObject:availableControls[ @(ASVideoPlayerNodeControlTypeDurationText) ]];
}
if (availableControls[ @(ASVideoPlayerNodeControlTypeFullScreenButton) ]) {
[controls addObject:availableControls[ @(ASVideoPlayerNodeControlTypeFullScreenButton) ]];
}
return controls;
}
#pragma mark - Layout
- (ASLayoutSpec*)videoPlayerNodeLayoutSpec:(ASVideoPlayerNode *)videoPlayer forControls:(NSDictionary *)controls forMaximumSize:(CGSize)maxSize
{
ASLayoutSpec *spacer = [[ASLayoutSpec alloc] init];
spacer.style.flexGrow = 1.0;
UIEdgeInsets insets = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
if (controls[ @(ASVideoPlayerNodeControlTypeScrubber) ]) {
ASDisplayNode *scrubber = controls[ @(ASVideoPlayerNodeControlTypeScrubber) ];
scrubber.style.height = ASDimensionMakeWithPoints(44.0);
scrubber.style.minWidth = ASDimensionMakeWithPoints(0.0);
scrubber.style.maxWidth = ASDimensionMakeWithPoints(maxSize.width);
scrubber.style.flexGrow = 1.0;
}
NSArray *controlBarControls = [self controlsForControlBar:controls];
NSMutableArray *topBarControls = [[NSMutableArray alloc] init];
//Our custom control
if (controls[@"muteControl"]) {
[topBarControls addObject:controls[@"muteControl"]];
}
ASStackLayoutSpec *topBarSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal
spacing:10.0
justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsCenter
children:topBarControls];
ASInsetLayoutSpec *topBarInsetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:topBarSpec];
ASStackLayoutSpec *controlbarSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal
spacing:10.0
justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsCenter
children: controlBarControls ];
controlbarSpec.style.alignSelf = ASStackLayoutAlignSelfStretch;
ASInsetLayoutSpec *controlbarInsetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:controlbarSpec];
controlbarInsetSpec.style.alignSelf = ASStackLayoutAlignSelfStretch;
ASStackLayoutSpec *mainVerticalStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical
spacing:0.0
justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsStart
children:@[topBarInsetSpec, spacer, controlbarInsetSpec]];
return mainVerticalStack;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
And in the cellforRow method I changed the code
if (post.medias.count > 0) {
MediaItem* item = post.medias[0];
if ([item getMediaType] == VIDEO) {
[cell setVideoURL:item.mediaUrl];
// dispatch_async(dispatch_get_main_queue(), ^{
//cell.videoThumbnail.image = nil;
//});
}
}
And it worked like a charm. I'm still trying to figure other things but it will be a enough to start for anyone else. The Code I picked up is from the sample app named ASDKTube [ObjC] from the Texture samples.
来源:https://stackoverflow.com/questions/51787983/autoplay-video-in-uitableviewcell-hiccupps