forked from facebookarchive/AsyncDisplayKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScreenNode.m
More file actions
158 lines (125 loc) · 5.15 KB
/
ScreenNode.m
File metadata and controls
158 lines (125 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//
// ScreenNode.m
// Sample
//
// Created by Huy Nguyen on 16/09/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import "ScreenNode.h"
@interface ScreenNode() <ASMultiplexImageNodeDataSource, ASMultiplexImageNodeDelegate, ASImageDownloaderProtocol>
@end
@implementation ScreenNode
- (instancetype)init
{
if (!(self = [super init])) {
return nil;
}
// multiplex image node!
// NB: we're using a custom downloader with an artificial delay for this demo, but ASBasicImageDownloader works too!
_imageNode = [[ASMultiplexImageNode alloc] initWithCache:nil downloader:self];
_imageNode.dataSource = self;
_imageNode.delegate = self;
// placeholder colour
_imageNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor();
// load low-quality images before high-quality images
_imageNode.downloadsIntermediateImages = YES;
// simple status label. Synchronous to avoid flicker / placeholder state when updating.
_buttonNode = [[ASButtonNode alloc] init];
[_buttonNode addTarget:self action:@selector(reload) forControlEvents:ASControlNodeEventTouchUpInside];
_buttonNode.titleNode.displaysAsynchronously = NO;
[self addSubnode:_imageNode];
[self addSubnode:_buttonNode];
return self;
}
- (void)start
{
[self setText:@"loading…"];
_buttonNode.userInteractionEnabled = NO;
_imageNode.imageIdentifiers = @[ @"best", @"medium", @"worst" ]; // go!
}
- (void)reload
{
[self start];
[_imageNode reloadImageIdentifierSources];
}
- (void)setText:(NSString *)text
{
NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Light" size:22.0f]};
NSAttributedString *string = [[NSAttributedString alloc] initWithString:text
attributes:attributes];
[_buttonNode setAttributedTitle:string forState:ASButtonStateNormal];
[self setNeedsLayout];
}
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
{
ASRatioLayoutSpec *imagePlaceholder = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1 child:_imageNode];
ASStackLayoutSpec *verticalStack = [[ASStackLayoutSpec alloc] init];
verticalStack.direction = ASStackLayoutDirectionVertical;
verticalStack.spacing = 10;
verticalStack.justifyContent = ASStackLayoutJustifyContentCenter;
verticalStack.alignItems = ASStackLayoutAlignItemsCenter;
verticalStack.children = @[imagePlaceholder, _buttonNode];
return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(10, 10, 10, 10) child:verticalStack];
}
#pragma mark -
#pragma mark ASMultiplexImageNode data source & delegate.
- (NSURL *)multiplexImageNode:(ASMultiplexImageNode *)imageNode URLForImageIdentifier:(id)imageIdentifier
{
if ([imageIdentifier isEqualToString:@"worst"]) {
return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/worst.png"];
}
if ([imageIdentifier isEqualToString:@"medium"]) {
return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/medium.png"];
}
if ([imageIdentifier isEqualToString:@"best"]) {
return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/best.png"];
}
// unexpected identifier
return nil;
}
- (void)multiplexImageNode:(ASMultiplexImageNode *)imageNode didFinishDownloadingImageWithIdentifier:(id)imageIdentifier error:(NSError *)error
{
[self setText:[NSString stringWithFormat:@"loaded '%@'", imageIdentifier]];
if ([imageIdentifier isEqualToString:@"best"]) {
[self setText:[_buttonNode.titleNode.attributedString.string stringByAppendingString:@". tap to reload"]];
_buttonNode.userInteractionEnabled = YES;
}
}
#pragma mark -
#pragma mark ASImageDownloaderProtocol.
- (id)downloadImageWithURL:(NSURL *)URL
callbackQueue:(dispatch_queue_t)callbackQueue
downloadProgressBlock:(void (^)(CGFloat progress))downloadProgressBlock
completion:(void (^)(CGImageRef image, NSError *error))completion
{
// if no callback queue is supplied, run on the main thread
if (callbackQueue == nil) {
callbackQueue = dispatch_get_main_queue();
}
// call completion blocks
void (^handler)(NSURLResponse *, NSData *, NSError *) = ^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// add an artificial delay
usleep(1.0 * USEC_PER_SEC);
// ASMultiplexImageNode callbacks
dispatch_async(callbackQueue, ^{
if (downloadProgressBlock) {
downloadProgressBlock(1.0f);
}
if (completion) {
completion([[UIImage imageWithData:data] CGImage], connectionError);
}
});
};
// let NSURLConnection do the heavy lifting
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
[NSURLConnection sendAsynchronousRequest:request
queue:[[NSOperationQueue alloc] init]
completionHandler:handler];
// return nil, don't support cancellation
return nil;
}
- (void)cancelImageDownloadForIdentifier:(id)downloadIdentifier
{
// no-op, don't support cancellation
}
@end