0

我正在尝试使用 ComponentKit 显示视频。我希望它在点击组件时播放。我发现了这个Github Issue,所以我知道我需要使用 aCKStatefulViewComponent但我不知道处理点击事件的建议方法是使用 ComponentKit。

这是我到目前为止的代码:

#import "CDBVideoPlayerComponent.h"
#import <ComponentKit/ComponentKit.h>

#import <ComponentKit/CKStatefulViewComponentController.h>
#import <AVFoundation/AVFoundation.h>

@interface CDBVideoPlayerComponent()
@property (nonatomic, strong) AVPlayer *player;
@end

@implementation CDBVideoPlayerComponent

+ (instancetype)newWithVideoURL:(NSURL*)url size:(const CKComponentSize &)size {

    CKComponentScope scope(self, url);

    CDBVideoPlayerComponent *component = [super newWithSize:size accessibility:{}];

    component->_player = [[AVPlayer alloc] initWithURL:url];

    return component;
}

@end

@interface CDBVideoPlayerComponentController : CKStatefulViewComponentController
- (void)handleTapForPlayer:(AVPlayer *)player;
@end

@implementation CDBVideoPlayerComponentController

+ (UIView *)newStatefulView:(id)context {

    UIView *view = [[UIView alloc] init];
    view.backgroundColor = [UIColor darkGrayColor];

    AVPlayerLayer *playerLayer = [[AVPlayerLayer alloc] init];
    playerLayer.frame = view.bounds;

    [view.layer addSublayer:playerLayer];

    return view;
}

+ (void)configureStatefulView:(UIView *)statefulView forComponent:(CDBVideoPlayerComponent *)videoComponent {

    __block AVPlayerLayer *layer = nil;

    for (CALayer *currentLayer in statefulView.layer.sublayers) {

        if ([[currentLayer class] isSubclassOfClass:[AVPlayerLayer class]]) {
            layer = (AVPlayerLayer*)currentLayer;
            break;
        }
    }

    if (layer) {
        layer.player = videoComponent.player;
    } else {
        layer.player = nil;
    }
}

- (void)handleTapForPlayer:(AVPlayer *)player {
    [player play];
}

@end
4

1 回答 1

1

所以我能够找到一个解决方案,它不是很干净,而且我不确定这是否是ComponentKitFacebook 的开发人员打算如何处理这种情况的正确方法应该是这样的,但这个解决方案有效:

首先,我们需要创建一个单独的视图来处理实际的视频演示。这是从苹果的例子中提取的

#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
于 2016-12-08T23:22:26.820 回答