所以我能够找到一个解决方案,它不是很干净,而且我不确定这是否是ComponentKit
Facebook 的开发人员打算如何处理这种情况的正确方法应该是这样的,但这个解决方案有效:
首先,我们需要创建一个单独的视图来处理实际的视频演示。这是从苹果的例子中提取的
#import "CDBVideoPlayerView.h"
@implementation CDBVideoPlayerView
+ (Class)layerClass {
return [AVPlayerLayer class];
}
- (AVPlayer*)player {
return [(AVPlayerLayer *)[self layer] player];
}
- (void)setPlayer:(AVPlayer *)player {
[(AVPlayerLayer *)[self layer] setPlayer:player];
}
@end
然后,组件和控制器:
#import "CDBVideoPlayerComponent.h"
#import "CDBVideoPlayerView.h"
#import <ComponentKit/CKStatefulViewComponent.h>
#import <ComponentKit/CKStatefulViewComponentController.h>
#import <AVFoundation/AVFoundation.h>
@interface CDBVideoStateComponent : CKStatefulViewComponent
@property (nonatomic, strong) AVPlayer *player;
+ (instancetype)newWithVideoURL:(NSURL*)url size:(const CKComponentSize &)size;
@end
@implementation CDBVideoStateComponent
+ (instancetype)newWithVideoURL:(NSURL*)url size:(const CKComponentSize &)size {
CKComponentScope scope(self, url);
CDBVideoStateComponent *component = [super newWithSize:size accessibility:{}];
component->_player = [[AVPlayer alloc] initWithURL:url];
component->_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
return component;
}
@end
@interface CDBVideoStateComponentController : CKStatefulViewComponentController
@end
@implementation CDBVideoStateComponentController
+ (UIView *)newStatefulView:(id)context {
CDBVideoPlayerView *view = [[CDBVideoPlayerView alloc] init];
return view;
}
+ (void)configureStatefulView:(CDBVideoPlayerView *)statefulView forComponent:(CDBVideoStateComponent *)videoComponent {
statefulView.player = videoComponent.player;
}
@end
@interface CDBVideoPlayerComponent ()
@property (nonatomic, strong) AVPlayer *player;
@end
@implementation CDBVideoPlayerComponent
+ (instancetype)newWithVideoURL:(NSURL*)url size:(const CKComponentSize &)size {
CKComponentScope scope(self, url);
CDBVideoStateComponent *component = [CDBVideoStateComponent newWithVideoURL:url size:size];
CDBVideoPlayerComponent *playerComponent = [super newWithComponent:component
overlay:
[CKButtonComponent
newWithTitles:{}
titleColors:{}
images:{}
backgroundImages:{}
titleFont:{}
selected:NO
enabled:YES
action:@selector(handleButtonPress:)
size:{}
attributes:{}
accessibilityConfiguration:{}
]
];
playerComponent->_player = component.player;
return playerComponent;
}
- (void)handleButtonPress:(id)sender {
if (self.player.status == AVPlayerStatusReadyToPlay) {
if (self.player.timeControlStatus == AVPlayerTimeControlStatusPaused || self.player.timeControlStatus == AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate) {
[self.player play];
} else {
[self.player pause];
}
}
}
@end
编辑
我还发现,我认为是通过将大部分代码移动到 VideoPlayerView 的更清洁的解决方案
@implementation VideoPlayerView
- (instancetype)init {
if (self = [super init]) {
[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]];
}
return self;
}
- (void)dealloc {
[self removeObserversForPlayer:self.player];
}
+ (Class)layerClass {
return [AVPlayerLayer class];
}
- (AVPlayer*)player {
return [(AVPlayerLayer *)[self layer] player];
}
- (void)setPlayer:(AVPlayer *)player {
[self removeObserversForPlayer:self.player];
[(AVPlayerLayer *)[self layer] setPlayer:player];
[self addObserverForPlayer:player];
}
- (void)addObserverForPlayer:(AVPlayer *)player {
if (player) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:player.currentItem];
}
}
- (void)removeObserversForPlayer:(AVPlayer *)player {
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:player.currentItem];
}
- (void)itemDidFinishPlaying:(NSNotification *)notification {
[self.player seekToTime:kCMTimeZero];
[self.player pause];
}
- (void)handleTap:(id)sender {
if (self.player.status == AVPlayerStatusReadyToPlay) {
if (self.player.timeControlStatus == AVPlayerTimeControlStatusPaused || self.player.timeControlStatus == AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate) {
[self.player play];
} else {
[self.player pause];
}
}
}
@end
更新的组件:
#import "VideoPlayerComponent.h"
#import "VideoPlayerView.h"
#import <ComponentKit/CKStatefulViewComponentController.h>
#import <AVFoundation/AVFoundation.h>
#import <ComponentKit/ComponentKit.h>
@interface VideoPlayerComponent ()
@property (nonatomic, strong) AVPlayer *player;
@end
@implementation VideoPlayerComponent
+ (instancetype)newWithVideoURL:(NSURL*)url size:(const CKComponentSize &)size {
CKComponentScope scope(self, url);
VideoPlayerComponent *component = [super newWithSize:size accessibility:{}];
component->_player = [[AVPlayer alloc] initWithURL:url];
component->_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
return component;
}
@end
@interface VideoPlayerComponentController : CKStatefulViewComponentController
@end
@implementation VideoPlayerComponentController
+ (UIView *)newStatefulView:(id)context {
VideoPlayerView *view = [[VideoPlayerView alloc] init];
view.backgroundColor = [UIColor grayColor];
return view;
}
+ (void)configureStatefulView:(VideoPlayerView *)statefulView forComponent:(VideoPlayerComponent *)videoComponent {
statefulView.player = videoComponent.player;
}
@end