Merge pull request #1096 from facebook/pr/1059

[tvOS] Initial changes to support building AsyncDisplayKit for tvOS.
This commit is contained in:
appleguy
2016-01-23 12:28:43 -08:00
15 changed files with 167 additions and 23 deletions

View File

@@ -47,4 +47,5 @@ Pod::Spec.new do |spec|
}
spec.ios.deployment_target = '7.0'
spec.tvos.deployment_target = '9.0'
end

View File

@@ -641,7 +641,9 @@ NS_ASSUME_NONNULL_END
@property (atomic, assign) UIViewContentMode contentMode; // default=UIViewContentModeScaleToFill
@property (atomic, assign, getter=isUserInteractionEnabled) BOOL userInteractionEnabled; // default=YES (NO for layer-backed nodes)
#if TARGET_OS_IOS
@property (atomic, assign, getter=isExclusiveTouch) BOOL exclusiveTouch; // default=NO
#endif
@property (atomic, assign, nullable) CGColorRef shadowColor; // default=opaque rgb black
@property (atomic, assign) CGFloat shadowOpacity; // default=0.0
@property (atomic, assign) CGSize shadowOffset; // default=(0, -3)
@@ -658,6 +660,16 @@ NS_ASSUME_NONNULL_END
- (BOOL)isFirstResponder;
- (BOOL)canPerformAction:(nonnull SEL)action withSender:(nonnull id)sender;
#if TARGET_OS_TV
//Focus Engine
- (void)setNeedsFocusUpdate;
- (BOOL)canBecomeFocused;
- (void)updateFocusIfNeeded;
- (void)didUpdateFocusInContext:(nonnull UIFocusUpdateContext *)context withAnimationCoordinator:(nonnull UIFocusAnimationCoordinator *)coordinator;
- (BOOL)shouldUpdateFocusInContext:(nonnull UIFocusUpdateContext *)context;
- (nullable UIView *)preferredFocusedView;
#endif
// Accessibility support
@property (atomic, assign) BOOL isAccessibilityElement;
@property (nullable, atomic, copy) NSString *accessibilityLabel;

View File

@@ -2312,6 +2312,38 @@ static void _recursivelySetDisplaySuspended(ASDisplayNode *node, CALayer *layer,
return self;
}
#if TARGET_OS_TV
#pragma mark - UIFocusEnvironment Protocol (tvOS)
- (void)setNeedsFocusUpdate
{
}
- (void)updateFocusIfNeeded
{
}
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
{
return YES;
}
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
}
- (UIView *)preferredFocusedView
{
if (self.nodeLoaded) {
return self.view;
} else {
return nil;
}
}
#endif
@end
@implementation ASDisplayNode (Debugging)

View File

@@ -163,7 +163,9 @@
_textKitComponents.textView = self.textView;
//_textKitComponents.textView = NO; // Unfortunately there's a bug here with iOS 7 DP5 that causes the text-view to only be one line high when scrollEnabled is NO. rdar://14729288
_textKitComponents.textView.delegate = self;
#if TARGET_OS_IOS
_textKitComponents.textView.editable = YES;
#endif
_textKitComponents.textView.typingAttributes = _typingAttributes;
_textKitComponents.textView.returnKeyType = _returnKeyType;
_textKitComponents.textView.accessibilityHint = _placeholderTextKitComponents.textStorage.string;

View File

@@ -7,6 +7,7 @@
*/
#import <AsyncDisplayKit/ASImageNode.h>
#if TARGET_OS_IOS
#import <MapKit/MapKit.h>
NS_ASSUME_NONNULL_BEGIN
@@ -48,3 +49,5 @@ NS_ASSUME_NONNULL_BEGIN
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -6,6 +6,7 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#if TARGET_OS_IOS
#import "ASMapNode.h"
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
@@ -247,3 +248,4 @@
}
}
@end
#endif

View File

@@ -6,9 +6,10 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#if TARGET_OS_IOS
#import <AsyncDisplayKit/ASImageNode.h>
#import <AsyncDisplayKit/ASImageProtocols.h>
#import <Photos/Photos.h>
NS_ASSUME_NONNULL_BEGIN
@@ -116,13 +117,14 @@ typedef NS_ENUM(NSUInteger, ASMultiplexImageNodeErrorCode) {
*/
@property (nullable, nonatomic, readonly) ASImageIdentifier displayedImageIdentifier;
#if TARGET_OS_IOS
/**
* @abstract The image manager that this image node should use when requesting images from the Photos framework. If this is `nil` (the default), then `PHImageManager.defaultManager` is used.
* @see `+[NSURL URLWithAssetLocalIdentifier:targetSize:contentMode:options:]` below.
*/
@property (nonatomic, strong) PHImageManager *imageManager;
#endif
@end
@@ -229,6 +231,7 @@ didFinishDownloadingImageWithIdentifier:(ASImageIdentifier)imageIdentifier
*/
- (nullable NSURL *)multiplexImageNode:(ASMultiplexImageNode *)imageNode URLForImageIdentifier:(ASImageIdentifier)imageIdentifier;
#if TARGET_OS_IOS
/**
* @abstract A PHAsset for the specific asset local identifier
* @param imageNode The sender.
@@ -240,11 +243,11 @@ didFinishDownloadingImageWithIdentifier:(ASImageIdentifier)imageIdentifier
* @return A PHAsset corresponding to `assetLocalIdentifier`, or nil if none is available.
*/
- (nullable PHAsset *)multiplexImageNode:(ASMultiplexImageNode *)imageNode assetForLocalIdentifier:(NSString *)assetLocalIdentifier;
#endif
@end
#pragma mark -
#if TARGET_OS_IOS
@interface NSURL (ASPhotosFrameworkURLs)
/**
@@ -261,5 +264,8 @@ didFinishDownloadingImageWithIdentifier:(ASImageIdentifier)imageIdentifier
options:(PHImageRequestOptions *)options;
@end
#endif
NS_ASSUME_NONNULL_END
#endif

View File

@@ -6,12 +6,12 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "ASMultiplexImageNode.h"
#if TARGET_OS_IOS
#import "ASMultiplexImageNode.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <Photos/Photos.h>
#import <libkern/OSAtomic.h>
#import "ASAvailability.h"
@@ -112,6 +112,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
*/
- (void)_fetchImageWithIdentifierFromCache:(id)imageIdentifier URL:(NSURL *)imageURL completion:(void (^)(UIImage *image))completionBlock;
#if TARGET_OS_IOS
/**
@abstract Loads the image corresponding to the given assetURL from the device's Assets Library.
@param imageIdentifier The identifier for the image to be loaded. May not be nil.
@@ -131,7 +132,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
@param error An error describing why the load failed, if it failed; nil otherwise.
*/
- (void)_loadPHAssetWithRequest:(ASPhotosFrameworkImageRequest *)request identifier:(id)imageIdentifier completion:(void (^)(UIImage *image, NSError *error))completionBlock;
#endif
/**
@abstract Downloads the image corresponding to the given imageIdentifier from the given URL.
@param imageIdentifier The identifier for the image to be downloaded. May not be nil.
@@ -262,7 +263,9 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
_dataSource = dataSource;
_dataSourceFlags.image = [_dataSource respondsToSelector:@selector(multiplexImageNode:imageForImageIdentifier:)];
_dataSourceFlags.URL = [_dataSource respondsToSelector:@selector(multiplexImageNode:URLForImageIdentifier:)];
#if TARGET_OS_IOS
_dataSourceFlags.asset = [_dataSource respondsToSelector:@selector(multiplexImageNode:assetForLocalIdentifier:)];
#endif
}
#pragma mark -
@@ -455,6 +458,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
return;
}
#if TARGET_OS_IOS
// If it's an assets-library URL, we need to fetch it from the assets library.
if ([[nextImageURL scheme] isEqualToString:kAssetsLibraryURLScheme]) {
// Load the asset.
@@ -470,6 +474,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
finishedLoadingBlock(image, nextImageIdentifier, error);
}];
}
#endif
else // Otherwise, it's a web URL that we can download.
{
// First, check the cache.
@@ -499,7 +504,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
}];
}
}
#if TARGET_OS_IOS
- (void)_loadALAssetWithIdentifier:(id)imageIdentifier URL:(NSURL *)assetURL completion:(void (^)(UIImage *image, NSError *error))completionBlock
{
ASDisplayNodeAssertNotNil(imageIdentifier, @"imageIdentifier is required");
@@ -609,7 +614,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
_phImageRequestOperation = newImageRequestOp;
[phImageRequestQueue addOperation:newImageRequestOp];
}
#endif
- (void)_fetchImageWithIdentifierFromCache:(id)imageIdentifier URL:(NSURL *)imageURL completion:(void (^)(UIImage *image))completionBlock
{
ASDisplayNodeAssertNotNil(imageIdentifier, @"imageIdentifier is required");
@@ -708,7 +713,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
}
@end
#if TARGET_OS_IOS
@implementation NSURL (ASPhotosFrameworkURLs)
+ (NSURL *)URLWithAssetLocalIdentifier:(NSString *)assetLocalIdentifier targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(PHImageRequestOptions *)options
@@ -721,3 +726,6 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
}
@end
#endif
#endif

View File

@@ -48,12 +48,13 @@
[super didLoad];
ASCollectionView *cv = self.view;
#if TARGET_OS_IOS
cv.pagingEnabled = YES;
cv.scrollsToTop = NO;
#endif
cv.allowsSelection = NO;
cv.showsVerticalScrollIndicator = NO;
cv.showsHorizontalScrollIndicator = NO;
cv.scrollsToTop = NO;
// Zeroing contentInset is important, as UIKit will set the top inset for the navigation bar even though
// our view is only horizontally scrollable. This causes UICollectionViewFlowLayout to log a warning.

View File

@@ -73,8 +73,9 @@ NS_ASSUME_NONNULL_BEGIN
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
- (nullable NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
#if TARGET_OS_IOS
- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath;
#endif
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath;

View File

@@ -5,7 +5,7 @@
// Created by Adlai Holler on 9/25/15.
// Copyright © 2015 Facebook. All rights reserved.
//
#if TARGET_OS_IOS
#import <Foundation/Foundation.h>
#import <Photos/Photos.h>
@@ -64,3 +64,4 @@ extern NSString *const ASPhotosURLScheme;
@end
// NS_ASSUME_NONNULL_END
#endif

View File

@@ -5,7 +5,7 @@
// Created by Adlai Holler on 9/25/15.
// Copyright © 2015 Facebook. All rights reserved.
//
#if TARGET_OS_IOS
#import "ASPhotosFrameworkImageRequest.h"
#import "ASBaseDefines.h"
#import "ASAvailability.h"
@@ -159,3 +159,4 @@ static NSString *const _ASPhotosURLQueryKeyCropHeight = @"crop_h";
}
@end
#endif

View File

@@ -331,4 +331,36 @@
return _node;
}
#if TARGET_OS_TV
#pragma mark - tvOS
- (BOOL)canBecomeFocused
{
return [_node canBecomeFocused];
}
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
return [_node didUpdateFocusInContext:context withAnimationCoordinator:coordinator];
}
- (void)setNeedsFocusUpdate
{
return [_node setNeedsFocusUpdate];
}
- (void)updateFocusIfNeeded
{
return [_node updateFocusIfNeeded];
}
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
{
return [_node shouldUpdateFocusInContext:context];
}
- (UIView *)preferredFocusedView
{
return [_node preferredFocusedView];
}
#endif
@end

View File

@@ -81,6 +81,46 @@
return YES;
}
#if TARGET_OS_TV
// Focus Engine
- (BOOL)canBecomeFocused
{
return YES;
}
- (void)setNeedsFocusUpdate
{
ASDisplayNodeAssertMainThread();
[_view setNeedsFocusUpdate];
}
- (void)updateFocusIfNeeded
{
ASDisplayNodeAssertMainThread();
[_view updateFocusIfNeeded];
}
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
{
return YES;
}
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
}
- (UIView *)preferredFocusedView
{
if (self.nodeLoaded) {
return _view;
}
else {
return nil;
}
}
#endif
- (BOOL)isFirstResponder
{
ASDisplayNodeAssertMainThread();
@@ -298,7 +338,7 @@
_bridge_prologue;
_setToViewOnly(userInteractionEnabled, enabled);
}
#if TARGET_OS_IOS
- (BOOL)isExclusiveTouch
{
_bridge_prologue;
@@ -310,7 +350,7 @@
_bridge_prologue;
_setToViewOnly(exclusiveTouch, exclusiveTouch);
}
#endif
- (BOOL)clipsToBounds
{
_bridge_prologue;

View File

@@ -716,8 +716,10 @@ static UIColor *defaultTintColor = nil;
if (_flags.setUserInteractionEnabled)
view.userInteractionEnabled = userInteractionEnabled;
#if TARGET_OS_IOS
if (_flags.setExclusiveTouch)
view.exclusiveTouch = exclusiveTouch;
#endif
if (_flags.setShadowColor)
layer.shadowColor = shadowColor;
@@ -943,10 +945,10 @@ static UIColor *defaultTintColor = nil;
pendingState.userInteractionEnabled = view.userInteractionEnabled;
(pendingState->_flags).setUserInteractionEnabled = YES;
#if TARGET_OS_IOS
pendingState.exclusiveTouch = view.exclusiveTouch;
(pendingState->_flags).setExclusiveTouch = YES;
#endif
pendingState.shadowColor = layer.shadowColor;
(pendingState->_flags).setShadowColor = YES;