Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit a758710

Browse files
committed
added video sample app with tableview and simple one with 3 video examples
1 parent b5c1076 commit a758710

28 files changed

Lines changed: 1441 additions & 77 deletions

AsyncDisplayKit/ASVideoNode.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,9 @@ typedef NS_ENUM(NSUInteger, ASVideoGravity) {
77
ASVideoGravityResize
88
};
99

10-
// set up boolean to repeat video
11-
// set up delegate methods to provide play button
12-
// tapping should play and pause
13-
14-
@interface ASVideoNode : ASDisplayNode
10+
@interface ASVideoNode : ASDisplayNode<_ASDisplayLayerDelegate>
1511
@property (atomic, strong, readwrite) AVAsset *asset;
16-
@property (nonatomic, assign, readwrite) BOOL shouldRepeat;
12+
@property (nonatomic, assign, readwrite) BOOL shouldAutoPlay;
1713
@property (atomic) ASVideoGravity gravity;
1814
@property (atomic) BOOL autorepeat;
1915
@property (atomic) ASButtonNode *playButton;

AsyncDisplayKit/ASVideoNode.mm

Lines changed: 120 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11

22

33
#import "ASVideoNode.h"
4+
#import "ASDisplayNodeInternal.h"
5+
#import "ASDisplayNode+Subclasses.h"
6+
#import "ASDisplayNode+FrameworkPrivate.h"
7+
8+
@interface ASDisplayNode ()
9+
- (void)setInterfaceState:(ASInterfaceState)newState;
10+
@end
411

512
@interface ASVideoNode () {
613
ASDN::RecursiveMutex _lock;
714

815
__weak id<ASVideoNodeDatasource> _datasource;
916

10-
AVPlayer *_player;
1117
BOOL _shouldBePlaying;
1218
AVAsset *_asset;
19+
AVPlayerItem *_currentItem;
1320
ASButtonNode *_playButton;
1421
ASDisplayNode *_playerNode;
22+
ASDisplayNode *_spinner;
1523
}
1624

1725
@end
@@ -22,18 +30,81 @@ - (instancetype)init {
2230
if (!(self = [super init])) { return nil; }
2331

2432
_playerNode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer *{ return [[AVPlayerLayer alloc] init]; }];
33+
2534
[self addSubnode:_playerNode];
2635

2736
self.gravity = ASVideoGravityResizeAspect;
2837

38+
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(restartVideo:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
39+
2940
return self;
3041
}
3142

43+
- (void)setInterfaceState:(ASInterfaceState)newState
44+
{
45+
[super setInterfaceState:newState];
46+
47+
if (!(newState & ASInterfaceStateVisible)) {
48+
[self pause];
49+
[_spinner removeFromSupernode];
50+
} else {
51+
if (_shouldBePlaying) {
52+
[self play];
53+
}
54+
if (_spinner) {
55+
[self addSubnode:_spinner];
56+
}
57+
}
58+
}
59+
60+
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
61+
{
62+
if ([[change objectForKey:@"new"] integerValue] == AVPlayerItemStatusReadyToPlay) {
63+
if ([self.subnodes containsObject:_spinner]) {
64+
[_spinner removeFromSupernode];
65+
_spinner = nil;
66+
}
67+
}
68+
69+
if ([[change objectForKey:@"new"] integerValue] == AVPlayerItemStatusFailed) {
70+
71+
}
72+
}
73+
74+
- (void)restartVideo:(NSNotification *)notification
75+
{
76+
if ( [[[notification object] asset] isEqual:_asset]) {
77+
[[((AVPlayerLayer *)_playerNode.layer) player] seekToTime:CMTimeMakeWithSeconds(0, 1)];
78+
79+
if (_autorepeat) {
80+
[self play];
81+
} else {
82+
[self pause];
83+
}
84+
}
85+
}
86+
3287
- (void)layoutDidFinish
3388
{
3489
_playerNode.frame = self.bounds;
3590
}
3691

92+
- (void)didLoad {
93+
[super didLoad];
94+
95+
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped)];
96+
[self.view addGestureRecognizer:tap];
97+
}
98+
99+
- (void)tapped
100+
{
101+
if (_shouldBePlaying) {
102+
[self pause];
103+
} else {
104+
[self play];
105+
}
106+
}
107+
37108
- (instancetype)initWithViewBlock:(ASDisplayNodeViewBlock)viewBlock didLoadBlock:(ASDisplayNodeDidLoadBlock)didLoadBlock
38109
{
39110
ASDisplayNodeAssertNotSupported();
@@ -44,13 +115,24 @@ - (void)fetchData
44115
{
45116
[super fetchData];
46117

118+
@try {
119+
[_currentItem removeObserver:self forKeyPath:NSStringFromSelector(@selector(status))];
120+
}
121+
@catch (NSException * __unused exception) {
122+
NSLog(@"unnecessary removal in fetch data");
123+
}
124+
47125
{
48126
ASDN::MutexLocker l(_lock);
49-
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:_asset];
50-
((AVPlayerLayer *)_playerNode.layer).player = [[AVPlayer alloc] initWithPlayerItem:item];
51-
if (_shouldBePlaying) {
52-
[[((AVPlayerLayer *)_playerNode.layer) player] play];
53-
}
127+
128+
_currentItem = [[AVPlayerItem alloc] initWithAsset:_asset];
129+
[_currentItem addObserver:self forKeyPath:NSStringFromSelector(@selector(status)) options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:NULL];
130+
131+
[((AVPlayerLayer *)_playerNode.layer).player replaceCurrentItemWithPlayerItem:_currentItem];
132+
}
133+
134+
if (_shouldAutoPlay) {
135+
[self play];
54136
}
55137
}
56138

@@ -72,14 +154,8 @@ - (void)setPlayButton:(ASButtonNode *)playButton
72154
_playButton = playButton;
73155

74156
[self addSubnode:playButton];
75-
[self.view bringSubviewToFront:playButton.view];
76157

77-
[_playButton addTarget:self action:@selector(playButtonWasTouchedUpInside) forControlEvents:ASControlNodeEventTouchUpInside];
78-
}
79-
80-
- (void)playButtonWasTouchedUpInside
81-
{
82-
[self play];
158+
[_playButton addTarget:self action:@selector(play) forControlEvents:ASControlNodeEventTouchUpInside];
83159
}
84160

85161
- (ASButtonNode *)playButton
@@ -106,6 +182,7 @@ - (void)setAsset:(AVAsset *)asset
106182

107183
- (AVAsset *)asset
108184
{
185+
ASDN::MutexLocker l(_lock);
109186
return _asset;
110187
}
111188

@@ -148,14 +225,43 @@ - (void)play;
148225

149226
[[((AVPlayerLayer *)_playerNode.layer) player] play];
150227
_shouldBePlaying = YES;
228+
_playButton.alpha = 0.0;
229+
if ([self ready] && ![self.subnodes containsObject:_spinner]) {
230+
_spinner = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{
231+
UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc] initWithFrame:_playButton.frame];
232+
spinnnerView.color = [UIColor whiteColor];
233+
[spinnnerView startAnimating];
234+
235+
return spinnnerView;
236+
}];
237+
238+
[self addSubnode:_spinner];
239+
}
240+
}
241+
242+
- (BOOL)ready;
243+
{
244+
return [((AVPlayerLayer *)_playerNode.layer) player].currentItem.status != AVPlayerItemStatusReadyToPlay;
151245
}
152246

153247
- (void)pause;
154248
{
155-
ASDN::MutexLocker l(_lock);
249+
// ASDN::MutexLocker l(_lock);
156250

157251
[[((AVPlayerLayer *)_playerNode.layer) player] pause];
158252
_shouldBePlaying = NO;
253+
_playButton.alpha = 1.0;
254+
}
255+
256+
- (void)dealloc
257+
{
258+
[[NSNotificationCenter defaultCenter] removeObserver:self];
259+
@try {
260+
[_currentItem removeObserver:self forKeyPath:NSStringFromSelector(@selector(status))];
261+
}
262+
@catch (NSException * __unused exception) {
263+
NSLog(@"unnecessary removal in dealloc");
264+
}
159265
}
160266

161267
@end

examples/Kittens/Sample.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
05E2127E19D4DB510098F589 /* Frameworks */,
129129
05E2127F19D4DB510098F589 /* Resources */,
130130
F012A6F39E0149F18F564F50 /* Copy Pods Resources */,
131+
A5C135CBCFD74D965DE0D799 /* Embed Pods Frameworks */,
131132
);
132133
buildRules = (
133134
);
@@ -184,6 +185,21 @@
184185
/* End PBXResourcesBuildPhase section */
185186

186187
/* Begin PBXShellScriptBuildPhase section */
188+
A5C135CBCFD74D965DE0D799 /* Embed Pods Frameworks */ = {
189+
isa = PBXShellScriptBuildPhase;
190+
buildActionMask = 2147483647;
191+
files = (
192+
);
193+
inputPaths = (
194+
);
195+
name = "Embed Pods Frameworks";
196+
outputPaths = (
197+
);
198+
runOnlyForDeploymentPostprocessing = 0;
199+
shellPath = /bin/sh;
200+
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
201+
showEnvVarsInLog = 0;
202+
};
187203
E080B80F89C34A25B3488E26 /* Check Pods Manifest.lock */ = {
188204
isa = PBXShellScriptBuildPhase;
189205
buildActionMask = 2147483647;

examples/Kittens/Sample.xcworkspace/contents.xcworkspacedata

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/Kittens/Sample/KittenNode.mm

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
@interface KittenNode ()
2626
{
2727
CGSize _kittenSize;
28-
28+
2929
ASNetworkImageNode *_imageNode;
3030
ASTextNode *_textNode;
3131
ASDisplayNode *_divider;
@@ -42,7 +42,7 @@ @implementation KittenNode
4242
+ (NSArray *)placeholders
4343
{
4444
static NSArray *placeholders = nil;
45-
45+
4646
static dispatch_once_t once;
4747
dispatch_once(&once, ^{
4848
placeholders = @[
@@ -68,38 +68,38 @@ + (NSArray *)placeholders
6868
@"Sollicitudin feed me et ac in viverra catnip, nunc eat I don't like that food iaculis give me fish.",
6969
];
7070
});
71-
71+
7272
return placeholders;
7373
}
7474

7575
- (instancetype)initWithKittenOfSize:(CGSize)size
7676
{
7777
if (!(self = [super init]))
7878
return nil;
79-
79+
8080
_kittenSize = size;
81-
81+
8282
// kitten image, with a solid background colour serving as placeholder
8383
_imageNode = [[ASNetworkImageNode alloc] init];
8484
_imageNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor();
8585
_imageNode.URL = [NSURL URLWithString:[NSString stringWithFormat:@"https://placekitten.com/%zd/%zd",
86-
(NSInteger)roundl(_kittenSize.width),
87-
(NSInteger)roundl(_kittenSize.height)]];
88-
// _imageNode.contentMode = UIViewContentModeCenter;
86+
(NSInteger)roundl(_kittenSize.width),
87+
(NSInteger)roundl(_kittenSize.height)]];
88+
// _imageNode.contentMode = UIViewContentModeCenter;
8989
[_imageNode addTarget:self action:@selector(toggleNodesSwap) forControlEvents:ASControlNodeEventTouchUpInside];
9090
[self addSubnode:_imageNode];
91-
91+
9292
// lorem ipsum text, plus some nice styling
9393
_textNode = [[ASTextNode alloc] init];
9494
_textNode.attributedString = [[NSAttributedString alloc] initWithString:[self kittyIpsum]
9595
attributes:[self textStyle]];
9696
[self addSubnode:_textNode];
97-
97+
9898
// hairline cell separator
9999
_divider = [[ASDisplayNode alloc] init];
100100
_divider.backgroundColor = [UIColor lightGrayColor];
101101
[self addSubnode:_divider];
102-
102+
103103
return self;
104104
}
105105

@@ -109,24 +109,24 @@ - (NSString *)kittyIpsum
109109
u_int32_t ipsumCount = (u_int32_t)[placeholders count];
110110
u_int32_t location = arc4random_uniform(ipsumCount);
111111
u_int32_t length = arc4random_uniform(ipsumCount - location);
112-
112+
113113
NSMutableString *string = [placeholders[location] mutableCopy];
114114
for (u_int32_t i = location + 1; i < location + length; i++) {
115115
[string appendString:(i % 2 == 0) ? @"\n" : @" "];
116116
[string appendString:placeholders[i]];
117117
}
118-
118+
119119
return string;
120120
}
121121

122122
- (NSDictionary *)textStyle
123123
{
124124
UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:12.0f];
125-
125+
126126
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
127127
style.paragraphSpacing = 0.5 * font.lineHeight;
128128
style.hyphenationFactor = 1.0;
129-
129+
130130
return @{ NSFontAttributeName: font,
131131
NSParagraphStyleAttributeName: style };
132132
}
@@ -164,7 +164,7 @@ - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
164164
CGSize imageSize = CGSizeMake(kImageSize, kImageSize);
165165
CGSize textSize = [_textNode measure:CGSizeMake(constrainedSize.width - kImageSize - 2 * kOuterPadding - kInnerPadding,
166166
constrainedSize.height)];
167-
167+
168168
// ensure there's room for the text
169169
CGFloat requiredHeight = MAX(textSize.height, imageSize.height);
170170
return CGSizeMake(constrainedSize.width, requiredHeight + 2 * kOuterPadding);
@@ -174,9 +174,9 @@ - (void)layout
174174
{
175175
CGFloat pixelHeight = 1.0f / [[UIScreen mainScreen] scale];
176176
_divider.frame = CGRectMake(0.0f, 0.0f, self.calculatedSize.width, pixelHeight);
177-
177+
178178
_imageNode.frame = CGRectMake(kOuterPadding, kOuterPadding, kImageSize, kImageSize);
179-
179+
180180
CGSize textSize = _textNode.calculatedSize;
181181
_textNode.frame = CGRectMake(kOuterPadding + kImageSize + kInnerPadding, kOuterPadding, textSize.width, textSize.height);
182182
}
17.1 KB
Loading
17.9 KB
Loading
22.8 KB
Loading
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source 'https://github.com/CocoaPods/Specs.git'
2+
platform :ios, '8.0'
3+
pod 'AsyncDisplayKit', :path => '../..'

0 commit comments

Comments
 (0)