mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Merge commit '89156ebbc750a2d28b8d4594ccad62ef4c73127e'
This commit is contained in:
22
.buckconfig
Normal file
22
.buckconfig
Normal file
@@ -0,0 +1,22 @@
|
||||
[cxx]
|
||||
default_platform = iphonesimulator-x86_64
|
||||
combined_preprocess_and_compile = true
|
||||
|
||||
[apple]
|
||||
iphonesimulator_target_sdk_version = 8.0
|
||||
iphoneos_target_sdk_version = 8.0
|
||||
xctool_default_destination_specifier = platform=iOS Simulator, name=iPhone 6, OS=10.2
|
||||
|
||||
[alias]
|
||||
lib = //:AsyncDisplayKit
|
||||
tests = //:Tests
|
||||
|
||||
[httpserver]
|
||||
port = 8080
|
||||
|
||||
[project]
|
||||
ide = xcode
|
||||
ignore = .buckd, \
|
||||
.hg, \
|
||||
.git, \
|
||||
buck-out, \
|
||||
1
.buckversion
Normal file
1
.buckversion
Normal file
@@ -0,0 +1 @@
|
||||
c948c20ebb155904909af05cfd16428a6992b98d
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -29,3 +29,8 @@ build
|
||||
timeline.xctimeline
|
||||
playground.xcworkspace
|
||||
|
||||
# Buck
|
||||
/buck-out
|
||||
/.buckconfig.local
|
||||
/.buckd
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
254C6B7D1BF94DF4003EC431 /* ASTextKitShadower.h in Headers */ = {isa = PBXBuildFile; fileRef = 2577549F1BEE44CD00737CA5 /* ASTextKitShadower.h */; };
|
||||
254C6B7E1BF94DF4003EC431 /* ASTextKitTailTruncater.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754A11BEE44CD00737CA5 /* ASTextKitTailTruncater.h */; };
|
||||
254C6B7F1BF94DF4003EC431 /* ASTextKitTruncating.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754A31BEE44CD00737CA5 /* ASTextKitTruncating.h */; };
|
||||
254C6B821BF94F8A003EC431 /* ASTextKitComponents.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754B71BEE458D00737CA5 /* ASTextKitComponents.m */; };
|
||||
254C6B821BF94F8A003EC431 /* ASTextKitComponents.mm in Sources */ = {isa = PBXBuildFile; fileRef = 257754B71BEE458D00737CA5 /* ASTextKitComponents.mm */; };
|
||||
254C6B831BF94F8A003EC431 /* ASTextKitCoreTextAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754B81BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m */; };
|
||||
254C6B841BF94F8A003EC431 /* ASTextNodeWordKerner.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */; };
|
||||
254C6B851BF94F8A003EC431 /* ASTextKitAttributes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 257754941BEE44CD00737CA5 /* ASTextKitAttributes.mm */; };
|
||||
@@ -112,7 +112,7 @@
|
||||
257754B01BEE44CD00737CA5 /* ASTextKitRenderer+TextChecking.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2577549E1BEE44CD00737CA5 /* ASTextKitRenderer+TextChecking.mm */; };
|
||||
257754B21BEE44CD00737CA5 /* ASTextKitShadower.mm in Sources */ = {isa = PBXBuildFile; fileRef = 257754A01BEE44CD00737CA5 /* ASTextKitShadower.mm */; };
|
||||
257754B41BEE44CD00737CA5 /* ASTextKitTailTruncater.mm in Sources */ = {isa = PBXBuildFile; fileRef = 257754A21BEE44CD00737CA5 /* ASTextKitTailTruncater.mm */; };
|
||||
257754BE1BEE458E00737CA5 /* ASTextKitComponents.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754B71BEE458D00737CA5 /* ASTextKitComponents.m */; };
|
||||
257754BE1BEE458E00737CA5 /* ASTextKitComponents.mm in Sources */ = {isa = PBXBuildFile; fileRef = 257754B71BEE458D00737CA5 /* ASTextKitComponents.mm */; };
|
||||
257754BF1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754B81BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m */; };
|
||||
257754C41BEE458E00737CA5 /* ASTextNodeWordKerner.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */; };
|
||||
25E327571C16819500A2170C /* ASPagerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E327541C16819500A2170C /* ASPagerNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@@ -203,8 +203,16 @@
|
||||
6907C2581DC4ECFE00374C66 /* ASObjectDescriptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 6907C2561DC4ECFE00374C66 /* ASObjectDescriptionHelpers.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
6907C2591DC4ECFE00374C66 /* ASObjectDescriptionHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 6907C2571DC4ECFE00374C66 /* ASObjectDescriptionHelpers.m */; };
|
||||
6907C25A1DC4ECFE00374C66 /* ASObjectDescriptionHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 6907C2571DC4ECFE00374C66 /* ASObjectDescriptionHelpers.m */; };
|
||||
690C35611E055C5D00069B91 /* ASDimensionInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 690C35601E055C5D00069B91 /* ASDimensionInternal.mm */; };
|
||||
690C35621E055C5D00069B91 /* ASDimensionInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 690C35601E055C5D00069B91 /* ASDimensionInternal.mm */; };
|
||||
690C35641E055C7B00069B91 /* ASDimensionInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 690C35631E055C7B00069B91 /* ASDimensionInternal.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
690C35661E0567C600069B91 /* ASDimensionDeprecated.mm in Sources */ = {isa = PBXBuildFile; fileRef = 690C35651E0567C600069B91 /* ASDimensionDeprecated.mm */; };
|
||||
690C35671E0567C600069B91 /* ASDimensionDeprecated.mm in Sources */ = {isa = PBXBuildFile; fileRef = 690C35651E0567C600069B91 /* ASDimensionDeprecated.mm */; };
|
||||
690C356B1E05680300069B91 /* ASDimensionDeprecated.h in Headers */ = {isa = PBXBuildFile; fileRef = 690C356A1E05680300069B91 /* ASDimensionDeprecated.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
69127CFE1DD2B387004BF6E2 /* ASEventLog.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 696F01EA1DD2AF450049FBD5 /* ASEventLog.h */; };
|
||||
693117CE1DC7C72700DE4784 /* ASDisplayNode+Deprecated.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 683489271D70DE3400327501 /* ASDisplayNode+Deprecated.h */; };
|
||||
693DA50F1E2536A600F66DF4 /* ASDimensionInternal.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 690C35631E055C7B00069B91 /* ASDimensionInternal.h */; };
|
||||
693DA5141E25373100F66DF4 /* ASDimensionDeprecated.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 690C356A1E05680300069B91 /* ASDimensionDeprecated.h */; };
|
||||
69527B121DC84292004785FB /* ASLayoutElementStylePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 69527B111DC84292004785FB /* ASLayoutElementStylePrivate.h */; };
|
||||
6959433E1D70815300B0EE1F /* ASDisplayNodeLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6959433C1D70815300B0EE1F /* ASDisplayNodeLayout.mm */; };
|
||||
6959433F1D70815300B0EE1F /* ASDisplayNodeLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6959433C1D70815300B0EE1F /* ASDisplayNodeLayout.mm */; };
|
||||
@@ -673,6 +681,8 @@
|
||||
dstPath = "include/$(PRODUCT_NAME)";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
693DA5141E25373100F66DF4 /* ASDimensionDeprecated.h in CopyFiles */,
|
||||
693DA50F1E2536A600F66DF4 /* ASDimensionInternal.h in CopyFiles */,
|
||||
68C2155C1DE11AA80019C4BC /* ASObjectDescriptionHelpers.h in CopyFiles */,
|
||||
68C2155B1DE11A790019C4BC /* ASCollectionViewLayoutInspector.h in CopyFiles */,
|
||||
DEB8ED7E1DD007F400DBDE55 /* ASLayoutElementInspectorNode.h in CopyFiles */,
|
||||
@@ -956,7 +966,7 @@
|
||||
257754A11BEE44CD00737CA5 /* ASTextKitTailTruncater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitTailTruncater.h; path = TextKit/ASTextKitTailTruncater.h; sourceTree = "<group>"; };
|
||||
257754A21BEE44CD00737CA5 /* ASTextKitTailTruncater.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASTextKitTailTruncater.mm; path = TextKit/ASTextKitTailTruncater.mm; sourceTree = "<group>"; };
|
||||
257754A31BEE44CD00737CA5 /* ASTextKitTruncating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitTruncating.h; path = TextKit/ASTextKitTruncating.h; sourceTree = "<group>"; };
|
||||
257754B71BEE458D00737CA5 /* ASTextKitComponents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASTextKitComponents.m; path = TextKit/ASTextKitComponents.m; sourceTree = "<group>"; };
|
||||
257754B71BEE458D00737CA5 /* ASTextKitComponents.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASTextKitComponents.mm; path = TextKit/ASTextKitComponents.mm; sourceTree = "<group>"; };
|
||||
257754B81BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASTextKitCoreTextAdditions.m; path = TextKit/ASTextKitCoreTextAdditions.m; sourceTree = "<group>"; };
|
||||
257754B91BEE458E00737CA5 /* ASTextNodeWordKerner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextNodeWordKerner.h; path = TextKit/ASTextNodeWordKerner.h; sourceTree = "<group>"; };
|
||||
257754BA1BEE458E00737CA5 /* ASTextKitComponents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitComponents.h; path = TextKit/ASTextKitComponents.h; sourceTree = "<group>"; };
|
||||
@@ -1003,6 +1013,10 @@
|
||||
68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASVisibilityProtocols.m; sourceTree = "<group>"; };
|
||||
6907C2561DC4ECFE00374C66 /* ASObjectDescriptionHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASObjectDescriptionHelpers.h; sourceTree = "<group>"; };
|
||||
6907C2571DC4ECFE00374C66 /* ASObjectDescriptionHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASObjectDescriptionHelpers.m; sourceTree = "<group>"; };
|
||||
690C35601E055C5D00069B91 /* ASDimensionInternal.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASDimensionInternal.mm; path = AsyncDisplayKit/Layout/ASDimensionInternal.mm; sourceTree = "<group>"; };
|
||||
690C35631E055C7B00069B91 /* ASDimensionInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASDimensionInternal.h; path = AsyncDisplayKit/Layout/ASDimensionInternal.h; sourceTree = "<group>"; };
|
||||
690C35651E0567C600069B91 /* ASDimensionDeprecated.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASDimensionDeprecated.mm; path = AsyncDisplayKit/Layout/ASDimensionDeprecated.mm; sourceTree = "<group>"; };
|
||||
690C356A1E05680300069B91 /* ASDimensionDeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASDimensionDeprecated.h; path = AsyncDisplayKit/Layout/ASDimensionDeprecated.h; sourceTree = "<group>"; };
|
||||
69527B111DC84292004785FB /* ASLayoutElementStylePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutElementStylePrivate.h; path = AsyncDisplayKit/Layout/ASLayoutElementStylePrivate.h; sourceTree = SOURCE_ROOT; };
|
||||
6959433C1D70815300B0EE1F /* ASDisplayNodeLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayNodeLayout.mm; sourceTree = "<group>"; };
|
||||
6959433D1D70815300B0EE1F /* ASDisplayNodeLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDisplayNodeLayout.h; sourceTree = "<group>"; };
|
||||
@@ -1658,7 +1672,7 @@
|
||||
B30BF6501C5964B0004FCD53 /* ASLayoutManager.h */,
|
||||
B30BF6511C5964B0004FCD53 /* ASLayoutManager.m */,
|
||||
257754BA1BEE458E00737CA5 /* ASTextKitComponents.h */,
|
||||
257754B71BEE458D00737CA5 /* ASTextKitComponents.m */,
|
||||
257754B71BEE458D00737CA5 /* ASTextKitComponents.mm */,
|
||||
257754BB1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h */,
|
||||
257754B81BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m */,
|
||||
257754B91BEE458E00737CA5 /* ASTextNodeWordKerner.h */,
|
||||
@@ -1731,6 +1745,10 @@
|
||||
ACF6ED041B17843500DA7C62 /* ASCenterLayoutSpec.mm */,
|
||||
ACF6ED071B17843500DA7C62 /* ASDimension.h */,
|
||||
ACF6ED081B17843500DA7C62 /* ASDimension.mm */,
|
||||
690C356A1E05680300069B91 /* ASDimensionDeprecated.h */,
|
||||
690C35651E0567C600069B91 /* ASDimensionDeprecated.mm */,
|
||||
690C35631E055C7B00069B91 /* ASDimensionInternal.h */,
|
||||
690C35601E055C5D00069B91 /* ASDimensionInternal.mm */,
|
||||
ACF6ED091B17843500DA7C62 /* ASInsetLayoutSpec.h */,
|
||||
ACF6ED0A1B17843500DA7C62 /* ASInsetLayoutSpec.mm */,
|
||||
ACF6ED0B1B17843500DA7C62 /* ASLayout.h */,
|
||||
@@ -1808,6 +1826,8 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
696F01EC1DD2AF450049FBD5 /* ASEventLog.h in Headers */,
|
||||
690C35641E055C7B00069B91 /* ASDimensionInternal.h in Headers */,
|
||||
690C356B1E05680300069B91 /* ASDimensionDeprecated.h in Headers */,
|
||||
683489281D70DE3400327501 /* ASDisplayNode+Deprecated.h in Headers */,
|
||||
6907C2581DC4ECFE00374C66 /* ASObjectDescriptionHelpers.h in Headers */,
|
||||
69E0E8A71D356C9400627613 /* ASEqualityHelpers.h in Headers */,
|
||||
@@ -2195,6 +2215,7 @@
|
||||
8B0768B41CE752EC002E1453 /* ASDefaultPlaybackButton.m in Sources */,
|
||||
E55D86321CA8A14000A0C26F /* ASLayoutElement.mm in Sources */,
|
||||
68FC85E41CE29B7E00EDD713 /* ASTabBarController.m in Sources */,
|
||||
690C35661E0567C600069B91 /* ASDimensionDeprecated.mm in Sources */,
|
||||
058D0A23195D050800B7D73C /* _ASAsyncTransactionContainer.m in Sources */,
|
||||
058D0A24195D050800B7D73C /* _ASAsyncTransactionGroup.m in Sources */,
|
||||
68355B3A1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m in Sources */,
|
||||
@@ -2287,7 +2308,7 @@
|
||||
9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */,
|
||||
251B8EF81BBB3D690087C538 /* ASCollectionDataController.mm in Sources */,
|
||||
ACF6ED301B17843500DA7C62 /* ASStackLayoutSpec.mm in Sources */,
|
||||
257754BE1BEE458E00737CA5 /* ASTextKitComponents.m in Sources */,
|
||||
257754BE1BEE458E00737CA5 /* ASTextKitComponents.mm in Sources */,
|
||||
257754A91BEE44CD00737CA5 /* ASTextKitContext.mm in Sources */,
|
||||
ACF6ED501B17847A00DA7C62 /* ASStackPositionedLayout.mm in Sources */,
|
||||
ACF6ED521B17847A00DA7C62 /* ASStackUnpositionedLayout.mm in Sources */,
|
||||
@@ -2299,6 +2320,7 @@
|
||||
92074A691CC8BADA00918F75 /* ASControlNode+tvOS.m in Sources */,
|
||||
ACF6ED321B17843500DA7C62 /* ASAbsoluteLayoutSpec.mm in Sources */,
|
||||
AC026B6B1BD57D6F00BBC17E /* ASChangeSetDataController.mm in Sources */,
|
||||
690C35611E055C5D00069B91 /* ASDimensionInternal.mm in Sources */,
|
||||
68355B311CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */,
|
||||
68C215591DE10D330019C4BC /* ASCollectionViewLayoutInspector.m in Sources */,
|
||||
9CFFC6C01CCAC73C006A6476 /* ASViewController.mm in Sources */,
|
||||
@@ -2386,6 +2408,7 @@
|
||||
9C70F2091CDABA36007D6C76 /* ASViewController.mm in Sources */,
|
||||
8BBBAB8D1CEBAF1E00107FC6 /* ASDefaultPlaybackButton.m in Sources */,
|
||||
B30BF6541C59D889004FCD53 /* ASLayoutManager.m in Sources */,
|
||||
690C35671E0567C600069B91 /* ASDimensionDeprecated.mm in Sources */,
|
||||
92DD2FE71BF4D0850074C9DD /* ASMapNode.mm in Sources */,
|
||||
636EA1A51C7FF4EF00EE152F /* ASDefaultPlayButton.m in Sources */,
|
||||
9B92C8861BC2EB7600EE46B2 /* ASCollectionViewFlowLayoutInspector.m in Sources */,
|
||||
@@ -2449,7 +2472,7 @@
|
||||
B35062541B010EFD0018CF92 /* ASImageNode+CGExtras.m in Sources */,
|
||||
68355B401CB57A69001D4E68 /* ASImageContainerProtocolCategories.m in Sources */,
|
||||
B35062031B010EFD0018CF92 /* ASImageNode.mm in Sources */,
|
||||
254C6B821BF94F8A003EC431 /* ASTextKitComponents.m in Sources */,
|
||||
254C6B821BF94F8A003EC431 /* ASTextKitComponents.mm in Sources */,
|
||||
430E7C921B4C23F100697A4C /* ASIndexPath.m in Sources */,
|
||||
34EFC7601B701C8B00AD841F /* ASInsetLayoutSpec.mm in Sources */,
|
||||
AC6145441D8AFD4F003D62A2 /* ASSection.m in Sources */,
|
||||
@@ -2490,6 +2513,7 @@
|
||||
AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.mm in Sources */,
|
||||
34EFC7741B701D0A00AD841F /* ASAbsoluteLayoutSpec.mm in Sources */,
|
||||
92074A6A1CC8BADA00918F75 /* ASControlNode+tvOS.m in Sources */,
|
||||
690C35621E055C5D00069B91 /* ASDimensionInternal.mm in Sources */,
|
||||
68C2155A1DE10D330019C4BC /* ASCollectionViewLayoutInspector.m in Sources */,
|
||||
DB78412E1C6BCE1600A9E2B4 /* _ASTransitionContext.m in Sources */,
|
||||
B350620B1B010EFD0018CF92 /* ASTableView.mm in Sources */,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ASCellNode;
|
||||
@class ASCellNode, ASTextNode;
|
||||
|
||||
typedef NSUInteger ASCellNodeAnimation;
|
||||
|
||||
@@ -92,12 +92,6 @@ typedef NS_ENUM(NSUInteger, ASCellNodeVisibilityEvent) {
|
||||
*/
|
||||
@property (nonatomic, strong, readonly, nullable) UICollectionViewLayoutAttributes *layoutAttributes;
|
||||
|
||||
/*
|
||||
* ASTableView uses these properties when configuring UITableViewCells that host ASCellNodes.
|
||||
*/
|
||||
//@property (nonatomic, retain) UIColor *backgroundColor;
|
||||
@property (nonatomic) UITableViewCellSelectionStyle selectionStyle;
|
||||
|
||||
/**
|
||||
* A Boolean value that is synchronized with the underlying collection or tableView cell property.
|
||||
* Setting this value is equivalent to calling selectItem / deselectItem on the collection or table.
|
||||
@@ -169,6 +163,25 @@ typedef NS_ENUM(NSUInteger, ASCellNodeVisibilityEvent) {
|
||||
*/
|
||||
- (void)cellNodeVisibilityEvent:(ASCellNodeVisibilityEvent)event inScrollView:(nullable UIScrollView *)scrollView withCellFrame:(CGRect)cellFrame;
|
||||
|
||||
#pragma mark - UITableViewCell specific passthrough properties
|
||||
|
||||
/* @abstract The selection style when a tap on a cell occurs
|
||||
* @default UITableViewCellSelectionStyleDefault
|
||||
* ASTableView uses these properties when configuring UITableViewCells that host ASCellNodes.
|
||||
*/
|
||||
@property (nonatomic) UITableViewCellSelectionStyle selectionStyle;
|
||||
|
||||
/* @abstract The accessory type view on the right side of the cell. Please take care of your ASLayoutSpec so that doesn't overlay the accessoryView
|
||||
* @default UITableViewCellAccessoryNone
|
||||
* ASTableView uses these properties when configuring UITableViewCells that host ASCellNodes.
|
||||
*/
|
||||
@property (nonatomic) UITableViewCellAccessoryType accessoryType;
|
||||
|
||||
/* @abstract The seperator inset of the cell seperator line
|
||||
* ASTableView uses these properties when configuring UITableViewCells that host ASCellNodes.
|
||||
*/
|
||||
@property (nonatomic) UIEdgeInsets seperatorInset;
|
||||
|
||||
@end
|
||||
|
||||
@interface ASCellNode (Unavailable)
|
||||
@@ -207,6 +220,11 @@ typedef NS_ENUM(NSUInteger, ASCellNodeVisibilityEvent) {
|
||||
*/
|
||||
@property (nonatomic, assign) UIEdgeInsets textInsets;
|
||||
|
||||
/**
|
||||
* The text node used by this cell node.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) ASTextNode *textNode;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -397,13 +397,6 @@ static NSMutableSet *__cellClassesForVisibilityNotifications = nil; // See +init
|
||||
#pragma mark -
|
||||
#pragma mark ASTextCellNode
|
||||
|
||||
@interface ASTextCellNode ()
|
||||
|
||||
@property (nonatomic, strong) ASTextNode *textNode;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation ASTextCellNode
|
||||
|
||||
static const CGFloat kASTextCellNodeDefaultFontSize = 18.0f;
|
||||
@@ -422,7 +415,7 @@ static const CGFloat kASTextCellNodeDefaultVerticalPadding = 11.0f;
|
||||
_textInsets = textInsets;
|
||||
_textAttributes = [textAttributes copy];
|
||||
_textNode = [[ASTextNode alloc] init];
|
||||
[self addSubnode:_textNode];
|
||||
self.automaticallyManagesSubnodes = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* Boolean parameter that contains the value YES if all of the related animations completed successfully or
|
||||
* NO if they were interrupted. This parameter may be nil. If supplied, the block is run on the main thread.
|
||||
*/
|
||||
- (void)performBatchAnimated:(BOOL)animated updates:(nullable __attribute((noescape)) void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
- (void)performBatchAnimated:(BOOL)animated updates:(nullable AS_NOESCAPE void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
|
||||
/**
|
||||
* Perform a batch of updates asynchronously, optionally disabling all animations in the batch. This method must be called from the main thread.
|
||||
@@ -184,7 +184,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* Boolean parameter that contains the value YES if all of the related animations completed successfully or
|
||||
* NO if they were interrupted. This parameter may be nil. If supplied, the block is run on the main thread.
|
||||
*/
|
||||
- (void)performBatchUpdates:(nullable __attribute((noescape)) void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
- (void)performBatchUpdates:(nullable AS_NOESCAPE void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
|
||||
/**
|
||||
* Blocks execution of the main thread until all section and item updates are committed to the view. This method must be called from the main thread.
|
||||
|
||||
@@ -227,7 +227,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* Boolean parameter that contains the value YES if all of the related animations completed successfully or
|
||||
* NO if they were interrupted. This parameter may be nil. If supplied, the block is run on the main thread.
|
||||
*/
|
||||
- (void)performBatchAnimated:(BOOL)animated updates:(nullable __attribute((noescape)) void (^)())updates completion:(nullable void (^)(BOOL finished))completion ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode method instead.");
|
||||
- (void)performBatchAnimated:(BOOL)animated updates:(nullable AS_NOESCAPE void (^)())updates completion:(nullable void (^)(BOOL finished))completion ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode method instead.");
|
||||
|
||||
/**
|
||||
* Perform a batch of updates asynchronously. This method must be called from the main thread.
|
||||
@@ -238,7 +238,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* Boolean parameter that contains the value YES if all of the related animations completed successfully or
|
||||
* NO if they were interrupted. This parameter may be nil. If supplied, the block is run on the main thread.
|
||||
*/
|
||||
- (void)performBatchUpdates:(nullable __attribute((noescape)) void (^)())updates completion:(nullable void (^)(BOOL finished))completion ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode method instead.");
|
||||
- (void)performBatchUpdates:(nullable AS_NOESCAPE void (^)())updates completion:(nullable void (^)(BOOL finished))completion ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode method instead.");
|
||||
|
||||
/**
|
||||
* Reload everything from scratch, destroying the working range and all cached nodes.
|
||||
|
||||
@@ -78,6 +78,8 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||
ASDisplayNodeAssertMainThread();
|
||||
node.layoutAttributes = _layoutAttributes;
|
||||
_node = node;
|
||||
self.backgroundColor = node.backgroundColor;
|
||||
self.clipsToBounds = node.clipsToBounds;
|
||||
[node __setSelectedFromUIKit:self.selected];
|
||||
[node __setHighlightedFromUIKit:self.highlighted];
|
||||
}
|
||||
@@ -121,6 +123,15 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||
self.layoutAttributes = layoutAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep our node filling our content view.
|
||||
*/
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
self.node.frame = self.contentView.bounds;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
@@ -283,6 +294,14 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||
if (!(self = [super initWithFrame:frame collectionViewLayout:layout]))
|
||||
return nil;
|
||||
|
||||
// Disable UICollectionView prefetching.
|
||||
// Experiments done by Instagram show that this option being YES (default)
|
||||
// when unused causes a significant hit to scroll performance.
|
||||
// https://github.com/Instagram/IGListKit/issues/318
|
||||
if (AS_AT_LEAST_IOS10) {
|
||||
self.prefetchingEnabled = NO;
|
||||
}
|
||||
|
||||
_layoutController = [[ASCollectionViewLayoutController alloc] initWithCollectionView:self];
|
||||
|
||||
_rangeController = [[ASRangeController alloc] init];
|
||||
@@ -614,6 +633,10 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||
|
||||
- (NSIndexPath *)convertIndexPathFromCollectionNode:(NSIndexPath *)indexPath waitingIfNeeded:(BOOL)wait
|
||||
{
|
||||
if (indexPath == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// If this is a section index path, we don't currently have a method
|
||||
// to do a mapping.
|
||||
if (indexPath.item == NSNotFound) {
|
||||
@@ -751,7 +774,8 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||
|
||||
- (void)performBatchUpdates:(void (^)())updates completion:(void (^)(BOOL))completion
|
||||
{
|
||||
[self performBatchAnimated:YES updates:updates completion:completion];
|
||||
// We capture the current state of whether animations are enabled if they don't provide us with one.
|
||||
[self performBatchAnimated:[UIView areAnimationsEnabled] updates:updates completion:completion];
|
||||
}
|
||||
|
||||
- (void)registerSupplementaryNodeOfKind:(NSString *)elementKind
|
||||
|
||||
@@ -63,6 +63,14 @@ id<NSCopying> _ASControlNodeEventKeyForControlEvent(ASControlNodeEvent controlEv
|
||||
*/
|
||||
void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, void (^block)(ASControlNodeEvent anEvent));
|
||||
|
||||
/**
|
||||
@abstract Returns the expanded bounds used to determine if a touch is considered 'inside' during tracking.
|
||||
@param controlNode A control node.
|
||||
@result The expanded bounds of the node.
|
||||
*/
|
||||
CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode);
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASControlNode
|
||||
@@ -158,7 +166,7 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v
|
||||
BOOL dragIsInsideBounds = [self pointInside:touchLocation withEvent:nil];
|
||||
|
||||
// Update our highlighted state.
|
||||
CGRect expandedBounds = CGRectInset(self.view.bounds, kASControlNodeExpandedInset, kASControlNodeExpandedInset);
|
||||
CGRect expandedBounds = _ASControlNodeGetExpandedBounds(self);
|
||||
BOOL dragIsInsideExpandedBounds = CGRectContainsPoint(expandedBounds, touchLocation);
|
||||
self.touchInside = dragIsInsideExpandedBounds;
|
||||
self.highlighted = dragIsInsideExpandedBounds;
|
||||
@@ -216,7 +224,7 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v
|
||||
[self endTrackingWithTouch:theTouch withEvent:event];
|
||||
|
||||
// Send the appropriate touch-up control event.
|
||||
CGRect expandedBounds = CGRectInset(self.view.bounds, kASControlNodeExpandedInset, kASControlNodeExpandedInset);
|
||||
CGRect expandedBounds = _ASControlNodeGetExpandedBounds(self);
|
||||
BOOL touchUpIsInsideExpandedBounds = CGRectContainsPoint(expandedBounds, touchLocation);
|
||||
|
||||
[self sendActionsForControlEvents:(touchUpIsInsideExpandedBounds ? ASControlNodeEventTouchUpInside : ASControlNodeEventTouchUpOutside)
|
||||
@@ -428,6 +436,10 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v
|
||||
}
|
||||
}
|
||||
|
||||
CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode) {
|
||||
return CGRectInset(UIEdgeInsetsInsetRect(controlNode.view.bounds, controlNode.hitTestSlop), kASControlNodeExpandedInset, kASControlNodeExpandedInset);
|
||||
}
|
||||
|
||||
#pragma mark - For Subclasses
|
||||
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)touchEvent
|
||||
{
|
||||
|
||||
@@ -195,7 +195,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* @note Called on the display queue and/or main queue (MUST BE THREAD SAFE)
|
||||
*/
|
||||
+ (void)drawRect:(CGRect)bounds withParameters:(nullable id <NSObject>)parameters
|
||||
isCancelled:(__attribute((noescape)) asdisplaynode_iscancelled_block_t)isCancelledBlock
|
||||
isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock
|
||||
isRasterizing:(BOOL)isRasterizing;
|
||||
|
||||
/**
|
||||
@@ -212,7 +212,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* @note Called on the display queue and/or main queue (MUST BE THREAD SAFE)
|
||||
*/
|
||||
+ (nullable UIImage *)displayWithParameters:(nullable id<NSObject>)parameters
|
||||
isCancelled:(__attribute((noescape)) asdisplaynode_iscancelled_block_t)isCancelledBlock;
|
||||
isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock;
|
||||
|
||||
/**
|
||||
* @abstract Delegate override for drawParameters
|
||||
|
||||
@@ -1805,6 +1805,21 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
|
||||
- (CGPoint)convertPoint:(CGPoint)point fromNode:(ASDisplayNode *)node
|
||||
{
|
||||
ASDisplayNodeAssertThreadAffinity(self);
|
||||
|
||||
/**
|
||||
* When passed node=nil, all methods in this family use the UIView-style
|
||||
* behavior – that is, convert from/to window coordinates if there's a window,
|
||||
* otherwise return the point untransformed.
|
||||
*/
|
||||
if (node == nil && self.nodeLoaded) {
|
||||
CALayer *layer = self.layer;
|
||||
if (UIWindow *window = ASFindWindowOfLayer(layer)) {
|
||||
return [layer convertPoint:point fromLayer:window.layer];
|
||||
} else {
|
||||
return point;
|
||||
}
|
||||
}
|
||||
|
||||
// Get root node of the accessible node hierarchy, if node not specified
|
||||
node = node ? : ASDisplayNodeUltimateParentOfNode(self);
|
||||
|
||||
@@ -1820,6 +1835,16 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
|
||||
- (CGPoint)convertPoint:(CGPoint)point toNode:(ASDisplayNode *)node
|
||||
{
|
||||
ASDisplayNodeAssertThreadAffinity(self);
|
||||
|
||||
if (node == nil && self.nodeLoaded) {
|
||||
CALayer *layer = self.layer;
|
||||
if (UIWindow *window = ASFindWindowOfLayer(layer)) {
|
||||
return [layer convertPoint:point toLayer:window.layer];
|
||||
} else {
|
||||
return point;
|
||||
}
|
||||
}
|
||||
|
||||
// Get root node of the accessible node hierarchy, if node not specified
|
||||
node = node ? : ASDisplayNodeUltimateParentOfNode(self);
|
||||
|
||||
@@ -1835,6 +1860,16 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
|
||||
- (CGRect)convertRect:(CGRect)rect fromNode:(ASDisplayNode *)node
|
||||
{
|
||||
ASDisplayNodeAssertThreadAffinity(self);
|
||||
|
||||
if (node == nil && self.nodeLoaded) {
|
||||
CALayer *layer = self.layer;
|
||||
if (UIWindow *window = ASFindWindowOfLayer(layer)) {
|
||||
return [layer convertRect:rect fromLayer:window.layer];
|
||||
} else {
|
||||
return rect;
|
||||
}
|
||||
}
|
||||
|
||||
// Get root node of the accessible node hierarchy, if node not specified
|
||||
node = node ? : ASDisplayNodeUltimateParentOfNode(self);
|
||||
|
||||
@@ -1850,6 +1885,16 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
|
||||
- (CGRect)convertRect:(CGRect)rect toNode:(ASDisplayNode *)node
|
||||
{
|
||||
ASDisplayNodeAssertThreadAffinity(self);
|
||||
|
||||
if (node == nil && self.nodeLoaded) {
|
||||
CALayer *layer = self.layer;
|
||||
if (UIWindow *window = ASFindWindowOfLayer(layer)) {
|
||||
return [layer convertRect:rect toLayer:window.layer];
|
||||
} else {
|
||||
return rect;
|
||||
}
|
||||
}
|
||||
|
||||
// Get root node of the accessible node hierarchy, if node not specified
|
||||
node = node ? : ASDisplayNodeUltimateParentOfNode(self);
|
||||
|
||||
|
||||
@@ -125,6 +125,11 @@ extern ASDisplayNode * _Nullable ASDisplayNodeFindFirstSupernode(ASDisplayNode *
|
||||
*/
|
||||
extern __kindof ASDisplayNode * _Nullable ASDisplayNodeFindFirstSupernodeOfClass(ASDisplayNode *start, Class c) AS_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Given a layer, find the window it lives in, if any.
|
||||
*/
|
||||
extern UIWindow * _Nullable ASFindWindowOfLayer(CALayer *layer) AS_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Given two nodes, finds their most immediate common parent. Used for geometry conversion methods.
|
||||
* NOTE: It is an error to try to convert between nodes which do not share a common ancestor. This behavior is
|
||||
|
||||
@@ -249,6 +249,21 @@ static inline BOOL _ASDisplayNodeIsAncestorOfDisplayNode(ASDisplayNode *possible
|
||||
return NO;
|
||||
}
|
||||
|
||||
extern UIWindow * _Nullable ASFindWindowOfLayer(CALayer *layer)
|
||||
{
|
||||
while (layer != nil) {
|
||||
if (UIView *view = ASDynamicCast(layer.delegate, UIView)) {
|
||||
if ([view isKindOfClass:[UIWindow class]]) {
|
||||
return (UIWindow *)view;
|
||||
} else {
|
||||
return view.window;
|
||||
}
|
||||
}
|
||||
layer = layer.superlayer;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
extern ASDisplayNode *ASDisplayNodeFindClosestCommonAncestor(ASDisplayNode *node1, ASDisplayNode *node2)
|
||||
{
|
||||
ASDisplayNode *possibleAncestor = node1;
|
||||
|
||||
@@ -93,16 +93,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, readwrite) UIEdgeInsets textContainerInset;
|
||||
|
||||
/**
|
||||
@abstract <UITextInputTraits> properties.
|
||||
@abstract The maximum number of lines to display. Additional lines will require scrolling.
|
||||
@default 0 (No limit)
|
||||
*/
|
||||
@property(nonatomic, readwrite, assign) UITextAutocapitalizationType autocapitalizationType; // default is UITextAutocapitalizationTypeSentences
|
||||
@property(nonatomic, readwrite, assign) UITextAutocorrectionType autocorrectionType; // default is UITextAutocorrectionTypeDefault
|
||||
@property(nonatomic, readwrite, assign) UITextSpellCheckingType spellCheckingType; // default is UITextSpellCheckingTypeDefault;
|
||||
@property(nonatomic, readwrite, assign) UIKeyboardType keyboardType; // default is UIKeyboardTypeDefault
|
||||
@property(nonatomic, readwrite, assign) UIKeyboardAppearance keyboardAppearance; // default is UIKeyboardAppearanceDefault
|
||||
@property(nonatomic, readwrite, assign) UIReturnKeyType returnKeyType; // default is UIReturnKeyDefault (See note under UIReturnKeyType enum)
|
||||
@property(nonatomic, readwrite, assign) BOOL enablesReturnKeyAutomatically; // default is NO (when YES, will automatically disable return key when text widget has zero-length contents, and will automatically enable when text widget has non-zero-length contents)
|
||||
@property(nonatomic, readwrite, assign, getter=isSecureTextEntry) BOOL secureTextEntry; // default is NO
|
||||
@property (nonatomic, assign) NSUInteger maximumLinesToDisplay;
|
||||
|
||||
/**
|
||||
@abstract Indicates whether the receiver's text view is the first responder, and thus has the keyboard visible and is prepared for editing by the user.
|
||||
@@ -125,6 +119,18 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (CGRect)frameForTextRange:(NSRange)textRange AS_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
@abstract <UITextInputTraits> properties.
|
||||
*/
|
||||
@property(nonatomic, readwrite, assign) UITextAutocapitalizationType autocapitalizationType; // default is UITextAutocapitalizationTypeSentences
|
||||
@property(nonatomic, readwrite, assign) UITextAutocorrectionType autocorrectionType; // default is UITextAutocorrectionTypeDefault
|
||||
@property(nonatomic, readwrite, assign) UITextSpellCheckingType spellCheckingType; // default is UITextSpellCheckingTypeDefault;
|
||||
@property(nonatomic, readwrite, assign) UIKeyboardType keyboardType; // default is UIKeyboardTypeDefault
|
||||
@property(nonatomic, readwrite, assign) UIKeyboardAppearance keyboardAppearance; // default is UIKeyboardAppearanceDefault
|
||||
@property(nonatomic, readwrite, assign) UIReturnKeyType returnKeyType; // default is UIReturnKeyDefault (See note under UIReturnKeyType enum)
|
||||
@property(nonatomic, readwrite, assign) BOOL enablesReturnKeyAutomatically; // default is NO (when YES, will automatically disable return key when text widget has zero-length contents, and will automatically enable when text widget has non-zero-length contents)
|
||||
@property(nonatomic, readwrite, assign, getter=isSecureTextEntry) BOOL secureTextEntry; // default is NO
|
||||
|
||||
@end
|
||||
|
||||
@interface ASEditableTextNode (Unavailable)
|
||||
|
||||
@@ -238,7 +238,16 @@
|
||||
- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
|
||||
{
|
||||
ASTextKitComponents *displayedComponents = [self isDisplayingPlaceholder] ? _placeholderTextKitComponents : _textKitComponents;
|
||||
CGSize textSize = [displayedComponents sizeForConstrainedWidth:constrainedSize.width];
|
||||
|
||||
CGSize textSize;
|
||||
|
||||
if (_maximumLinesToDisplay > 0) {
|
||||
textSize = [displayedComponents sizeForConstrainedWidth:constrainedSize.width
|
||||
forMaxNumberOfLines: _maximumLinesToDisplay];
|
||||
} else {
|
||||
textSize = [displayedComponents sizeForConstrainedWidth:constrainedSize.width];
|
||||
}
|
||||
|
||||
CGFloat width = std::ceil(textSize.width + _textContainerInset.left + _textContainerInset.right);
|
||||
CGFloat height = std::ceil(textSize.height + _textContainerInset.top + _textContainerInset.bottom);
|
||||
return CGSizeMake(std::fmin(width, constrainedSize.width), std::fmin(height, constrainedSize.height));
|
||||
@@ -313,6 +322,12 @@
|
||||
return _textKitComponents.textView;
|
||||
}
|
||||
|
||||
- (void)setMaximumLinesToDisplay:(NSUInteger)maximumLines
|
||||
{
|
||||
_maximumLinesToDisplay = maximumLines;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
@dynamic typingAttributes;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#import "ASEqualityHelpers.h"
|
||||
#import "ASEqualityHashHelpers.h"
|
||||
#import "ASWeakMap.h"
|
||||
#import "CoreGraphics+ASConvenience.h"
|
||||
|
||||
// TODO: It would be nice to remove this dependency; it's the only subclass using more than +FrameworkSubclasses.h
|
||||
#import "ASDisplayNodeInternal.h"
|
||||
@@ -183,6 +184,26 @@ struct ASImageNodeDrawParameters {
|
||||
[self invalidateAnimatedImage];
|
||||
}
|
||||
|
||||
- (UIImage *)placeholderImage
|
||||
{
|
||||
// FIXME: Replace this implementation with reusable CALayers that have .backgroundColor set.
|
||||
// This would completely eliminate the memory and performance cost of the backing store.
|
||||
CGSize size = self.calculatedSize;
|
||||
if ((size.width * size.height) < CGFLOAT_EPSILON) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
|
||||
UIGraphicsBeginImageContext(size);
|
||||
[self.placeholderColor setFill];
|
||||
UIRectFill(CGRectMake(0, 0, size.width, size.height));
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
#pragma mark - Layout and Sizing
|
||||
|
||||
- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
|
||||
|
||||
@@ -27,9 +27,6 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
|
||||
@interface ASNetworkImageNode ()
|
||||
{
|
||||
__weak id<ASImageCacheProtocol> _cache;
|
||||
__weak id<ASImageDownloaderProtocol> _downloader;
|
||||
|
||||
// Only access any of these with __instanceLock__.
|
||||
__weak id<ASNetworkImageNodeDelegate> _delegate;
|
||||
|
||||
@@ -55,6 +52,9 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
} _delegateFlags;
|
||||
|
||||
//set on init only
|
||||
__weak id<ASImageDownloaderProtocol> _downloader;
|
||||
__weak id<ASImageCacheProtocol> _cache;
|
||||
|
||||
struct {
|
||||
unsigned int downloaderImplementsSetProgress:1;
|
||||
unsigned int downloaderImplementsSetPriority:1;
|
||||
@@ -237,12 +237,14 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
}
|
||||
|
||||
- (void)setShouldRenderProgressImages:(BOOL)shouldRenderProgressImages
|
||||
{
|
||||
{
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
if (shouldRenderProgressImages == _shouldRenderProgressImages) {
|
||||
return;
|
||||
}
|
||||
_shouldRenderProgressImages = shouldRenderProgressImages;
|
||||
}
|
||||
|
||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||
}
|
||||
@@ -295,28 +297,41 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
- (void)didEnterVisibleState
|
||||
{
|
||||
[super didEnterVisibleState];
|
||||
|
||||
id downloadIdentifier = nil;
|
||||
|
||||
{
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
|
||||
if (_downloaderFlags.downloaderImplementsSetPriority) {
|
||||
if (_downloadIdentifier != nil) {
|
||||
[_downloader setPriority:ASImageDownloaderPriorityVisible withDownloadIdentifier:_downloadIdentifier];
|
||||
downloadIdentifier = _downloadIdentifier;
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadIdentifier != nil) {
|
||||
[_downloader setPriority:ASImageDownloaderPriorityVisible withDownloadIdentifier:downloadIdentifier];
|
||||
}
|
||||
|
||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||
}
|
||||
|
||||
- (void)didExitVisibleState
|
||||
{
|
||||
[super didExitVisibleState];
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
|
||||
id downloadIdentifier = nil;
|
||||
|
||||
{
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
if (_downloaderFlags.downloaderImplementsSetPriority) {
|
||||
if (_downloadIdentifier != nil) {
|
||||
[_downloader setPriority:ASImageDownloaderPriorityPreload withDownloadIdentifier:_downloadIdentifier];
|
||||
downloadIdentifier = _downloadIdentifier;
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadIdentifier != nil) {
|
||||
[_downloader setPriority:ASImageDownloaderPriorityPreload withDownloadIdentifier:downloadIdentifier];
|
||||
}
|
||||
|
||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||
}
|
||||
|
||||
@@ -372,9 +387,16 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
}
|
||||
|
||||
// Read state.
|
||||
BOOL shouldRender = _shouldRenderProgressImages && ASInterfaceStateIncludesVisible(_interfaceState);
|
||||
id oldDownloadIDForProgressBlock = _downloadIdentifierForProgressBlock;
|
||||
id newDownloadIDForProgressBlock = shouldRender ? _downloadIdentifier : nil;
|
||||
BOOL shouldRender;
|
||||
id oldDownloadIDForProgressBlock;
|
||||
id newDownloadIDForProgressBlock;
|
||||
BOOL clearAndReattempt = NO;
|
||||
{
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
shouldRender = _shouldRenderProgressImages && ASInterfaceStateIncludesVisible(_interfaceState);
|
||||
oldDownloadIDForProgressBlock = _downloadIdentifierForProgressBlock;
|
||||
newDownloadIDForProgressBlock = shouldRender ? _downloadIdentifier : nil;
|
||||
}
|
||||
|
||||
// If we're already bound to the correct download, we're done.
|
||||
if (ASObjectIsEqual(oldDownloadIDForProgressBlock, newDownloadIDForProgressBlock)) {
|
||||
@@ -395,7 +417,19 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
}
|
||||
|
||||
// Update state.
|
||||
{
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
if (_downloadIdentifierForProgressBlock == oldDownloadIDForProgressBlock) {
|
||||
_downloadIdentifierForProgressBlock = newDownloadIDForProgressBlock;
|
||||
} else {
|
||||
clearAndReattempt = YES;
|
||||
}
|
||||
}
|
||||
|
||||
if (clearAndReattempt) {
|
||||
[_downloader setProgressImageBlock:nil callbackQueue:dispatch_get_main_queue() withDownloadIdentifier:newDownloadIDForProgressBlock];
|
||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_cancelDownloadAndClearImage
|
||||
@@ -445,9 +479,19 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
- (void)_downloadImageWithCompletion:(void (^)(id <ASImageContainerProtocol> imageContainer, NSError*, id downloadIdentifier))finished
|
||||
{
|
||||
ASPerformBlockOnBackgroundThread(^{
|
||||
NSURL *url;
|
||||
id downloadIdentifier;
|
||||
BOOL cancelAndReattempt = NO;
|
||||
|
||||
// Below, to avoid performance issues, we're calling downloadImageWithURL without holding the lock. This is a bit ugly because
|
||||
// We need to reobtain the lock after and ensure that the task we've kicked off still matches our URL. If not, we need to cancel
|
||||
// it and try again.
|
||||
{
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
_downloadIdentifier = [_downloader downloadImageWithURL:_URL
|
||||
url = _URL;
|
||||
}
|
||||
|
||||
downloadIdentifier = [_downloader downloadImageWithURL:url
|
||||
callbackQueue:dispatch_get_main_queue()
|
||||
downloadProgress:NULL
|
||||
completion:^(id <ASImageContainerProtocol> _Nullable imageContainer, NSError * _Nullable error, id _Nullable downloadIdentifier) {
|
||||
@@ -456,8 +500,25 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
}
|
||||
}];
|
||||
|
||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||
{
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
if ([_URL isEqual:url]) {
|
||||
// The download we kicked off is correct, no need to do any more work.
|
||||
_downloadIdentifier = downloadIdentifier;
|
||||
} else {
|
||||
// The URL changed since we kicked off our download task. This shouldn't happen often so we'll pay the cost and
|
||||
// cancel that request and kick off a new one.
|
||||
cancelAndReattempt = YES;
|
||||
}
|
||||
}
|
||||
|
||||
if (cancelAndReattempt) {
|
||||
[_downloader cancelImageDownloadForIdentifier:downloadIdentifier];
|
||||
[self _downloadImageWithCompletion:finished];
|
||||
return;
|
||||
}
|
||||
|
||||
[self _updateProgressImageBlockOnDownloaderIfNeeded];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ static void runLoopSourceCallback(void *info) {
|
||||
// 100ms timer. No resources are wasted in between, as the thread sleeps, and each check is fast.
|
||||
// This time is fast enough for most use cases without excessive churn.
|
||||
CFRunLoopTimerRef timer = CFRunLoopTimerCreateWithHandler(NULL, -1, 0.1, 0, 0, ^(CFRunLoopTimerRef timer) {
|
||||
@autoreleasepool {
|
||||
#if ASRunLoopQueueLoggingEnabled
|
||||
NSLog(@"ASDeallocQueue Processing: %d objects destroyed", weakSelf->_queue.size());
|
||||
#endif
|
||||
@@ -73,6 +74,7 @@ static void runLoopSourceCallback(void *info) {
|
||||
weakSelf->_queue = std::deque<id>();
|
||||
weakSelf->_queueLock.unlock();
|
||||
currentQueue.clear();
|
||||
}
|
||||
});
|
||||
|
||||
CFRunLoopRef runloop = CFRunLoopGetCurrent();
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
}
|
||||
// Don't provide a position, as that should be set by the parent.
|
||||
layout = [ASLayout layoutWithLayoutElement:self
|
||||
size:parentSize
|
||||
size:selfSize
|
||||
sublayouts:layout.sublayouts];
|
||||
}
|
||||
return layout;
|
||||
|
||||
@@ -150,7 +150,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* Boolean parameter that contains the value YES if all of the related animations completed successfully or
|
||||
* NO if they were interrupted. This parameter may be nil. If supplied, the block is run on the main thread.
|
||||
*/
|
||||
- (void)performBatchAnimated:(BOOL)animated updates:(nullable __attribute((noescape)) void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
- (void)performBatchAnimated:(BOOL)animated updates:(nullable AS_NOESCAPE void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
|
||||
/**
|
||||
* Perform a batch of updates asynchronously, optionally disabling all animations in the batch. This method must be called from the main thread.
|
||||
@@ -161,7 +161,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* Boolean parameter that contains the value YES if all of the related animations completed successfully or
|
||||
* NO if they were interrupted. This parameter may be nil. If supplied, the block is run on the main thread.
|
||||
*/
|
||||
- (void)performBatchUpdates:(nullable __attribute((noescape)) void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
- (void)performBatchUpdates:(nullable AS_NOESCAPE void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
|
||||
/**
|
||||
* Blocks execution of the main thread until all section and row updates are committed. This method must be called from the main thread.
|
||||
|
||||
@@ -76,6 +76,13 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
- (void)setNode:(ASCellNode *)node
|
||||
{
|
||||
_node = node;
|
||||
|
||||
self.backgroundColor = node.backgroundColor;
|
||||
self.selectionStyle = node.selectionStyle;
|
||||
self.accessoryType = node.accessoryType;
|
||||
self.separatorInset = node.seperatorInset;
|
||||
self.clipsToBounds = node.clipsToBounds;
|
||||
|
||||
[node __setSelectedFromUIKit:self.selected];
|
||||
[node __setHighlightedFromUIKit:self.highlighted];
|
||||
}
|
||||
@@ -593,6 +600,10 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
|
||||
- (nullable NSIndexPath *)indexPathForNode:(ASCellNode *)cellNode waitingIfNeeded:(BOOL)wait
|
||||
{
|
||||
if (cellNode == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSIndexPath *indexPath = [_dataController completedIndexPathForNode:cellNode];
|
||||
indexPath = [self validateIndexPath:indexPath];
|
||||
if (indexPath == nil && wait) {
|
||||
@@ -627,7 +638,8 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
|
||||
- (void)endUpdates
|
||||
{
|
||||
[self endUpdatesAnimated:YES completion:nil];
|
||||
// We capture the current state of whether animations are enabled if they don't provide us with one.
|
||||
[self endUpdatesAnimated:[UIView areAnimationsEnabled] completion:nil];
|
||||
}
|
||||
|
||||
- (void)endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL completed))completion;
|
||||
@@ -801,13 +813,6 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
[_rangeController configureContentView:cell.contentView forCellNode:node];
|
||||
|
||||
cell.node = node;
|
||||
cell.backgroundColor = node.backgroundColor;
|
||||
cell.selectionStyle = node.selectionStyle;
|
||||
|
||||
// the following ensures that we clip the entire cell to it's bounds if node.clipsToBounds is set (the default)
|
||||
// This is actually a workaround for a bug we are seeing in some rare cases (selected background view
|
||||
// overlaps other cells if size of ASCellNode has changed.)
|
||||
cell.clipsToBounds = node.clipsToBounds;
|
||||
}
|
||||
|
||||
return cell;
|
||||
@@ -816,7 +821,18 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ASCellNode *node = [_dataController nodeAtIndexPath:indexPath];
|
||||
return node.calculatedSize.height;
|
||||
CGFloat height = node.calculatedSize.height;
|
||||
|
||||
/**
|
||||
* Weirdly enough, Apple expects the return value here to _include_ the height
|
||||
* of the separator, if there is one! So if our node wants to be 43.5, we need
|
||||
* to return 44. UITableView will make a cell of height 44 with a content view
|
||||
* of height 43.5.
|
||||
*/
|
||||
if (tableView.separatorStyle != UITableViewCellSeparatorStyleNone) {
|
||||
height += 1.0 / ASScreenScale();
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
|
||||
@@ -73,7 +73,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, assign) int32_t periodicTimeObserverTimescale;
|
||||
|
||||
//! Defaults to AVLayerVideoGravityResizeAspect
|
||||
@property (nonatomic) NSString *gravity;
|
||||
@property (nonatomic, copy) NSString *gravity;
|
||||
|
||||
@property (nullable, nonatomic, weak, readwrite) id<ASVideoNodeDelegate, ASNetworkImageNodeDelegate> delegate;
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ static NSString * const kRate = @"rate";
|
||||
|
||||
@interface ASVideoNode ()
|
||||
{
|
||||
__weak id<ASVideoNodeDelegate> _delegate;
|
||||
struct {
|
||||
unsigned int delegateVideNodeShouldChangePlayerStateTo:1;
|
||||
unsigned int delegateVideoDidPlayToEnd:1;
|
||||
@@ -88,6 +87,8 @@ static NSString * const kRate = @"rate";
|
||||
|
||||
@implementation ASVideoNode
|
||||
|
||||
@dynamic delegate;
|
||||
|
||||
// TODO: Support preview images with HTTP Live Streaming videos.
|
||||
|
||||
#pragma mark - Construction and Layout
|
||||
@@ -163,7 +164,7 @@ static NSString * const kRate = @"rate";
|
||||
}
|
||||
|
||||
if (_delegateFlags.delegateVideoNodeDidSetCurrentItem) {
|
||||
[_delegate videoNode:self didSetCurrentItem:playerItem];
|
||||
[self.delegate videoNode:self didSetCurrentItem:playerItem];
|
||||
}
|
||||
|
||||
if (self.image == nil && self.URL == nil) {
|
||||
@@ -316,6 +317,9 @@ static NSString * const kRate = @"rate";
|
||||
if ([change[NSKeyValueChangeNewKey] integerValue] == AVPlayerItemStatusReadyToPlay) {
|
||||
if (self.playerState != ASVideoNodePlayerStatePlaying) {
|
||||
self.playerState = ASVideoNodePlayerStateReadyToPlay;
|
||||
if (_shouldBePlaying && ASInterfaceStateIncludesVisible(self.interfaceState)) {
|
||||
[self play];
|
||||
}
|
||||
}
|
||||
// If we don't yet have a placeholder image update it now that we should have data available for it
|
||||
if (self.image == nil && self.URL == nil) {
|
||||
@@ -334,7 +338,7 @@ static NSString * const kRate = @"rate";
|
||||
}
|
||||
if (_shouldBePlaying && (_shouldAggressivelyRecoverFromStall || likelyToKeepUp) && ASInterfaceStateIncludesVisible(self.interfaceState)) {
|
||||
if (self.playerState == ASVideoNodePlayerStateLoading && _delegateFlags.delegateVideoNodeDidRecoverFromStall) {
|
||||
[_delegate videoNodeDidRecoverFromStall:self];
|
||||
[self.delegate videoNodeDidRecoverFromStall:self];
|
||||
}
|
||||
[self play]; // autoresume after buffer catches up
|
||||
}
|
||||
@@ -359,7 +363,7 @@ static NSString * const kRate = @"rate";
|
||||
- (void)tapped
|
||||
{
|
||||
if (_delegateFlags.delegateDidTapVideoNode) {
|
||||
[_delegate didTapVideoNode:self];
|
||||
[self.delegate didTapVideoNode:self];
|
||||
|
||||
} else {
|
||||
if (_shouldBePlaying) {
|
||||
@@ -383,14 +387,14 @@ static NSString * const kRate = @"rate";
|
||||
|
||||
self.playerState = ASVideoNodePlayerStateLoading;
|
||||
if (_delegateFlags.delegateVideoNodeDidStartInitialLoading) {
|
||||
[_delegate videoNodeDidStartInitialLoading:self];
|
||||
[self.delegate videoNodeDidStartInitialLoading:self];
|
||||
}
|
||||
|
||||
NSArray<NSString *> *requestedKeys = @[@"playable"];
|
||||
[asset loadValuesAsynchronouslyForKeys:requestedKeys completionHandler:^{
|
||||
ASPerformBlockOnMainThread(^{
|
||||
if (_delegateFlags.delegateVideoNodeDidFinishInitialLoading) {
|
||||
[_delegate videoNodeDidFinishInitialLoading:self];
|
||||
[self.delegate videoNodeDidFinishInitialLoading:self];
|
||||
}
|
||||
[self prepareToPlayAsset:asset withKeys:requestedKeys];
|
||||
});
|
||||
@@ -405,7 +409,7 @@ static NSString * const kRate = @"rate";
|
||||
}
|
||||
|
||||
if (_delegateFlags.delegateVideoNodeDidPlayToTimeInterval) {
|
||||
[_delegate videoNode:self didPlayToTimeInterval:timeInSeconds];
|
||||
[self.delegate videoNode:self didPlayToTimeInterval:timeInSeconds];
|
||||
|
||||
}
|
||||
}
|
||||
@@ -465,7 +469,7 @@ static NSString * const kRate = @"rate";
|
||||
}
|
||||
|
||||
if (_delegateFlags.delegateVideoNodeWillChangePlayerStateToState) {
|
||||
[_delegate videoNode:self willChangePlayerState:oldState toState:playerState];
|
||||
[self.delegate videoNode:self willChangePlayerState:oldState toState:playerState];
|
||||
}
|
||||
|
||||
_playerState = playerState;
|
||||
@@ -564,28 +568,23 @@ static NSString * const kRate = @"rate";
|
||||
return (AVPlayerLayer *)_playerNode.layer;
|
||||
}
|
||||
|
||||
- (id<ASVideoNodeDelegate>)delegate{
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id<ASVideoNodeDelegate>)delegate
|
||||
{
|
||||
[super setDelegate:delegate];
|
||||
_delegate = delegate;
|
||||
|
||||
if (_delegate == nil) {
|
||||
if (delegate == nil) {
|
||||
memset(&_delegateFlags, 0, sizeof(_delegateFlags));
|
||||
} else {
|
||||
_delegateFlags.delegateVideNodeShouldChangePlayerStateTo = [_delegate respondsToSelector:@selector(videoNode:shouldChangePlayerStateTo:)];
|
||||
_delegateFlags.delegateVideoDidPlayToEnd = [_delegate respondsToSelector:@selector(videoDidPlayToEnd:)];
|
||||
_delegateFlags.delegateDidTapVideoNode = [_delegate respondsToSelector:@selector(didTapVideoNode:)];
|
||||
_delegateFlags.delegateVideoNodeWillChangePlayerStateToState = [_delegate respondsToSelector:@selector(videoNode:willChangePlayerState:toState:)];
|
||||
_delegateFlags.delegateVideoNodeDidPlayToTimeInterval = [_delegate respondsToSelector:@selector(videoNode:didPlayToTimeInterval:)];
|
||||
_delegateFlags.delegateVideoNodeDidStartInitialLoading = [_delegate respondsToSelector:@selector(videoNodeDidStartInitialLoading:)];
|
||||
_delegateFlags.delegateVideoNodeDidFinishInitialLoading = [_delegate respondsToSelector:@selector(videoNodeDidFinishInitialLoading:)];
|
||||
_delegateFlags.delegateVideoNodeDidSetCurrentItem = [_delegate respondsToSelector:@selector(videoNode:didSetCurrentItem:)];
|
||||
_delegateFlags.delegateVideoNodeDidStallAtTimeInterval = [_delegate respondsToSelector:@selector(videoNode:didStallAtTimeInterval:)];
|
||||
_delegateFlags.delegateVideoNodeDidRecoverFromStall = [_delegate respondsToSelector:@selector(videoNodeDidRecoverFromStall:)];
|
||||
_delegateFlags.delegateVideNodeShouldChangePlayerStateTo = [delegate respondsToSelector:@selector(videoNode:shouldChangePlayerStateTo:)];
|
||||
_delegateFlags.delegateVideoDidPlayToEnd = [delegate respondsToSelector:@selector(videoDidPlayToEnd:)];
|
||||
_delegateFlags.delegateDidTapVideoNode = [delegate respondsToSelector:@selector(didTapVideoNode:)];
|
||||
_delegateFlags.delegateVideoNodeWillChangePlayerStateToState = [delegate respondsToSelector:@selector(videoNode:willChangePlayerState:toState:)];
|
||||
_delegateFlags.delegateVideoNodeDidPlayToTimeInterval = [delegate respondsToSelector:@selector(videoNode:didPlayToTimeInterval:)];
|
||||
_delegateFlags.delegateVideoNodeDidStartInitialLoading = [delegate respondsToSelector:@selector(videoNodeDidStartInitialLoading:)];
|
||||
_delegateFlags.delegateVideoNodeDidFinishInitialLoading = [delegate respondsToSelector:@selector(videoNodeDidFinishInitialLoading:)];
|
||||
_delegateFlags.delegateVideoNodeDidSetCurrentItem = [delegate respondsToSelector:@selector(videoNode:didSetCurrentItem:)];
|
||||
_delegateFlags.delegateVideoNodeDidStallAtTimeInterval = [delegate respondsToSelector:@selector(videoNode:didStallAtTimeInterval:)];
|
||||
_delegateFlags.delegateVideoNodeDidRecoverFromStall = [delegate respondsToSelector:@selector(videoNodeDidRecoverFromStall:)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -677,7 +676,7 @@ static NSString * const kRate = @"rate";
|
||||
- (BOOL)isStateChangeValid:(ASVideoNodePlayerState)state
|
||||
{
|
||||
if (_delegateFlags.delegateVideNodeShouldChangePlayerStateTo) {
|
||||
if (![_delegate videoNode:self shouldChangePlayerStateTo:state]) {
|
||||
if (![self.delegate videoNode:self shouldChangePlayerStateTo:state]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
@@ -704,7 +703,7 @@ static NSString * const kRate = @"rate";
|
||||
{
|
||||
self.playerState = ASVideoNodePlayerStateFinished;
|
||||
if (_delegateFlags.delegateVideoDidPlayToEnd) {
|
||||
[_delegate videoDidPlayToEnd:self];
|
||||
[self.delegate videoDidPlayToEnd:self];
|
||||
}
|
||||
|
||||
if (_shouldAutorepeat) {
|
||||
@@ -719,7 +718,7 @@ static NSString * const kRate = @"rate";
|
||||
{
|
||||
self.playerState = ASVideoNodePlayerStateLoading;
|
||||
if (_delegateFlags.delegateVideoNodeDidStallAtTimeInterval) {
|
||||
[_delegate videoNode:self didStallAtTimeInterval:CMTimeGetSeconds(_player.currentItem.currentTime)];
|
||||
[self.delegate videoNode:self didStallAtTimeInterval:CMTimeGetSeconds(_player.currentItem.currentTime)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
//! Defaults to 100
|
||||
@property (nonatomic, assign) int32_t periodicTimeObserverTimescale;
|
||||
//! Defaults to AVLayerVideoGravityResizeAspect
|
||||
@property (nonatomic) NSString *gravity;
|
||||
@property (nonatomic, copy) NSString *gravity;
|
||||
|
||||
- (instancetype)initWithUrl:(NSURL*)url;
|
||||
- (instancetype)initWithAsset:(AVAsset*)asset;
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
|
||||
#import <AsyncDisplayKit/ASLayout.h>
|
||||
#import <AsyncDisplayKit/ASDimension.h>
|
||||
#import <AsyncDisplayKit/ASDimensionInternal.h>
|
||||
#import <AsyncDisplayKit/ASDimensionDeprecated.h>
|
||||
#import <AsyncDisplayKit/ASEnvironment.h>
|
||||
#import <AsyncDisplayKit/ASLayoutElement.h>
|
||||
#import <AsyncDisplayKit/ASLayoutSpec.h>
|
||||
|
||||
@@ -76,12 +76,11 @@ extern NSString * const ASCollectionInvalidUpdateException;
|
||||
*/
|
||||
@protocol ASDataControllerDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
Called for batch update.
|
||||
*/
|
||||
- (void)dataControllerBeginUpdates:(ASDataController *)dataController;
|
||||
- (void)dataControllerWillDeleteAllData:(ASDataController *)dataController;
|
||||
- (void)dataController:(ASDataController *)dataController endUpdatesAnimated:(BOOL)animated completion:(void (^ _Nullable)(BOOL))completion;
|
||||
|
||||
/**
|
||||
|
||||
@@ -454,6 +454,7 @@ NSString * const ASCollectionInvalidUpdateException = @"ASCollectionInvalidUpdat
|
||||
// -beginUpdates
|
||||
[_mainSerialQueue performBlockOnMainThread:^{
|
||||
[_delegate dataControllerBeginUpdates:self];
|
||||
[_delegate dataControllerWillDeleteAllData:self];
|
||||
}];
|
||||
|
||||
// deleteSections:
|
||||
@@ -673,40 +674,7 @@ NSString * const ASCollectionInvalidUpdateException = @"ASCollectionInvalidUpdat
|
||||
|
||||
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
LOG(@"Edit Command - moveSection");
|
||||
|
||||
if (!_initialReloadDataHasBeenCalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableArray *rowContexts = _nodeContexts[ASDataControllerRowNodeKind];
|
||||
NSArray *contexts = rowContexts[section];
|
||||
[rowContexts removeObjectAtIndex:section];
|
||||
[rowContexts insertObject:contexts atIndex:section];
|
||||
|
||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
||||
[self willMoveSection:section toSection:newSection];
|
||||
|
||||
// remove elements
|
||||
|
||||
LOG(@"Edit Transaction - moveSection");
|
||||
NSMutableArray *editingRows = _editingNodes[ASDataControllerRowNodeKind];
|
||||
NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet(editingRows, [NSIndexSet indexSetWithIndex:section]);
|
||||
NSArray *nodes = ASFindElementsInMultidimensionalArrayAtIndexPaths(editingRows, indexPaths);
|
||||
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||
|
||||
// update the section of indexpaths
|
||||
NSMutableArray *updatedIndexPaths = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];
|
||||
for (NSIndexPath *indexPath in indexPaths) {
|
||||
NSIndexPath *updatedIndexPath = [NSIndexPath indexPathForItem:indexPath.item inSection:newSection];
|
||||
[updatedIndexPaths addObject:updatedIndexPath];
|
||||
}
|
||||
|
||||
// Don't re-calculate size for moving
|
||||
[self _insertNodes:nodes atIndexPaths:updatedIndexPaths withAnimationOptions:animationOptions];
|
||||
});
|
||||
ASDisplayNodeAssert(NO, @"ASDataController does not support %@. Call this on ASChangeSetDataController and the move will be processed along with the current batch of updates.", NSStringFromSelector(_cmd));
|
||||
}
|
||||
|
||||
|
||||
@@ -879,29 +847,7 @@ NSString * const ASCollectionInvalidUpdateException = @"ASCollectionInvalidUpdat
|
||||
|
||||
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
if (!_initialReloadDataHasBeenCalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableArray *contexts = _nodeContexts[ASDataControllerRowNodeKind];
|
||||
ASIndexedNodeContext *context = contexts[indexPath.section][indexPath.item];
|
||||
[contexts[indexPath.section] removeObjectAtIndex:indexPath.item];
|
||||
[contexts[newIndexPath.section] insertObject:context atIndex:newIndexPath.item];
|
||||
|
||||
LOG(@"Edit Command - moveRow: %@ > %@", indexPath, newIndexPath);
|
||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||
|
||||
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
||||
LOG(@"Edit Transaction - moveRow: %@ > %@", indexPath, newIndexPath);
|
||||
NSArray *indexPaths = @[indexPath];
|
||||
NSArray *nodes = ASFindElementsInMultidimensionalArrayAtIndexPaths(_editingNodes[ASDataControllerRowNodeKind], indexPaths);
|
||||
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||
|
||||
// Don't re-calculate size for moving
|
||||
NSArray *newIndexPaths = @[newIndexPath];
|
||||
[self _insertNodes:nodes atIndexPaths:newIndexPaths withAnimationOptions:animationOptions];
|
||||
});
|
||||
ASDisplayNodeAssert(NO, @"ASDataController does not support %@. Call this on ASChangeSetDataController and the move will be processed along with the current batch of updates.", NSStringFromSelector(_cmd));
|
||||
}
|
||||
|
||||
#pragma mark - Data Querying (Subclass API)
|
||||
@@ -953,6 +899,9 @@ NSString * const ASCollectionInvalidUpdateException = @"ASCollectionInvalidUpdat
|
||||
- (ASCellNode *)nodeAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
if (indexPath == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *contexts = _nodeContexts[ASDataControllerRowNodeKind];
|
||||
NSInteger section = indexPath.section;
|
||||
@@ -972,6 +921,9 @@ NSString * const ASCollectionInvalidUpdateException = @"ASCollectionInvalidUpdat
|
||||
- (ASCellNode *)nodeAtCompletedIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
if (indexPath == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *completedNodes = [self completedNodes];
|
||||
NSInteger section = indexPath.section;
|
||||
|
||||
@@ -59,17 +59,9 @@
|
||||
ASRangeTuningParameters tuningParameters = [self tuningParametersForRangeMode:rangeMode rangeType:rangeType];
|
||||
|
||||
if (_layoutDirection == ASFlowLayoutDirectionHorizontal) {
|
||||
ASDisplayNodeAssert(scrollDirection == ASScrollDirectionNone ||
|
||||
scrollDirection == ASScrollDirectionLeft ||
|
||||
scrollDirection == ASScrollDirectionRight, @"Invalid scroll direction");
|
||||
|
||||
viewportDirectionalSize = viewportSize.width;
|
||||
directionalBuffer = ASDirectionalScreenfulBufferHorizontal(scrollDirection, tuningParameters);
|
||||
} else {
|
||||
ASDisplayNodeAssert(scrollDirection == ASScrollDirectionNone ||
|
||||
scrollDirection == ASScrollDirectionUp ||
|
||||
scrollDirection == ASScrollDirectionDown, @"Invalid scroll direction");
|
||||
|
||||
viewportDirectionalSize = viewportSize.height;
|
||||
directionalBuffer = ASDirectionalScreenfulBufferVertical(scrollDirection, tuningParameters);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,12 @@
|
||||
BOOL _didRegisterForNodeDisplayNotifications;
|
||||
CFTimeInterval _pendingDisplayNodesTimestamp;
|
||||
|
||||
// If the user is not currently scrolling, we will keep our ranges
|
||||
// configured to match their previous scroll direction. Defaults
|
||||
// to [.right, .down] so that when the user first opens a screen
|
||||
// the ranges point down into the content.
|
||||
ASScrollDirection _previousScrollDirection;
|
||||
|
||||
#if AS_RANGECONTROLLER_LOG_UPDATE_FREQ
|
||||
NSUInteger _updateCountThisFrame;
|
||||
CADisplayLink *_displayLink;
|
||||
@@ -65,6 +71,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
_rangeIsValid = YES;
|
||||
_currentRangeMode = ASLayoutRangeModeInvalid;
|
||||
_preserveCurrentRangeMode = NO;
|
||||
_previousScrollDirection = ASScrollDirectionDown | ASScrollDirectionRight;
|
||||
|
||||
[[[self class] allRangeControllersWeakSet] addObject:self];
|
||||
|
||||
@@ -216,7 +223,13 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
}
|
||||
ASProfilingSignpostStart(1, self);
|
||||
|
||||
// Get the scroll direction. Default to using the previous one, if they're not scrolling.
|
||||
ASScrollDirection scrollDirection = [_dataSource scrollDirectionForRangeController:self];
|
||||
if (scrollDirection == ASScrollDirectionNone) {
|
||||
scrollDirection = _previousScrollDirection;
|
||||
}
|
||||
_previousScrollDirection = scrollDirection;
|
||||
|
||||
if (_layoutControllerImplementsSetViewportSize) {
|
||||
[_layoutController setViewportSize:[_dataSource viewportSizeForRangeController:self]];
|
||||
}
|
||||
@@ -478,6 +491,11 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
||||
[_delegate didBeginUpdatesInRangeController:self];
|
||||
}
|
||||
|
||||
- (void)dataControllerWillDeleteAllData:(ASDataController *)dataController
|
||||
{
|
||||
[self _setVisibleNodes:nil];
|
||||
}
|
||||
|
||||
- (void)dataController:(ASDataController *)dataController endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
|
||||
@class ASDisplayNode;
|
||||
@protocol _ASDisplayLayerDelegate;
|
||||
@@ -103,7 +104,7 @@ typedef BOOL(^asdisplaynode_iscancelled_block_t)(void);
|
||||
@param isCancelledBlock Execute this block to check whether the current drawing operation has been cancelled to avoid unnecessary work. A return value of YES means cancel drawing and return.
|
||||
@param isRasterizing YES if the layer is being rasterized into another layer, in which case drawRect: probably wants to avoid doing things like filling its bounds with a zero-alpha color to clear the backing store.
|
||||
*/
|
||||
+ (void)drawRect:(CGRect)bounds withParameters:(id<NSObject>)parameters isCancelled:(__attribute((noescape)) asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing;
|
||||
+ (void)drawRect:(CGRect)bounds withParameters:(id<NSObject>)parameters isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing;
|
||||
|
||||
/**
|
||||
@summary Delegate override to provide new layer contents as a UIImage.
|
||||
@@ -111,19 +112,19 @@ typedef BOOL(^asdisplaynode_iscancelled_block_t)(void);
|
||||
@param isCancelledBlock Execute this block to check whether the current drawing operation has been cancelled to avoid unnecessary work. A return value of YES means cancel drawing and return.
|
||||
@return A UIImage with contents that are ready to display on the main thread. Make sure that the image is already decoded before returning it here.
|
||||
*/
|
||||
+ (UIImage *)displayWithParameters:(id<NSObject>)parameters isCancelled:(__attribute((noescape)) asdisplaynode_iscancelled_block_t)isCancelledBlock;
|
||||
+ (UIImage *)displayWithParameters:(id<NSObject>)parameters isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock;
|
||||
|
||||
/**
|
||||
* @abstract instance version of drawRect class method
|
||||
* @see drawRect:withParameters:isCancelled:isRasterizing class method
|
||||
*/
|
||||
- (void)drawRect:(CGRect)bounds withParameters:(id <NSObject>)parameters isCancelled:(__attribute((noescape)) asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing;
|
||||
- (void)drawRect:(CGRect)bounds withParameters:(id <NSObject>)parameters isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelledBlock isRasterizing:(BOOL)isRasterizing;
|
||||
|
||||
/**
|
||||
* @abstract instance version of display class method
|
||||
* @see displayWithParameters:isCancelled class method
|
||||
*/
|
||||
- (UIImage *)displayWithParameters:(id <NSObject>)parameters isCancelled:(__attribute((noescape)) asdisplaynode_iscancelled_block_t)isCancelled;
|
||||
- (UIImage *)displayWithParameters:(id <NSObject>)parameters isCancelled:(AS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelled;
|
||||
|
||||
// Called on the main thread only
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
#import <AsyncDisplayKit/ASDimension.h>
|
||||
#import <AsyncDisplayKit/ASDimensionDeprecated.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
#import <AsyncDisplayKit/ASAssert.h>
|
||||
|
||||
ASDISPLAYNODE_EXTERN_C_BEGIN
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma mark -
|
||||
|
||||
ASDISPLAYNODE_INLINE BOOL AS_WARN_UNUSED_RESULT ASPointsValidForLayout(CGFloat points)
|
||||
{
|
||||
return ((isnormal(points) || points == 0.0) && points >= 0.0 && points < (CGFLOAT_MAX / 2.0));
|
||||
@@ -33,6 +38,8 @@ ASDISPLAYNODE_INLINE BOOL AS_WARN_UNUSED_RESULT ASIsCGSizeValidForSize(CGSize si
|
||||
return (ASPointsValidForSize(size.width) && ASPointsValidForSize(size.height));
|
||||
}
|
||||
|
||||
#pragma mark - ASDimension
|
||||
|
||||
/**
|
||||
* A dimension relative to constraints to be provided in the future.
|
||||
* A ASDimension can be one of three types:
|
||||
@@ -58,42 +65,10 @@ typedef struct {
|
||||
} ASDimension;
|
||||
|
||||
/**
|
||||
* Expresses an inclusive range of sizes. Used to provide a simple constraint to layout.
|
||||
* Represents auto as ASDimension
|
||||
*/
|
||||
typedef struct {
|
||||
CGSize min;
|
||||
CGSize max;
|
||||
} ASSizeRange;
|
||||
|
||||
/**
|
||||
* A struct specifying a ASLayoutElement's size. Example:
|
||||
*
|
||||
* ASLayoutElementSize size = (ASLayoutElementSize){
|
||||
* .width = ASDimensionMakeWithFraction(0.25),
|
||||
* .maxWidth = ASDimensionMakeWithPoints(200),
|
||||
* .minHeight = ASDimensionMakeWithFraction(0.50)
|
||||
* };
|
||||
*
|
||||
* Description: <ASLayoutElementSize: exact={25%, Auto}, min={Auto, 50%}, max={200pt, Auto}>
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
ASDimension width;
|
||||
ASDimension height;
|
||||
ASDimension minWidth;
|
||||
ASDimension maxWidth;
|
||||
ASDimension minHeight;
|
||||
ASDimension maxHeight;
|
||||
} ASLayoutElementSize;
|
||||
|
||||
extern ASDimension const ASDimensionAuto;
|
||||
|
||||
ASDISPLAYNODE_EXTERN_C_BEGIN
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
#pragma mark - ASDimension
|
||||
|
||||
/**
|
||||
* Returns a dimension with the specified type and value.
|
||||
*/
|
||||
@@ -173,15 +148,6 @@ ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT CGFloat ASDimensionResolve(ASDimensio
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - NSNumber+ASDimension
|
||||
|
||||
@interface NSNumber (ASDimension)
|
||||
@property (nonatomic, readonly) ASDimension as_pointDimension;
|
||||
@property (nonatomic, readonly) ASDimension as_fractionDimension;
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - ASLayoutSize
|
||||
|
||||
/**
|
||||
@@ -205,6 +171,15 @@ ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT ASLayoutSize ASLayoutSizeMake(ASDimen
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve this relative size relative to a parent size.
|
||||
*/
|
||||
ASDISPLAYNODE_INLINE CGSize ASLayoutSizeResolveSize(ASLayoutSize layoutSize, CGSize parentSize, CGSize autoSize)
|
||||
{
|
||||
return CGSizeMake(ASDimensionResolve(layoutSize.width, parentSize.width, autoSize.width),
|
||||
ASDimensionResolve(layoutSize.height, parentSize.height, autoSize.height));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a string representation of a relative size.
|
||||
*/
|
||||
@@ -217,6 +192,14 @@ ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT NSString *NSStringFromASLayoutSize(AS
|
||||
|
||||
#pragma mark - ASSizeRange
|
||||
|
||||
/**
|
||||
* Expresses an inclusive range of sizes. Used to provide a simple constraint to layout.
|
||||
*/
|
||||
typedef struct {
|
||||
CGSize min;
|
||||
CGSize max;
|
||||
} ASSizeRange;
|
||||
|
||||
/**
|
||||
* Creates an ASSizeRange with provided min and max size.
|
||||
*/
|
||||
@@ -272,149 +255,5 @@ ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT BOOL ASSizeRangeEqualToSizeRange(ASSi
|
||||
*/
|
||||
extern AS_WARN_UNUSED_RESULT NSString *NSStringFromASSizeRange(ASSizeRange sizeRange);
|
||||
|
||||
|
||||
#pragma mark - ASLayoutElementSize
|
||||
|
||||
/**
|
||||
* Returns an ASLayoutElementSize with default values.
|
||||
*/
|
||||
ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT ASLayoutElementSize ASLayoutElementSizeMake()
|
||||
{
|
||||
return (ASLayoutElementSize){
|
||||
.width = ASDimensionAuto,
|
||||
.height = ASDimensionAuto,
|
||||
.minWidth = ASDimensionAuto,
|
||||
.maxWidth = ASDimensionAuto,
|
||||
.minHeight = ASDimensionAuto,
|
||||
.maxHeight = ASDimensionAuto
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ASLayoutElementSize with the specified CGSize values as width and height.
|
||||
*/
|
||||
ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT ASLayoutElementSize ASLayoutElementSizeMakeFromCGSize(CGSize size)
|
||||
{
|
||||
ASLayoutElementSize s = ASLayoutElementSizeMake();
|
||||
s.width = ASDimensionMakeWithPoints(size.width);
|
||||
s.height = ASDimensionMakeWithPoints(size.height);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether two sizes are equal.
|
||||
*/
|
||||
ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT BOOL ASLayoutElementSizeEqualToLayoutElementSize(ASLayoutElementSize lhs, ASLayoutElementSize rhs)
|
||||
{
|
||||
return (ASDimensionEqualToDimension(lhs.width, rhs.width)
|
||||
&& ASDimensionEqualToDimension(lhs.height, rhs.height)
|
||||
&& ASDimensionEqualToDimension(lhs.minWidth, rhs.minWidth)
|
||||
&& ASDimensionEqualToDimension(lhs.maxWidth, rhs.maxWidth)
|
||||
&& ASDimensionEqualToDimension(lhs.minHeight, rhs.minHeight)
|
||||
&& ASDimensionEqualToDimension(lhs.maxHeight, rhs.maxHeight));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string formatted to contain the data from an ASLayoutElementSize.
|
||||
*/
|
||||
extern AS_WARN_UNUSED_RESULT NSString *NSStringFromASLayoutElementSize(ASLayoutElementSize size);
|
||||
|
||||
/**
|
||||
* Resolve the given size relative to a parent size and an auto size.
|
||||
* From the given size uses width, height to resolve the exact size constraint, uses the minHeight and minWidth to
|
||||
* resolve the min size constraint and the maxHeight and maxWidth to resolve the max size constraint. For every
|
||||
* dimension with unit ASDimensionUnitAuto the given autoASSizeRange value will be used.
|
||||
* Based on the calculated exact, min and max size constraints the final size range will be calculated.
|
||||
*/
|
||||
extern AS_WARN_UNUSED_RESULT ASSizeRange ASLayoutElementSizeResolveAutoSize(ASLayoutElementSize size, const CGSize parentSize, ASSizeRange autoASSizeRange);
|
||||
|
||||
/**
|
||||
* Resolve the given size to a parent size. Uses internally ASLayoutElementSizeResolveAutoSize with {INFINITY, INFINITY} as
|
||||
* as autoASSizeRange. For more information look at ASLayoutElementSizeResolveAutoSize.
|
||||
*/
|
||||
ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT ASSizeRange ASLayoutElementSizeResolve(ASLayoutElementSize size, const CGSize parentSize)
|
||||
{
|
||||
return ASLayoutElementSizeResolveAutoSize(size, parentSize, ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY)));
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Deprecated
|
||||
|
||||
/**
|
||||
* A dimension relative to constraints to be provided in the future.
|
||||
* A ASDimension can be one of three types:
|
||||
*
|
||||
* "Auto" - This indicated "I have no opinion" and may be resolved in whatever way makes most sense given the circumstances.
|
||||
*
|
||||
* "Points" - Just a number. It will always resolve to exactly this amount.
|
||||
*
|
||||
* "Percent" - Multiplied to a provided parent amount to resolve a final amount.
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, ASRelativeDimensionType) {
|
||||
/** This indicates "I have no opinion" and may be resolved in whatever way makes most sense given the circumstances. */
|
||||
ASRelativeDimensionTypeAuto,
|
||||
/** Just a number. It will always resolve to exactly this amount. This is the default type. */
|
||||
ASRelativeDimensionTypePoints,
|
||||
/** Multiplied to a provided parent amount to resolve a final amount. */
|
||||
ASRelativeDimensionTypeFraction,
|
||||
};
|
||||
|
||||
#define ASRelativeDimension ASDimension
|
||||
#define ASRelativeSize ASLayoutSize
|
||||
#define ASRelativeDimensionMakeWithPoints ASDimensionMakeWithPoints
|
||||
#define ASRelativeDimensionMakeWithFraction ASDimensionMakeWithFraction
|
||||
|
||||
/**
|
||||
* Function is deprecated. Use ASSizeRangeMake instead.
|
||||
*/
|
||||
extern AS_WARN_UNUSED_RESULT ASSizeRange ASSizeRangeMakeExactSize(CGSize size) ASDISPLAYNODE_DEPRECATED_MSG("Use ASSizeRangeMake instead.");
|
||||
|
||||
/**
|
||||
Expresses an inclusive range of relative sizes. Used to provide additional constraint to layout.
|
||||
Used by ASStaticLayoutSpec.
|
||||
*/
|
||||
typedef struct {
|
||||
ASLayoutSize min;
|
||||
ASLayoutSize max;
|
||||
} ASRelativeSizeRange;
|
||||
|
||||
extern ASRelativeSizeRange const ASRelativeSizeRangeUnconstrained;
|
||||
|
||||
#pragma mark - ASRelativeDimension
|
||||
|
||||
extern ASDimension ASRelativeDimensionMake(ASRelativeDimensionType type, CGFloat value) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
#pragma mark - ASRelativeSize
|
||||
|
||||
extern ASLayoutSize ASRelativeSizeMake(ASRelativeDimension width, ASRelativeDimension height) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
/** Convenience constructor to provide size in points. */
|
||||
extern ASLayoutSize ASRelativeSizeMakeWithCGSize(CGSize size) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
/** Convenience constructor to provide size as a fraction. */
|
||||
extern ASLayoutSize ASRelativeSizeMakeWithFraction(CGFloat fraction) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern BOOL ASRelativeSizeEqualToRelativeSize(ASLayoutSize lhs, ASLayoutSize rhs) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern NSString *NSStringFromASRelativeSize(ASLayoutSize size) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
#pragma mark - ASRelativeSizeRange
|
||||
|
||||
extern ASRelativeSizeRange ASRelativeSizeRangeMake(ASLayoutSize min, ASLayoutSize max) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
#pragma mark Convenience constructors to provide an exact size (min == max).
|
||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeSize(ASLayoutSize exact) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactCGSize(CGSize exact) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactFraction(CGFloat fraction) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimension exactWidth, ASRelativeDimension exactHeight) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern BOOL ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRange lhs, ASRelativeSizeRange rhs) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
/** Provided a parent size, compute final dimensions for this RelativeSizeRange to arrive at a SizeRange. */
|
||||
extern ASSizeRange ASRelativeSizeRangeResolve(ASRelativeSizeRange relativeSizeRange, CGSize parentSize) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
ASDISPLAYNODE_EXTERN_C_END
|
||||
|
||||
@@ -52,91 +52,10 @@ NSString *NSStringFromASDimension(ASDimension dimension)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - NSNumber+ASDimension
|
||||
|
||||
@implementation NSNumber (ASDimension)
|
||||
|
||||
- (ASDimension)as_pointDimension
|
||||
{
|
||||
return ASDimensionMake(ASDimensionUnitPoints, ASCGFloatFromNumber(self));
|
||||
}
|
||||
|
||||
- (ASDimension)as_fractionDimension
|
||||
{
|
||||
return ASDimensionMake(ASDimensionUnitFraction, ASCGFloatFromNumber(self));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - ASLayoutSize
|
||||
|
||||
ASLayoutSize const ASLayoutSizeAuto = {ASDimensionAuto, ASDimensionAuto};
|
||||
|
||||
// ** Resolve this relative size relative to a parent size. */
|
||||
ASDISPLAYNODE_INLINE CGSize ASLayoutSizeResolveSize(ASLayoutSize layoutSize, CGSize parentSize, CGSize autoSize)
|
||||
{
|
||||
return CGSizeMake(ASDimensionResolve(layoutSize.width, parentSize.width, autoSize.width),
|
||||
ASDimensionResolve(layoutSize.height, parentSize.height, autoSize.height));
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - ASLayoutElementSize
|
||||
|
||||
NSString *NSStringFromASLayoutElementSize(ASLayoutElementSize size)
|
||||
{
|
||||
return [NSString stringWithFormat:
|
||||
@"<ASLayoutElementSize: exact=%@, min=%@, max=%@>",
|
||||
NSStringFromASLayoutSize(ASLayoutSizeMake(size.width, size.height)),
|
||||
NSStringFromASLayoutSize(ASLayoutSizeMake(size.minWidth, size.minHeight)),
|
||||
NSStringFromASLayoutSize(ASLayoutSizeMake(size.maxWidth, size.maxHeight))];
|
||||
}
|
||||
|
||||
ASDISPLAYNODE_INLINE void ASLayoutElementSizeConstrain(CGFloat minVal, CGFloat exactVal, CGFloat maxVal, CGFloat *outMin, CGFloat *outMax)
|
||||
{
|
||||
NSCAssert(!isnan(minVal), @"minVal must not be NaN");
|
||||
NSCAssert(!isnan(maxVal), @"maxVal must not be NaN");
|
||||
// Avoid use of min/max primitives since they're harder to reason
|
||||
// about in the presence of NaN (in exactVal)
|
||||
// Follow CSS: min overrides max overrides exact.
|
||||
|
||||
// Begin with the min/max range
|
||||
*outMin = minVal;
|
||||
*outMax = maxVal;
|
||||
if (maxVal <= minVal) {
|
||||
// min overrides max and exactVal is irrelevant
|
||||
*outMax = minVal;
|
||||
return;
|
||||
}
|
||||
if (isnan(exactVal)) {
|
||||
// no exact value, so leave as a min/max range
|
||||
return;
|
||||
}
|
||||
if (exactVal > maxVal) {
|
||||
// clip to max value
|
||||
*outMin = maxVal;
|
||||
} else if (exactVal < minVal) {
|
||||
// clip to min value
|
||||
*outMax = minVal;
|
||||
} else {
|
||||
// use exact value
|
||||
*outMin = *outMax = exactVal;
|
||||
}
|
||||
}
|
||||
|
||||
ASSizeRange ASLayoutElementSizeResolveAutoSize(ASLayoutElementSize size, const CGSize parentSize, ASSizeRange autoASSizeRange)
|
||||
{
|
||||
CGSize resolvedExact = ASLayoutSizeResolveSize(ASLayoutSizeMake(size.width, size.height), parentSize, {NAN, NAN});
|
||||
CGSize resolvedMin = ASLayoutSizeResolveSize(ASLayoutSizeMake(size.minWidth, size.minHeight), parentSize, autoASSizeRange.min);
|
||||
CGSize resolvedMax = ASLayoutSizeResolveSize(ASLayoutSizeMake(size.maxWidth, size.maxHeight), parentSize, autoASSizeRange.max);
|
||||
|
||||
CGSize rangeMin, rangeMax;
|
||||
ASLayoutElementSizeConstrain(resolvedMin.width, resolvedExact.width, resolvedMax.width, &rangeMin.width, &rangeMax.width);
|
||||
ASLayoutElementSizeConstrain(resolvedMin.height, resolvedExact.height, resolvedMax.height, &rangeMin.height, &rangeMax.height);
|
||||
return {rangeMin, rangeMax};
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - ASSizeRange
|
||||
|
||||
@@ -178,90 +97,3 @@ NSString *NSStringFromASSizeRange(ASSizeRange sizeRange)
|
||||
NSStringFromCGSize(sizeRange.min),
|
||||
NSStringFromCGSize(sizeRange.max)];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Deprecated
|
||||
|
||||
ASDimension ASRelativeDimensionMake(ASRelativeDimensionType type, CGFloat value)
|
||||
{
|
||||
if (type == ASRelativeDimensionTypePoints) {
|
||||
return ASDimensionMakeWithPoints(value);
|
||||
} else if (type == ASRelativeDimensionTypeFraction) {
|
||||
return ASDimensionMakeWithFraction(value);
|
||||
}
|
||||
|
||||
ASDisplayNodeCAssert(NO, @"ASRelativeDimensionMake does not support the given ASRelativeDimensionType");
|
||||
return ASDimensionMakeWithPoints(0);
|
||||
}
|
||||
|
||||
ASSizeRange ASSizeRangeMakeExactSize(CGSize size)
|
||||
{
|
||||
return ASSizeRangeMake(size);
|
||||
}
|
||||
|
||||
ASRelativeSizeRange const ASRelativeSizeRangeUnconstrained = {};
|
||||
|
||||
#pragma mark - ASRelativeSize
|
||||
|
||||
ASLayoutSize ASRelativeSizeMake(ASRelativeDimension width, ASRelativeDimension height)
|
||||
{
|
||||
return ASLayoutSizeMake(width, height);
|
||||
}
|
||||
|
||||
ASLayoutSize ASRelativeSizeMakeWithCGSize(CGSize size)
|
||||
{
|
||||
return ASRelativeSizeMake(ASRelativeDimensionMakeWithPoints(size.width),
|
||||
ASRelativeDimensionMakeWithPoints(size.height));
|
||||
}
|
||||
|
||||
ASLayoutSize ASRelativeSizeMakeWithFraction(CGFloat fraction)
|
||||
{
|
||||
return ASRelativeSizeMake(ASRelativeDimensionMakeWithFraction(fraction),
|
||||
ASRelativeDimensionMakeWithFraction(fraction));
|
||||
}
|
||||
|
||||
BOOL ASRelativeSizeEqualToRelativeSize(ASLayoutSize lhs, ASLayoutSize rhs)
|
||||
{
|
||||
return ASDimensionEqualToDimension(lhs.width, rhs.width)
|
||||
&& ASDimensionEqualToDimension(lhs.height, rhs.height);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - ASRelativeSizeRange
|
||||
|
||||
ASRelativeSizeRange ASRelativeSizeRangeMake(ASLayoutSize min, ASLayoutSize max)
|
||||
{
|
||||
ASRelativeSizeRange sizeRange; sizeRange.min = min; sizeRange.max = max; return sizeRange;
|
||||
}
|
||||
|
||||
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeSize(ASLayoutSize exact)
|
||||
{
|
||||
return ASRelativeSizeRangeMake(exact, exact);
|
||||
}
|
||||
|
||||
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactCGSize(CGSize exact)
|
||||
{
|
||||
return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMakeWithCGSize(exact));
|
||||
}
|
||||
|
||||
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactFraction(CGFloat fraction)
|
||||
{
|
||||
return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMakeWithFraction(fraction));
|
||||
}
|
||||
|
||||
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimension exactWidth, ASRelativeDimension exactHeight)
|
||||
{
|
||||
return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMake(exactWidth, exactHeight));
|
||||
}
|
||||
|
||||
BOOL ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRange lhs, ASRelativeSizeRange rhs)
|
||||
{
|
||||
return ASRelativeSizeEqualToRelativeSize(lhs.min, rhs.min) && ASRelativeSizeEqualToRelativeSize(lhs.max, rhs.max);
|
||||
}
|
||||
|
||||
ASSizeRange ASRelativeSizeRangeResolve(ASRelativeSizeRange relativeSizeRange,
|
||||
CGSize parentSize)
|
||||
{
|
||||
return ASSizeRangeMake(ASLayoutSizeResolveSize(relativeSizeRange.min, parentSize, parentSize),
|
||||
ASLayoutSizeResolveSize(relativeSizeRange.max, parentSize, parentSize));
|
||||
}
|
||||
|
||||
95
AsyncDisplayKit/Layout/ASDimensionDeprecated.h
Normal file
95
AsyncDisplayKit/Layout/ASDimensionDeprecated.h
Normal file
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// ASDimensionDeprecated.h
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
#import <AsyncDisplayKit/ASDimension.h>
|
||||
|
||||
ASDISPLAYNODE_EXTERN_C_BEGIN
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* A dimension relative to constraints to be provided in the future.
|
||||
* A ASDimension can be one of three types:
|
||||
*
|
||||
* "Auto" - This indicated "I have no opinion" and may be resolved in whatever way makes most sense given the circumstances.
|
||||
*
|
||||
* "Points" - Just a number. It will always resolve to exactly this amount.
|
||||
*
|
||||
* "Percent" - Multiplied to a provided parent amount to resolve a final amount.
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, ASRelativeDimensionType) {
|
||||
/** This indicates "I have no opinion" and may be resolved in whatever way makes most sense given the circumstances. */
|
||||
ASRelativeDimensionTypeAuto,
|
||||
/** Just a number. It will always resolve to exactly this amount. This is the default type. */
|
||||
ASRelativeDimensionTypePoints,
|
||||
/** Multiplied to a provided parent amount to resolve a final amount. */
|
||||
ASRelativeDimensionTypeFraction,
|
||||
};
|
||||
|
||||
#define ASRelativeDimension ASDimension
|
||||
#define ASRelativeSize ASLayoutSize
|
||||
#define ASRelativeDimensionMakeWithPoints ASDimensionMakeWithPoints
|
||||
#define ASRelativeDimensionMakeWithFraction ASDimensionMakeWithFraction
|
||||
|
||||
/**
|
||||
* Function is deprecated. Use ASSizeRangeMake instead.
|
||||
*/
|
||||
extern AS_WARN_UNUSED_RESULT ASSizeRange ASSizeRangeMakeExactSize(CGSize size) ASDISPLAYNODE_DEPRECATED_MSG("Use ASSizeRangeMake instead.");
|
||||
|
||||
/**
|
||||
Expresses an inclusive range of relative sizes. Used to provide additional constraint to layout.
|
||||
Used by ASStaticLayoutSpec.
|
||||
*/
|
||||
typedef struct {
|
||||
ASLayoutSize min;
|
||||
ASLayoutSize max;
|
||||
} ASRelativeSizeRange;
|
||||
|
||||
extern ASRelativeSizeRange const ASRelativeSizeRangeUnconstrained;
|
||||
|
||||
#pragma mark - ASRelativeDimension
|
||||
|
||||
extern ASDimension ASRelativeDimensionMake(ASRelativeDimensionType type, CGFloat value) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
#pragma mark - ASRelativeSize
|
||||
|
||||
extern ASLayoutSize ASRelativeSizeMake(ASRelativeDimension width, ASRelativeDimension height) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
/** Convenience constructor to provide size in points. */
|
||||
extern ASLayoutSize ASRelativeSizeMakeWithCGSize(CGSize size) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
/** Convenience constructor to provide size as a fraction. */
|
||||
extern ASLayoutSize ASRelativeSizeMakeWithFraction(CGFloat fraction) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern BOOL ASRelativeSizeEqualToRelativeSize(ASLayoutSize lhs, ASLayoutSize rhs) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern NSString *NSStringFromASRelativeSize(ASLayoutSize size) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
#pragma mark - ASRelativeSizeRange
|
||||
|
||||
extern ASRelativeSizeRange ASRelativeSizeRangeMake(ASLayoutSize min, ASLayoutSize max) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
#pragma mark Convenience constructors to provide an exact size (min == max).
|
||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeSize(ASLayoutSize exact) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactCGSize(CGSize exact) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactFraction(CGFloat fraction) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimension exactWidth, ASRelativeDimension exactHeight) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
extern BOOL ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRange lhs, ASRelativeSizeRange rhs) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
/** Provided a parent size, compute final dimensions for this RelativeSizeRange to arrive at a SizeRange. */
|
||||
extern ASSizeRange ASRelativeSizeRangeResolve(ASRelativeSizeRange relativeSizeRange, CGSize parentSize) ASDISPLAYNODE_DEPRECATED;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
ASDISPLAYNODE_EXTERN_C_END
|
||||
95
AsyncDisplayKit/Layout/ASDimensionDeprecated.mm
Normal file
95
AsyncDisplayKit/Layout/ASDimensionDeprecated.mm
Normal file
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// ASDimensionDeprecated.mm
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
|
||||
#import "ASDimensionDeprecated.h"
|
||||
|
||||
ASDimension ASRelativeDimensionMake(ASRelativeDimensionType type, CGFloat value)
|
||||
{
|
||||
if (type == ASRelativeDimensionTypePoints) {
|
||||
return ASDimensionMakeWithPoints(value);
|
||||
} else if (type == ASRelativeDimensionTypeFraction) {
|
||||
return ASDimensionMakeWithFraction(value);
|
||||
}
|
||||
|
||||
ASDisplayNodeCAssert(NO, @"ASRelativeDimensionMake does not support the given ASRelativeDimensionType");
|
||||
return ASDimensionMakeWithPoints(0);
|
||||
}
|
||||
|
||||
ASSizeRange ASSizeRangeMakeExactSize(CGSize size)
|
||||
{
|
||||
return ASSizeRangeMake(size);
|
||||
}
|
||||
|
||||
ASRelativeSizeRange const ASRelativeSizeRangeUnconstrained = {};
|
||||
|
||||
#pragma mark - ASRelativeSize
|
||||
|
||||
ASLayoutSize ASRelativeSizeMake(ASRelativeDimension width, ASRelativeDimension height)
|
||||
{
|
||||
return ASLayoutSizeMake(width, height);
|
||||
}
|
||||
|
||||
ASLayoutSize ASRelativeSizeMakeWithCGSize(CGSize size)
|
||||
{
|
||||
return ASRelativeSizeMake(ASRelativeDimensionMakeWithPoints(size.width),
|
||||
ASRelativeDimensionMakeWithPoints(size.height));
|
||||
}
|
||||
|
||||
ASLayoutSize ASRelativeSizeMakeWithFraction(CGFloat fraction)
|
||||
{
|
||||
return ASRelativeSizeMake(ASRelativeDimensionMakeWithFraction(fraction),
|
||||
ASRelativeDimensionMakeWithFraction(fraction));
|
||||
}
|
||||
|
||||
BOOL ASRelativeSizeEqualToRelativeSize(ASLayoutSize lhs, ASLayoutSize rhs)
|
||||
{
|
||||
return ASDimensionEqualToDimension(lhs.width, rhs.width)
|
||||
&& ASDimensionEqualToDimension(lhs.height, rhs.height);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - ASRelativeSizeRange
|
||||
|
||||
ASRelativeSizeRange ASRelativeSizeRangeMake(ASLayoutSize min, ASLayoutSize max)
|
||||
{
|
||||
ASRelativeSizeRange sizeRange; sizeRange.min = min; sizeRange.max = max; return sizeRange;
|
||||
}
|
||||
|
||||
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeSize(ASLayoutSize exact)
|
||||
{
|
||||
return ASRelativeSizeRangeMake(exact, exact);
|
||||
}
|
||||
|
||||
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactCGSize(CGSize exact)
|
||||
{
|
||||
return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMakeWithCGSize(exact));
|
||||
}
|
||||
|
||||
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactFraction(CGFloat fraction)
|
||||
{
|
||||
return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMakeWithFraction(fraction));
|
||||
}
|
||||
|
||||
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimension exactWidth, ASRelativeDimension exactHeight)
|
||||
{
|
||||
return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMake(exactWidth, exactHeight));
|
||||
}
|
||||
|
||||
BOOL ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRange lhs, ASRelativeSizeRange rhs)
|
||||
{
|
||||
return ASRelativeSizeEqualToRelativeSize(lhs.min, rhs.min) && ASRelativeSizeEqualToRelativeSize(lhs.max, rhs.max);
|
||||
}
|
||||
|
||||
ASSizeRange ASRelativeSizeRangeResolve(ASRelativeSizeRange relativeSizeRange,
|
||||
CGSize parentSize)
|
||||
{
|
||||
return ASSizeRangeMake(ASLayoutSizeResolveSize(relativeSizeRange.min, parentSize, parentSize),
|
||||
ASLayoutSizeResolveSize(relativeSizeRange.max, parentSize, parentSize));
|
||||
}
|
||||
105
AsyncDisplayKit/Layout/ASDimensionInternal.h
Normal file
105
AsyncDisplayKit/Layout/ASDimensionInternal.h
Normal file
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// ASDimensionInternal.h
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
#import <AsyncDisplayKit/ASDimension.h>
|
||||
|
||||
ASDISPLAYNODE_EXTERN_C_BEGIN
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma mark - ASLayoutElementSize
|
||||
|
||||
/**
|
||||
* A struct specifying a ASLayoutElement's size. Example:
|
||||
*
|
||||
* ASLayoutElementSize size = (ASLayoutElementSize){
|
||||
* .width = ASDimensionMakeWithFraction(0.25),
|
||||
* .maxWidth = ASDimensionMakeWithPoints(200),
|
||||
* .minHeight = ASDimensionMakeWithFraction(0.50)
|
||||
* };
|
||||
*
|
||||
* Description: <ASLayoutElementSize: exact={25%, Auto}, min={Auto, 50%}, max={200pt, Auto}>
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
ASDimension width;
|
||||
ASDimension height;
|
||||
ASDimension minWidth;
|
||||
ASDimension maxWidth;
|
||||
ASDimension minHeight;
|
||||
ASDimension maxHeight;
|
||||
} ASLayoutElementSize;
|
||||
|
||||
/**
|
||||
* Returns an ASLayoutElementSize with default values.
|
||||
*/
|
||||
ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT ASLayoutElementSize ASLayoutElementSizeMake()
|
||||
{
|
||||
return (ASLayoutElementSize){
|
||||
.width = ASDimensionAuto,
|
||||
.height = ASDimensionAuto,
|
||||
.minWidth = ASDimensionAuto,
|
||||
.maxWidth = ASDimensionAuto,
|
||||
.minHeight = ASDimensionAuto,
|
||||
.maxHeight = ASDimensionAuto
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ASLayoutElementSize with the specified CGSize values as width and height.
|
||||
*/
|
||||
ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT ASLayoutElementSize ASLayoutElementSizeMakeFromCGSize(CGSize size)
|
||||
{
|
||||
ASLayoutElementSize s = ASLayoutElementSizeMake();
|
||||
s.width = ASDimensionMakeWithPoints(size.width);
|
||||
s.height = ASDimensionMakeWithPoints(size.height);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether two sizes are equal.
|
||||
*/
|
||||
ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT BOOL ASLayoutElementSizeEqualToLayoutElementSize(ASLayoutElementSize lhs, ASLayoutElementSize rhs)
|
||||
{
|
||||
return (ASDimensionEqualToDimension(lhs.width, rhs.width)
|
||||
&& ASDimensionEqualToDimension(lhs.height, rhs.height)
|
||||
&& ASDimensionEqualToDimension(lhs.minWidth, rhs.minWidth)
|
||||
&& ASDimensionEqualToDimension(lhs.maxWidth, rhs.maxWidth)
|
||||
&& ASDimensionEqualToDimension(lhs.minHeight, rhs.minHeight)
|
||||
&& ASDimensionEqualToDimension(lhs.maxHeight, rhs.maxHeight));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string formatted to contain the data from an ASLayoutElementSize.
|
||||
*/
|
||||
extern AS_WARN_UNUSED_RESULT NSString *NSStringFromASLayoutElementSize(ASLayoutElementSize size);
|
||||
|
||||
/**
|
||||
* Resolve the given size relative to a parent size and an auto size.
|
||||
* From the given size uses width, height to resolve the exact size constraint, uses the minHeight and minWidth to
|
||||
* resolve the min size constraint and the maxHeight and maxWidth to resolve the max size constraint. For every
|
||||
* dimension with unit ASDimensionUnitAuto the given autoASSizeRange value will be used.
|
||||
* Based on the calculated exact, min and max size constraints the final size range will be calculated.
|
||||
*/
|
||||
extern AS_WARN_UNUSED_RESULT ASSizeRange ASLayoutElementSizeResolveAutoSize(ASLayoutElementSize size, const CGSize parentSize, ASSizeRange autoASSizeRange);
|
||||
|
||||
/**
|
||||
* Resolve the given size to a parent size. Uses internally ASLayoutElementSizeResolveAutoSize with {INFINITY, INFINITY} as
|
||||
* as autoASSizeRange. For more information look at ASLayoutElementSizeResolveAutoSize.
|
||||
*/
|
||||
ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT ASSizeRange ASLayoutElementSizeResolve(ASLayoutElementSize size, const CGSize parentSize)
|
||||
{
|
||||
return ASLayoutElementSizeResolveAutoSize(size, parentSize, ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY)));
|
||||
}
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
ASDISPLAYNODE_EXTERN_C_END
|
||||
66
AsyncDisplayKit/Layout/ASDimensionInternal.mm
Normal file
66
AsyncDisplayKit/Layout/ASDimensionInternal.mm
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// ASDimensionInternal.mm
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
|
||||
#import "ASDimensionInternal.h"
|
||||
|
||||
#pragma mark - ASLayoutElementSize
|
||||
|
||||
NSString *NSStringFromASLayoutElementSize(ASLayoutElementSize size)
|
||||
{
|
||||
return [NSString stringWithFormat:
|
||||
@"<ASLayoutElementSize: exact=%@, min=%@, max=%@>",
|
||||
NSStringFromASLayoutSize(ASLayoutSizeMake(size.width, size.height)),
|
||||
NSStringFromASLayoutSize(ASLayoutSizeMake(size.minWidth, size.minHeight)),
|
||||
NSStringFromASLayoutSize(ASLayoutSizeMake(size.maxWidth, size.maxHeight))];
|
||||
}
|
||||
|
||||
ASDISPLAYNODE_INLINE void ASLayoutElementSizeConstrain(CGFloat minVal, CGFloat exactVal, CGFloat maxVal, CGFloat *outMin, CGFloat *outMax)
|
||||
{
|
||||
NSCAssert(!isnan(minVal), @"minVal must not be NaN");
|
||||
NSCAssert(!isnan(maxVal), @"maxVal must not be NaN");
|
||||
// Avoid use of min/max primitives since they're harder to reason
|
||||
// about in the presence of NaN (in exactVal)
|
||||
// Follow CSS: min overrides max overrides exact.
|
||||
|
||||
// Begin with the min/max range
|
||||
*outMin = minVal;
|
||||
*outMax = maxVal;
|
||||
if (maxVal <= minVal) {
|
||||
// min overrides max and exactVal is irrelevant
|
||||
*outMax = minVal;
|
||||
return;
|
||||
}
|
||||
if (isnan(exactVal)) {
|
||||
// no exact value, so leave as a min/max range
|
||||
return;
|
||||
}
|
||||
if (exactVal > maxVal) {
|
||||
// clip to max value
|
||||
*outMin = maxVal;
|
||||
} else if (exactVal < minVal) {
|
||||
// clip to min value
|
||||
*outMax = minVal;
|
||||
} else {
|
||||
// use exact value
|
||||
*outMin = *outMax = exactVal;
|
||||
}
|
||||
}
|
||||
|
||||
ASSizeRange ASLayoutElementSizeResolveAutoSize(ASLayoutElementSize size, const CGSize parentSize, ASSizeRange autoASSizeRange)
|
||||
{
|
||||
CGSize resolvedExact = ASLayoutSizeResolveSize(ASLayoutSizeMake(size.width, size.height), parentSize, {NAN, NAN});
|
||||
CGSize resolvedMin = ASLayoutSizeResolveSize(ASLayoutSizeMake(size.minWidth, size.minHeight), parentSize, autoASSizeRange.min);
|
||||
CGSize resolvedMax = ASLayoutSizeResolveSize(ASLayoutSizeMake(size.maxWidth, size.maxHeight), parentSize, autoASSizeRange.max);
|
||||
|
||||
CGSize rangeMin, rangeMax;
|
||||
ASLayoutElementSizeConstrain(resolvedMin.width, resolvedExact.width, resolvedMax.width, &rangeMin.width, &rangeMax.width);
|
||||
ASLayoutElementSizeConstrain(resolvedMin.height, resolvedExact.height, resolvedMax.height, &rangeMin.height, &rangeMax.height);
|
||||
return {rangeMin, rangeMax};
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/ASDimension.h>
|
||||
#import <AsyncDisplayKit/ASDimensionInternal.h>
|
||||
#import <AsyncDisplayKit/ASStackLayoutDefines.h>
|
||||
#import <AsyncDisplayKit/ASStackLayoutElement.h>
|
||||
#import <AsyncDisplayKit/ASAbsoluteLayoutElement.h>
|
||||
@@ -315,7 +315,7 @@ extern NSString * const ASLayoutElementStyleLayoutPositionProperty;
|
||||
|
||||
@protocol ASLayoutElementStylability
|
||||
|
||||
- (instancetype)styledWithBlock:(__attribute__((noescape)) void (^)(__kindof ASLayoutElementStyle *style))styleBlock;
|
||||
- (instancetype)styledWithBlock:(AS_NOESCAPE void (^)(__kindof ASLayoutElementStyle *style))styleBlock;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* Boolean parameter that contains the value YES if all of the related animations completed successfully or
|
||||
* NO if they were interrupted. This parameter may be nil. If supplied, the block is run on the main thread.
|
||||
*/
|
||||
- (void)performBatchAnimated:(BOOL)animated updates:(nullable __attribute((noescape)) void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
- (void)performBatchAnimated:(BOOL)animated updates:(nullable AS_NOESCAPE void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
|
||||
/**
|
||||
* Perform a batch of updates asynchronously. This method must be called from the main thread.
|
||||
@@ -144,7 +144,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* Boolean parameter that contains the value YES if all of the related animations completed successfully or
|
||||
* NO if they were interrupted. This parameter may be nil. If supplied, the block is run on the main thread.
|
||||
*/
|
||||
- (void)performBatchUpdates:(nullable __attribute((noescape)) void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
- (void)performBatchUpdates:(nullable AS_NOESCAPE void (^)())updates completion:(nullable void (^)(BOOL finished))completion;
|
||||
|
||||
/**
|
||||
* Reload everything from scratch, destroying the working range and all cached nodes.
|
||||
|
||||
@@ -39,14 +39,12 @@ static CGFloat crossOffset(const ASStackLayoutSpecStyle &style,
|
||||
* @param style The layout style of the overall stack layout
|
||||
* @param firstChildOffset Offset of the first child
|
||||
* @param extraSpacing Spacing between children, in addition to spacing set to the stack's layout style
|
||||
* @param lastChildOffset Offset of the last child
|
||||
* @param unpositionedLayout Unpositioned children of the stack
|
||||
* @param constrainedSize Constrained size of the stack
|
||||
*/
|
||||
static ASStackPositionedLayout stackedLayout(const ASStackLayoutSpecStyle &style,
|
||||
const CGFloat firstChildOffset,
|
||||
const CGFloat extraSpacing,
|
||||
const CGFloat lastChildOffset,
|
||||
const ASStackUnpositionedLayout &unpositionedLayout,
|
||||
const ASSizeRange &constrainedSize)
|
||||
{
|
||||
@@ -63,14 +61,11 @@ static ASStackPositionedLayout stackedLayout(const ASStackLayoutSpecStyle &style
|
||||
|
||||
CGPoint p = directionPoint(style.direction, firstChildOffset, 0);
|
||||
BOOL first = YES;
|
||||
const auto lastChild = unpositionedLayout.items.back().child;
|
||||
CGFloat offset = 0;
|
||||
|
||||
// Adjust the position of the unpositioned layouts to be positioned
|
||||
const auto stackedChildren = unpositionedLayout.items;
|
||||
for (const auto &l : stackedChildren) {
|
||||
offset = (l.child.element == lastChild.element) ? lastChildOffset : 0;
|
||||
p = p + directionPoint(style.direction, l.child.style.spacingBefore + offset, 0);
|
||||
p = p + directionPoint(style.direction, l.child.style.spacingBefore, 0);
|
||||
if (!first) {
|
||||
p = p + directionPoint(style.direction, style.spacing + extraSpacing, 0);
|
||||
}
|
||||
@@ -83,14 +78,6 @@ static ASStackPositionedLayout stackedLayout(const ASStackLayoutSpecStyle &style
|
||||
return {std::move(stackedChildren), crossSize};
|
||||
}
|
||||
|
||||
static ASStackPositionedLayout stackedLayout(const ASStackLayoutSpecStyle &style,
|
||||
const CGFloat firstChildOffset,
|
||||
const ASStackUnpositionedLayout &unpositionedLayout,
|
||||
const ASSizeRange &constrainedSize)
|
||||
{
|
||||
return stackedLayout(style, firstChildOffset, 0, 0, unpositionedLayout, constrainedSize);
|
||||
}
|
||||
|
||||
ASStackPositionedLayout ASStackPositionedLayout::compute(const ASStackUnpositionedLayout &unpositionedLayout,
|
||||
const ASStackLayoutSpecStyle &style,
|
||||
const ASSizeRange &constrainedSize)
|
||||
@@ -109,23 +96,23 @@ ASStackPositionedLayout ASStackPositionedLayout::compute(const ASStackUnposition
|
||||
|
||||
switch (justifyContent) {
|
||||
case ASStackLayoutJustifyContentStart: {
|
||||
return stackedLayout(style, 0, unpositionedLayout, constrainedSize);
|
||||
return stackedLayout(style, 0, 0, unpositionedLayout, constrainedSize);
|
||||
}
|
||||
case ASStackLayoutJustifyContentCenter: {
|
||||
return stackedLayout(style, std::floor(violation / 2), unpositionedLayout, constrainedSize);
|
||||
return stackedLayout(style, std::floor(violation / 2), 0, unpositionedLayout, constrainedSize);
|
||||
}
|
||||
case ASStackLayoutJustifyContentEnd: {
|
||||
return stackedLayout(style, violation, unpositionedLayout, constrainedSize);
|
||||
return stackedLayout(style, violation, 0, unpositionedLayout, constrainedSize);
|
||||
}
|
||||
case ASStackLayoutJustifyContentSpaceBetween: {
|
||||
// Spacing between the items, no spaces at the edges, evenly distributed
|
||||
const auto numOfSpacings = numOfItems - 1;
|
||||
return stackedLayout(style, 0, violation / numOfSpacings, 0, unpositionedLayout, constrainedSize);
|
||||
return stackedLayout(style, 0, violation / numOfSpacings, unpositionedLayout, constrainedSize);
|
||||
}
|
||||
case ASStackLayoutJustifyContentSpaceAround: {
|
||||
// Spacing between items are twice the spacing on the edges
|
||||
CGFloat spacingUnit = violation / (numOfItems * 2);
|
||||
return stackedLayout(style, spacingUnit, spacingUnit * 2, 0, unpositionedLayout, constrainedSize);
|
||||
return stackedLayout(style, spacingUnit, spacingUnit * 2, unpositionedLayout, constrainedSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (CGSize)sizeForConstrainedWidth:(CGFloat)constrainedWidth;
|
||||
|
||||
|
||||
- (CGSize)sizeForConstrainedWidth:(CGFloat)constrainedWidth
|
||||
forMaxNumberOfLines:(NSInteger)numberOfLines;
|
||||
|
||||
@property (nonatomic, strong, readonly) NSTextStorage *textStorage;
|
||||
@property (nonatomic, strong, readonly) NSTextContainer *textContainer;
|
||||
@property (nonatomic, strong, readonly) NSLayoutManager *layoutManager;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#import "ASTextKitComponents.h"
|
||||
|
||||
#import <tgmath.h>
|
||||
|
||||
@interface ASTextKitComponents ()
|
||||
|
||||
// read-write redeclarations
|
||||
@@ -66,4 +68,55 @@
|
||||
return textSize;
|
||||
}
|
||||
|
||||
- (CGSize)sizeForConstrainedWidth:(CGFloat)constrainedWidth
|
||||
forMaxNumberOfLines:(NSInteger)maxNumberOfLines
|
||||
{
|
||||
if (maxNumberOfLines == 0) {
|
||||
return [self sizeForConstrainedWidth:constrainedWidth];
|
||||
}
|
||||
|
||||
ASTextKitComponents *components = self;
|
||||
|
||||
// Always use temporary stack in case of threading issues
|
||||
components = [ASTextKitComponents componentsWithAttributedSeedString:components.textStorage textContainerSize:CGSizeMake(constrainedWidth, CGFLOAT_MAX)];
|
||||
|
||||
// Force glyph generation and layout, which may not have happened yet (and isn't triggered by - usedRectForTextContainer:).
|
||||
[components.layoutManager ensureLayoutForTextContainer:components.textContainer];
|
||||
|
||||
CGFloat width = [components.layoutManager usedRectForTextContainer:components.textContainer].size.width;
|
||||
|
||||
// Calculate height based on line fragments
|
||||
// Based on calculating number of lines from: http://asciiwwdc.com/2013/sessions/220
|
||||
NSRange glyphRange, lineRange = NSMakeRange(0, 0);
|
||||
CGRect rect = CGRectZero;
|
||||
CGFloat height = 0;
|
||||
CGFloat lastOriginY = -1.0;
|
||||
NSUInteger numberOfLines = 0;
|
||||
|
||||
glyphRange = [components.layoutManager glyphRangeForTextContainer:components.textContainer];
|
||||
|
||||
while (lineRange.location < NSMaxRange(glyphRange)) {
|
||||
rect = [components.layoutManager lineFragmentRectForGlyphAtIndex:lineRange.location
|
||||
effectiveRange:&lineRange];
|
||||
|
||||
if (CGRectGetMinY(rect) > lastOriginY) {
|
||||
++numberOfLines;
|
||||
if (numberOfLines == maxNumberOfLines) {
|
||||
height = rect.origin.y + rect.size.height;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lastOriginY = CGRectGetMinY(rect);
|
||||
lineRange.location = NSMaxRange(lineRange);
|
||||
}
|
||||
|
||||
CGFloat fragmentHeight = rect.origin.y + rect.size.height;
|
||||
CGFloat finalHeight = std::ceil(std::fmax(height, fragmentHeight));
|
||||
|
||||
CGSize size = CGSizeMake(width, finalHeight);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -70,6 +70,27 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
roundedCorners:(UIRectCorner)roundedCorners
|
||||
scale:(CGFloat)scale AS_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* A version of imageNamed that caches results because loading an image is expensive.
|
||||
* Calling with the same name value will usually return the same object. A UIImage,
|
||||
* after creation, is immutable and thread-safe so it's fine to share these objects across multiple threads.
|
||||
*
|
||||
* @param imageName The name of the image to load
|
||||
* @return The loaded image or nil
|
||||
*/
|
||||
+ (UIImage *)as_imageNamed:(NSString *)imageName;
|
||||
|
||||
/**
|
||||
* A version of imageNamed that caches results because loading an image is expensive.
|
||||
* Calling with the same name value will usually return the same object. A UIImage,
|
||||
* after creation, is immutable and thread-safe so it's fine to share these objects across multiple threads.
|
||||
*
|
||||
* @param imageName The name of the image to load
|
||||
* @param traitCollection The traits associated with the intended environment for the image.
|
||||
* @return The loaded image or nil
|
||||
*/
|
||||
+ (UIImage *)as_imageNamed:(NSString *)imageName compatibleWithTraitCollection:(nullable UITraitCollection *)traitCollection;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -122,4 +122,47 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma mark - as_imageNamed
|
||||
|
||||
UIImage *cachedImageNamed(NSString *imageName, UITraitCollection *traitCollection)
|
||||
{
|
||||
static NSCache *imageCache = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
// Because NSCache responds to memory warnings, we do not need an explicit limit.
|
||||
// all of these objects contain compressed image data and are relatively small
|
||||
// compared to the backing stores of text and image views.
|
||||
imageCache = [[NSCache alloc] init];
|
||||
});
|
||||
|
||||
UIImage *image = nil;
|
||||
if ([imageName length] > 0) {
|
||||
NSString *imageKey = imageName;
|
||||
if (traitCollection) {
|
||||
char imageKeyBuffer[256];
|
||||
snprintf(imageKeyBuffer, sizeof(imageKeyBuffer), "%s|%ld|%ld", imageName.UTF8String, (long)traitCollection.horizontalSizeClass, (long)traitCollection.verticalSizeClass);
|
||||
imageKey = [NSString stringWithUTF8String:imageKeyBuffer];
|
||||
}
|
||||
|
||||
image = [imageCache objectForKey:imageKey];
|
||||
if (!image) {
|
||||
image = [UIImage imageNamed:imageName inBundle:nil compatibleWithTraitCollection:traitCollection];
|
||||
if (image) {
|
||||
[imageCache setObject:image forKey:imageKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
+ (UIImage *)as_imageNamed:(NSString *)imageName
|
||||
{
|
||||
return cachedImageNamed(imageName, nil);
|
||||
}
|
||||
|
||||
+ (UIImage *)as_imageNamed:(NSString *)imageName compatibleWithTraitCollection:(UITraitCollection *)traitCollection
|
||||
{
|
||||
return cachedImageNamed(imageName, traitCollection);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -94,16 +94,6 @@
|
||||
};
|
||||
}
|
||||
|
||||
- (void)collectionView:(ASCollectionView *)collectionView willDisplayNode:(ASCellNode *)node forItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ASDisplayNodeAssertNotNil(node.layoutAttributes, @"Expected layout attributes for node in %@ to be non-nil.", NSStringFromSelector(_cmd));
|
||||
}
|
||||
|
||||
- (void)collectionView:(ASCollectionView *)collectionView didEndDisplayingNode:(ASCellNode *)node forItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ASDisplayNodeAssertNotNil(node.layoutAttributes, @"Expected layout attributes for node in %@ to be non-nil.", NSStringFromSelector(_cmd));
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||
return _itemCounts.size();
|
||||
}
|
||||
@@ -890,7 +880,6 @@
|
||||
ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
|
||||
window.rootViewController = testController;
|
||||
|
||||
// Start with 1 item so that our content does not fill bounds.
|
||||
testController.asyncDelegate->_itemCounts = {};
|
||||
[window makeKeyAndVisible];
|
||||
[window layoutIfNeeded];
|
||||
@@ -1002,4 +991,65 @@
|
||||
XCTAssertLessThanOrEqual(contentHeight, requiredContentHeight + 2 * itemHeight, @"Loaded too much content.");
|
||||
}
|
||||
|
||||
- (void)testInitialRangeBounds
|
||||
{
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
|
||||
ASCollectionNode *cn = testController.collectionNode;
|
||||
[cn setTuningParameters:{ .leadingBufferScreenfuls = 2, .trailingBufferScreenfuls = 0 } forRangeMode:ASLayoutRangeModeMinimum rangeType:ASLayoutRangeTypePreload];
|
||||
window.rootViewController = testController;
|
||||
|
||||
[window makeKeyAndVisible];
|
||||
[window layoutIfNeeded];
|
||||
|
||||
[cn waitUntilAllUpdatesAreCommitted];
|
||||
|
||||
CGRect preloadBounds = ({
|
||||
CGRect r = CGRectNull;
|
||||
for (NSInteger s = 0; s < cn.numberOfSections; s++) {
|
||||
NSInteger c = [cn numberOfItemsInSection:s];
|
||||
for (NSInteger i = 0; i < c; i++) {
|
||||
NSIndexPath *ip = [NSIndexPath indexPathForItem:i inSection:s];
|
||||
ASCellNode *node = [cn nodeForItemAtIndexPath:ip];
|
||||
if (node.inPreloadState) {
|
||||
CGRect frame = [cn.view layoutAttributesForItemAtIndexPath:ip].frame;
|
||||
r = CGRectUnion(r, frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
r;
|
||||
});
|
||||
CGFloat expectedHeight = cn.bounds.size.height * 3;
|
||||
XCTAssertEqualWithAccuracy(CGRectGetHeight(preloadBounds), expectedHeight, 100);
|
||||
XCTAssertEqual([[cn valueForKeyPath:@"rangeController.currentRangeMode"] integerValue], ASLayoutRangeModeMinimum, @"Expected range mode to be minimum before scrolling begins.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests an issue where, since subnode insertions aren't applied until the UIKit layout pass,
|
||||
* which we trigger during the display phase, subnodes like network image nodes are not preloading
|
||||
* until this layout pass happens which is too late.
|
||||
*/
|
||||
- (void)DISABLED_testThatAutomaticallyManagedSubnodesGetPreloadCallBeforeDisplay
|
||||
{
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
|
||||
window.rootViewController = testController;
|
||||
ASCollectionNode *cn = testController.collectionNode;
|
||||
|
||||
__block NSInteger itemCount = 100;
|
||||
testController.asyncDelegate->_itemCounts = {itemCount};
|
||||
[window makeKeyAndVisible];
|
||||
[window layoutIfNeeded];
|
||||
|
||||
[cn waitUntilAllUpdatesAreCommitted];
|
||||
for (NSInteger i = 0; i < itemCount; i++) {
|
||||
ASTextCellNodeWithSetSelectedCounter *node = [cn nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
|
||||
XCTAssert(node.automaticallyManagesSubnodes, @"Expected test cell node to use automatic subnode management. Can modify the test with a different class if needed.");
|
||||
ASDisplayNode *subnode = node.textNode;
|
||||
XCTAssertEqualObjects(NSStringFromASInterfaceState(subnode.interfaceState), NSStringFromASInterfaceState(node.interfaceState), @"Subtree interface state should match cell node interface state for ASM nodes.");
|
||||
XCTAssert(node.inDisplayState || !node.nodeLoaded, @"Only nodes in the display range should be loaded.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -2283,4 +2283,25 @@ static bool stringContainsPointer(NSString *description, id p) {
|
||||
XCTAssertLessThan(underlayIndex, overlayIndex);
|
||||
}
|
||||
|
||||
- (void)testThatConvertPointGoesToWindowWhenPassedNil
|
||||
{
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
|
||||
ASDisplayNode *node = [[ASDisplayNode alloc] init];
|
||||
node.frame = CGRectMake(10, 10, 10, 10);
|
||||
[window addSubnode:node];
|
||||
CGPoint expectedOrigin = CGPointMake(10, 10);
|
||||
ASXCTAssertEqualPoints([node convertPoint:node.bounds.origin toNode:nil], expectedOrigin);
|
||||
}
|
||||
|
||||
- (void)testThatConvertPointGoesToWindowWhenPassedNil_layerBacked
|
||||
{
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
|
||||
ASDisplayNode *node = [[ASDisplayNode alloc] init];
|
||||
node.layerBacked = YES;
|
||||
node.frame = CGRectMake(10, 10, 10, 10);
|
||||
[window addSubnode:node];
|
||||
CGPoint expectedOrigin = CGPointMake(10, 10);
|
||||
ASXCTAssertEqualPoints([node convertPoint:node.bounds.origin toNode:nil], expectedOrigin);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "ASXCTExtensions.h"
|
||||
#import "ASLayoutElement.h"
|
||||
|
||||
|
||||
@@ -93,7 +93,8 @@
|
||||
return testController;
|
||||
}
|
||||
|
||||
- (void)testThatRootPagerNodeDoesGetTheRightInsetWhilePoppingBack
|
||||
// Disabled due to flakiness https://github.com/facebook/AsyncDisplayKit/issues/2818
|
||||
- (void)DISABLED_testThatRootPagerNodeDoesGetTheRightInsetWhilePoppingBack
|
||||
{
|
||||
UICollectionViewCell *cell = nil;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <XCTest/XCTestAssertionsImpl.h>
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
|
||||
#define ASXCTAssertRelativePerformanceInRange(test, caseName, min, max) \
|
||||
_XCTPrimitiveAssertLessThanOrEqual(self, test.results[caseName].relativePerformance, @#caseName, max, @#max);\
|
||||
@@ -32,7 +33,7 @@ typedef void (^ASTestPerformanceCaseBlock)(NSUInteger i, dispatch_block_t startM
|
||||
/**
|
||||
* The first case you add here will be considered the reference case.
|
||||
*/
|
||||
- (void)addCaseWithName:(NSString *)caseName block:(__attribute((noescape)) ASTestPerformanceCaseBlock)block;
|
||||
- (void)addCaseWithName:(NSString *)caseName block:(AS_NOESCAPE ASTestPerformanceCaseBlock)block;
|
||||
|
||||
@property (nonatomic, copy, readonly) NSDictionary<NSString *, ASPerformanceTestResult *> *results;
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)addCaseWithName:(NSString *)caseName block:(__attribute((noescape)) ASTestPerformanceCaseBlock)block
|
||||
- (void)addCaseWithName:(NSString *)caseName block:(AS_NOESCAPE ASTestPerformanceCaseBlock)block
|
||||
{
|
||||
ASDisplayNodeAssert(_results[caseName] == nil, @"Already have a case named %@", caseName);
|
||||
ASPerformanceTestResult *result = [[ASPerformanceTestResult alloc] init];
|
||||
@@ -91,7 +91,7 @@
|
||||
}
|
||||
|
||||
/// Returns total work time
|
||||
- (CFTimeInterval)_testPerformanceForCaseWithBlock:(__attribute((noescape)) ASTestPerformanceCaseBlock)block
|
||||
- (CFTimeInterval)_testPerformanceForCaseWithBlock:(AS_NOESCAPE ASTestPerformanceCaseBlock)block
|
||||
{
|
||||
__block CFTimeInterval time = 0;
|
||||
for (NSInteger i = 0; i < _iterationCount; i++) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#import "ASTableView+Undeprecated.h"
|
||||
#import <JGMethodSwizzler/JGMethodSwizzler.h>
|
||||
#import "ASXCTExtensions.h"
|
||||
#import "ASInternalHelpers.h"
|
||||
|
||||
#define NumberOfSections 10
|
||||
#define NumberOfReloadIterations 50
|
||||
@@ -234,7 +235,7 @@
|
||||
- (void)testConstrainedSizeForRowAtIndexPath
|
||||
{
|
||||
// Initial width of the table view is non-zero and all nodes are measured with this size.
|
||||
// Any subsequence size change must trigger a relayout.
|
||||
// Any subsequent size change must trigger a relayout.
|
||||
// Width and height are swapped so that a later size change will simulate a rotation
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] __initWithFrame:CGRectMake(0, 0, 100, 400)
|
||||
style:UITableViewStylePlain];
|
||||
@@ -249,12 +250,13 @@
|
||||
[tableView setNeedsLayout];
|
||||
[tableView layoutIfNeeded];
|
||||
|
||||
CGFloat separatorHeight = 1.0 / ASScreenScale();
|
||||
for (int section = 0; section < NumberOfSections; section++) {
|
||||
for (int row = 0; row < [tableView numberOfRowsInSection:section]; row++) {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
|
||||
CGRect rect = [tableView rectForRowAtIndexPath:indexPath];
|
||||
XCTAssertEqual(rect.size.width, 100); // specified width should be ignored for table
|
||||
XCTAssertEqual(rect.size.height, 42);
|
||||
XCTAssertEqual(rect.size.height, 42 + separatorHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -775,7 +777,7 @@
|
||||
[window layoutIfNeeded];
|
||||
[node waitUntilAllUpdatesAreCommitted];
|
||||
XCTAssertEqual(node.view.numberOfSections, NumberOfSections);
|
||||
ASXCTAssertEqualRects(CGRectMake(0, 32, 375, 43.5), [node rectForRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]], @"This text requires very specific geometry. The rect for the first row should match up.");
|
||||
ASXCTAssertEqualRects(CGRectMake(0, 32, 375, 44), [node rectForRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]], @"This text requires very specific geometry. The rect for the first row should match up.");
|
||||
|
||||
__unused XCTestExpectation *e = [self expectationWithDescription:@"Did a bunch of rounds of updates."];
|
||||
NSInteger totalCount = 20;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright © 2016 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
@import XCTest;
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
#import "ASTableViewInternal.h"
|
||||
#import "ASTableView+Undeprecated.h"
|
||||
|
||||
@@ -25,12 +25,6 @@
|
||||
}
|
||||
@end
|
||||
|
||||
@interface ASNetworkImageNode () {
|
||||
@public __weak id<ASNetworkImageNodeDelegate> _delegate;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface ASVideoNode () {
|
||||
ASDisplayNode *_playerNode;
|
||||
AVPlayer *_player;
|
||||
@@ -419,11 +413,9 @@
|
||||
XCTAssertTrue([_videoNode.delegate conformsToProtocol:@protocol(ASVideoNodeDelegate)]);
|
||||
XCTAssertTrue([_videoNode.delegate conformsToProtocol:@protocol(ASNetworkImageNodeDelegate)]);
|
||||
XCTAssertTrue([((ASNetworkImageNode*)_videoNode).delegate conformsToProtocol:@protocol(ASNetworkImageNodeDelegate)]);
|
||||
XCTAssertTrue([((ASNetworkImageNode*)_videoNode)->_delegate conformsToProtocol:@protocol(ASNetworkImageNodeDelegate)]);
|
||||
|
||||
XCTAssertEqual(_videoNode.delegate, self);
|
||||
XCTAssertEqual(((ASNetworkImageNode*)_videoNode).delegate, self);
|
||||
XCTAssertEqual(((ASNetworkImageNode*)_videoNode)->_delegate, self);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.8 KiB |
204
BUCK
Executable file
204
BUCK
Executable file
@@ -0,0 +1,204 @@
|
||||
#####################################
|
||||
# Defines
|
||||
#####################################
|
||||
COMMON_PREPROCESSOR_FLAGS = [
|
||||
'-fobjc-arc',
|
||||
'-DDEBUG=1',
|
||||
]
|
||||
|
||||
COMMON_LANG_PREPROCESSOR_FLAGS = {
|
||||
'C': ['-std=gnu99'],
|
||||
'CXX': ['-std=c++11', '-stdlib=libc++'],
|
||||
'OBJCXX': ['-std=c++11', '-stdlib=libc++'],
|
||||
}
|
||||
|
||||
COMMON_LINKER_FLAGS = ['-ObjC++']
|
||||
|
||||
ASYNCDISPLAYKIT_EXPORTED_HEADERS = glob([
|
||||
'AsyncDisplayKit/*.h',
|
||||
'AsyncDisplayKit/Details/**/*.h',
|
||||
'AsyncDisplayKit/Layout/*.h',
|
||||
'Base/*.h',
|
||||
'AsyncDisplayKit/Debug/ASLayoutElementInspectorNode.h',
|
||||
# Most TextKit components are not public because the C++ content
|
||||
# in the headers will cause build errors when using
|
||||
# `use_frameworks!` on 0.39.0 & Swift 2.1.
|
||||
# See https://github.com/facebook/AsyncDisplayKit/issues/1153
|
||||
'AsyncDisplayKit/TextKit/ASTextNodeTypes.h',
|
||||
'AsyncDisplayKit/TextKit/ASTextKitComponents.h'
|
||||
])
|
||||
|
||||
ASYNCDISPLAYKIT_PRIVATE_HEADERS = glob([
|
||||
'AsyncDisplayKit/**/*.h'
|
||||
],
|
||||
excludes = ASYNCDISPLAYKIT_EXPORTED_HEADERS,
|
||||
)
|
||||
|
||||
def asyncdisplaykit_library(
|
||||
name,
|
||||
additional_preprocessor_flags = [],
|
||||
deps = [],
|
||||
additional_frameworks = []):
|
||||
|
||||
apple_library(
|
||||
name = name,
|
||||
prefix_header = 'AsyncDisplayKit/AsyncDisplayKit-Prefix.pch',
|
||||
header_path_prefix = 'AsyncDisplayKit',
|
||||
exported_headers = ASYNCDISPLAYKIT_EXPORTED_HEADERS,
|
||||
headers = ASYNCDISPLAYKIT_PRIVATE_HEADERS,
|
||||
srcs = glob([
|
||||
'AsyncDisplayKit/**/*.m',
|
||||
'AsyncDisplayKit/**/*.mm',
|
||||
'Base/*.m'
|
||||
]),
|
||||
preprocessor_flags = COMMON_PREPROCESSOR_FLAGS + additional_preprocessor_flags,
|
||||
lang_preprocessor_flags = COMMON_LANG_PREPROCESSOR_FLAGS,
|
||||
linker_flags = COMMON_LINKER_FLAGS + [
|
||||
'-weak_framework',
|
||||
'Photos',
|
||||
'-weak_framework',
|
||||
'MapKit',
|
||||
],
|
||||
deps = deps,
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Foundation.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/UIKit.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/AssetsLibrary.framework',
|
||||
|
||||
'$SDKROOT/System/Library/Frameworks/QuartzCore.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/CoreMedia.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/CoreText.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/CoreGraphics.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/CoreLocation.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/AVFoundation.framework',
|
||||
] + additional_frameworks,
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
|
||||
#####################################
|
||||
# AsyncDisplayKit targets
|
||||
#####################################
|
||||
asyncdisplaykit_library(
|
||||
name = 'AsyncDisplayKit-Core',
|
||||
)
|
||||
|
||||
# (Default) AsyncDisplayKit and AsyncDisplayKit-PINRemoteImage targets are basically the same library with different names
|
||||
for name in ['AsyncDisplayKit', 'AsyncDisplayKit-PINRemoteImage']:
|
||||
asyncdisplaykit_library(
|
||||
name = name,
|
||||
additional_preprocessor_flags = ['-DPIN_REMOTE_IMAGE=1'],
|
||||
deps = [
|
||||
'//Pods/PINRemoteImage:PINRemoteImage-PINCache',
|
||||
],
|
||||
additional_frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/MobileCoreServices.framework',
|
||||
]
|
||||
)
|
||||
|
||||
#####################################
|
||||
# Test Host
|
||||
# TODO: Split to smaller BUCK files and parse in parallel
|
||||
#####################################
|
||||
apple_resource(
|
||||
name = 'TestHostResources',
|
||||
files = ['Default-568h@2x.png'],
|
||||
dirs = [],
|
||||
)
|
||||
|
||||
apple_bundle(
|
||||
name = 'TestHost',
|
||||
binary = ':TestHostBinary',
|
||||
extension = 'app',
|
||||
info_plist = 'AsyncDisplayKitTestHost/Info.plist',
|
||||
info_plist_substitutions = {
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'com.facebook.AsyncDisplayKitTestHost',
|
||||
},
|
||||
tests = [':Tests'],
|
||||
)
|
||||
|
||||
apple_binary(
|
||||
name = 'TestHostBinary',
|
||||
headers = glob(['AsyncDisplayKitTestHost/*.h']),
|
||||
srcs = glob([
|
||||
'AsyncDisplayKitTestHost/*.m',
|
||||
'AsyncDisplayKitTestHost/*.mm',
|
||||
]),
|
||||
lang_preprocessor_flags = COMMON_LANG_PREPROCESSOR_FLAGS,
|
||||
linker_flags = COMMON_LINKER_FLAGS,
|
||||
deps = [
|
||||
':TestHostResources',
|
||||
':AsyncDisplayKit-Core',
|
||||
],
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Photos.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/MapKit.framework',
|
||||
],
|
||||
)
|
||||
|
||||
apple_package(
|
||||
name = 'TestHostPackage',
|
||||
bundle = ':TestHost',
|
||||
)
|
||||
|
||||
#####################################
|
||||
# Tests
|
||||
#####################################
|
||||
apple_resource(
|
||||
name = 'TestsResources',
|
||||
files = ['AsyncDisplayKitTests/en.lproj/InfoPlist.strings'],
|
||||
dirs = ['AsyncDisplayKitTests/TestResources'],
|
||||
)
|
||||
|
||||
apple_resource(
|
||||
name = 'SnapshotTestsResources',
|
||||
files = [],
|
||||
dirs = [
|
||||
'AsyncDisplayKitTests/ReferenceImages_32',
|
||||
'AsyncDisplayKitTests/ReferenceImages_64',
|
||||
'AsyncDisplayKitTests/ReferenceImages_iOS_10',
|
||||
],
|
||||
)
|
||||
|
||||
apple_test(
|
||||
name = 'Tests',
|
||||
test_host_app = ':TestHost',
|
||||
info_plist = 'AsyncDisplayKitTests/AsyncDisplayKitTests-Info.plist',
|
||||
info_plist_substitutions = {
|
||||
'PRODUCT_BUNDLE_IDENTIFIER': 'com.facebook.AsyncDisplayKitTests',
|
||||
},
|
||||
prefix_header = 'AsyncDisplayKitTests/AsyncDisplayKitTests-Prefix.pch',
|
||||
# Expose all ASDK headers to tests
|
||||
headers = ASYNCDISPLAYKIT_EXPORTED_HEADERS + ASYNCDISPLAYKIT_PRIVATE_HEADERS + glob([
|
||||
'AsyncDisplayKitTests/*.h',
|
||||
]),
|
||||
srcs = glob([
|
||||
'AsyncDisplayKitTests/*.m',
|
||||
'AsyncDisplayKitTests/*.mm'
|
||||
],
|
||||
# ASTextNodePerformanceTests are excluded (#2173)
|
||||
excludes = ['AsyncDisplayKitTests/ASTextNodePerformanceTests.m*']
|
||||
),
|
||||
preprocessor_flags = COMMON_PREPROCESSOR_FLAGS + [
|
||||
'-Wno-implicit-function-declaration',
|
||||
],
|
||||
lang_preprocessor_flags = COMMON_LANG_PREPROCESSOR_FLAGS,
|
||||
linker_flags = COMMON_LINKER_FLAGS,
|
||||
deps = [
|
||||
':TestsResources',
|
||||
':SnapshotTestsResources',
|
||||
'//Pods/OCMock:OCMock',
|
||||
'//Pods/FBSnapshotTestCase:FBSnapshotTestCase',
|
||||
'//Pods/JGMethodSwizzler:JGMethodSwizzler',
|
||||
],
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Foundation.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/UIKit.framework',
|
||||
|
||||
'$SDKROOT/System/Library/Frameworks/CoreMedia.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/CoreText.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/CoreGraphics.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/AVFoundation.framework',
|
||||
|
||||
'$PLATFORM_DIR/Developer/Library/Frameworks/XCTest.framework',
|
||||
],
|
||||
)
|
||||
@@ -183,5 +183,15 @@
|
||||
|
||||
#define ASOVERLOADABLE __attribute__((overloadable))
|
||||
|
||||
|
||||
#if __has_attribute(noescape)
|
||||
#define AS_NOESCAPE __attribute__((noescape))
|
||||
#else
|
||||
#define AS_NOESCAPE
|
||||
#endif
|
||||
|
||||
/// Ensure that class is of certain kind
|
||||
#define ASDynamicCast(x, c) ((c *) ([x isKindOfClass:[c class]] ? x : nil))
|
||||
#define ASDynamicCast(x, c) ({ \
|
||||
id __val = x;\
|
||||
((c *) ([__val isKindOfClass:[c class]] ? __val : nil));\
|
||||
})
|
||||
|
||||
22
Podfile
22
Podfile
@@ -6,4 +6,26 @@ target :'AsyncDisplayKitTests' do
|
||||
pod 'OCMock', '~> 2.2'
|
||||
pod 'FBSnapshotTestCase/Core', '~> 2.1'
|
||||
pod 'JGMethodSwizzler', :git => 'https://github.com/JonasGessner/JGMethodSwizzler', :branch => 'master'
|
||||
|
||||
# Only for buck build
|
||||
pod 'PINRemoteImage', '3.0.0-beta.7'
|
||||
|
||||
#TODO CocoaPods plugin instead?
|
||||
post_install do |installer|
|
||||
require 'fileutils'
|
||||
|
||||
# Assuming we're at the root dir
|
||||
buck_files_dir = 'buck-files'
|
||||
if File.directory?(buck_files_dir)
|
||||
installer.pod_targets.flat_map do |pod_target|
|
||||
pod_name = pod_target.pod_name
|
||||
# Copy the file at buck-files/BUCK_pod_name to Pods/pod_name/BUCK,
|
||||
# override existing file if needed
|
||||
buck_file = buck_files_dir + '/BUCK_' + pod_name
|
||||
if File.file?(buck_file)
|
||||
FileUtils.cp(buck_file, 'Pods/' + pod_name + '/BUCK', :preserve => false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||

|
||||
|
||||
[](http://cocoapods.org/pods/AsyncDisplayKit)
|
||||
[](http://cocoapods.org/pods/AsyncDisplayKit)
|
||||
[](http://cocoapods.org/pods/AsyncDisplayKit)
|
||||
[](http://cocoapods.org/pods/AsyncDisplayKit)
|
||||
|
||||
[](http://AsyncDisplayKit.org)
|
||||
[](http://AsyncDisplayKit.org)
|
||||
|
||||
12
buck-files/BUCK_FBSnapshotTestCase
Executable file
12
buck-files/BUCK_FBSnapshotTestCase
Executable file
@@ -0,0 +1,12 @@
|
||||
apple_library(
|
||||
name = 'FBSnapshotTestCase',
|
||||
exported_headers = glob(['FBSnapshotTestCase' + '/**/*.h']),
|
||||
srcs = glob(['FBSnapshotTestCase' + '/**/*.m']),
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Foundation.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/UIKit.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/QuartzCore.framework',
|
||||
'$PLATFORM_DIR/Developer/Library/Frameworks/XCTest.framework',
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
18
buck-files/BUCK_FLAnimatedImage
Executable file
18
buck-files/BUCK_FLAnimatedImage
Executable file
@@ -0,0 +1,18 @@
|
||||
apple_library(
|
||||
name = 'FLAnimatedImage',
|
||||
exported_headers = glob(['FLAnimatedImage/*.h']),
|
||||
srcs = glob(['FLAnimatedImage/*.m']),
|
||||
preprocessor_flags = ['-fobjc-arc', '-Wno-deprecated-declarations'],
|
||||
lang_preprocessor_flags = {
|
||||
'C': ['-std=gnu99'],
|
||||
'CXX': ['-std=gnu++11', '-stdlib=libc++'],
|
||||
},
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Foundation.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/UIKit.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/ImageIO.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/MobileCoreServices.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/QuartzCore.framework',
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
9
buck-files/BUCK_JGMethodSwizzler
Executable file
9
buck-files/BUCK_JGMethodSwizzler
Executable file
@@ -0,0 +1,9 @@
|
||||
apple_library(
|
||||
name = 'JGMethodSwizzler',
|
||||
exported_headers = ['JGMethodSwizzler' + '/JGMethodSwizzler.h'],
|
||||
srcs = ['JGMethodSwizzler' + '/JGMethodSwizzler.m'],
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Foundation.framework',
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
9
buck-files/BUCK_OCMock
Executable file
9
buck-files/BUCK_OCMock
Executable file
@@ -0,0 +1,9 @@
|
||||
apple_library(
|
||||
name = 'OCMock',
|
||||
exported_headers = glob(['Source/OCMock' + '/*.h']),
|
||||
srcs = glob(['Source/OCMock' + '/*.m']),
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Foundation.framework',
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
23
buck-files/BUCK_PINCache
Executable file
23
buck-files/BUCK_PINCache
Executable file
@@ -0,0 +1,23 @@
|
||||
apple_library(
|
||||
name = 'PINCache',
|
||||
exported_headers = glob(['PINCache/*.h']),
|
||||
# PINDiskCache.m should be compiled with '-fobjc-arc-exceptions' (#105)
|
||||
srcs =
|
||||
glob(['PINCache/*.m'], excludes = ['PINCache/PINDiskCache.m']) +
|
||||
[('PINCache/PINDiskCache.m', ['-fobjc-arc-exceptions'])],
|
||||
preprocessor_flags = ['-fobjc-arc'],
|
||||
lang_preprocessor_flags = {
|
||||
'C': ['-std=gnu99'],
|
||||
'CXX': ['-std=gnu++11', '-stdlib=libc++'],
|
||||
},
|
||||
linker_flags = [
|
||||
'-weak_framework',
|
||||
'UIKit',
|
||||
'-weak_framework',
|
||||
'AppKit',
|
||||
],
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Foundation.framework',
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
93
buck-files/BUCK_PINRemoteImage
Executable file
93
buck-files/BUCK_PINRemoteImage
Executable file
@@ -0,0 +1,93 @@
|
||||
#####################################
|
||||
# Defines
|
||||
#####################################
|
||||
COMMON_PREPROCESSOR_FLAGS = ['-fobjc-arc']
|
||||
|
||||
COMMON_LANG_PREPROCESSOR_FLAGS = {
|
||||
'C': ['-std=gnu99'],
|
||||
'CXX': ['-std=gnu++11', '-stdlib=libc++'],
|
||||
}
|
||||
|
||||
FLANIMATEDIMAGE_HEADER_FILES = ['Pod/Classes/Image Categories/FLAnimatedImageView+PINRemoteImage.h']
|
||||
FLANIMATEDIMAGE_SOURCE_FILES = ['Pod/Classes/Image Categories/FLAnimatedImageView+PINRemoteImage.m']
|
||||
|
||||
PINCACHE_HEADER_FILES = glob(['Pod/Classes/PINCache/**/*.h'])
|
||||
PINCACHE_SOURCE_FILES = glob(['Pod/Classes/PINCache/**/*.m'])
|
||||
|
||||
#####################################
|
||||
# PINRemoteImage core targets
|
||||
#####################################
|
||||
apple_library(
|
||||
name = 'PINRemoteImage-Core',
|
||||
header_path_prefix = 'PINRemoteImage',
|
||||
exported_headers = glob([
|
||||
'Pod/Classes/**/*.h',
|
||||
],
|
||||
excludes = FLANIMATEDIMAGE_HEADER_FILES + PINCACHE_HEADER_FILES
|
||||
),
|
||||
srcs = glob([
|
||||
'Pod/Classes/**/*.m',
|
||||
],
|
||||
excludes = FLANIMATEDIMAGE_SOURCE_FILES + PINCACHE_SOURCE_FILES
|
||||
),
|
||||
preprocessor_flags = COMMON_PREPROCESSOR_FLAGS + [
|
||||
'-DPIN_TARGET_IOS=(TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR || TARGET_OS_TV)',
|
||||
'-DPIN_TARGET_MAC=(TARGET_OS_MAC)',
|
||||
],
|
||||
lang_preprocessor_flags = COMMON_LANG_PREPROCESSOR_FLAGS,
|
||||
linker_flags = [
|
||||
'-weak_framework',
|
||||
'UIKit',
|
||||
'-weak_framework',
|
||||
'MobileCoreServices',
|
||||
'-weak_framework',
|
||||
'Cocoa',
|
||||
'-weak_framework',
|
||||
'CoreServices',
|
||||
],
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/ImageIO.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/Accelerate.framework',
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
|
||||
apple_library(
|
||||
name = 'PINRemoteImage',
|
||||
deps = [
|
||||
':PINRemoteImage-FLAnimatedImage',
|
||||
':PINRemoteImage-PINCache'
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
|
||||
#####################################
|
||||
# Other PINRemoteImage targets
|
||||
#####################################
|
||||
apple_library(
|
||||
name = 'PINRemoteImage-FLAnimatedImage',
|
||||
header_path_prefix = 'PINRemoteImage',
|
||||
exported_headers = FLANIMATEDIMAGE_HEADER_FILES,
|
||||
srcs = FLANIMATEDIMAGE_SOURCE_FILES,
|
||||
preprocessor_flags = COMMON_PREPROCESSOR_FLAGS,
|
||||
deps = [
|
||||
':PINRemoteImage-Core',
|
||||
'//Pods/FLAnimatedImage:FLAnimatedImage'
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
|
||||
apple_library(
|
||||
name = 'PINRemoteImage-PINCache',
|
||||
header_path_prefix = 'PINRemoteImage',
|
||||
exported_headers = PINCACHE_HEADER_FILES,
|
||||
srcs = PINCACHE_SOURCE_FILES,
|
||||
preprocessor_flags = COMMON_PREPROCESSOR_FLAGS,
|
||||
deps = [
|
||||
':PINRemoteImage-Core',
|
||||
'//Pods/PINCache:PINCache'
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
|
||||
#TODO WebP variants
|
||||
2
build.sh
2
build.sh
@@ -295,7 +295,7 @@ fi
|
||||
if [ "$MODE" = "cocoapods-lint" ]; then
|
||||
echo "Verifying that podspec lints."
|
||||
|
||||
set -o pipefail && pod lib lint
|
||||
set -o pipefail && pod env && pod lib lint
|
||||
trap - EXIT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -88,10 +88,11 @@ static const CGFloat kInnerPadding = 10.0f;
|
||||
|
||||
// kitten image, with a solid background colour serving as placeholder
|
||||
_imageNode = [[ASNetworkImageNode alloc] init];
|
||||
_imageNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor();
|
||||
_imageNode.URL = [NSURL URLWithString:[NSString stringWithFormat:@"https://placekitten.com/%zd/%zd",
|
||||
(NSInteger)roundl(_kittenSize.width),
|
||||
(NSInteger)roundl(_kittenSize.height)]];
|
||||
_imageNode.placeholderFadeDuration = .5;
|
||||
_imageNode.placeholderColor = ASDisplayNodeDefaultPlaceholderColor();
|
||||
// _imageNode.contentMode = UIViewContentModeCenter;
|
||||
[_imageNode addTarget:self action:@selector(toggleNodesSwap) forControlEvents:ASControlNodeEventTouchUpInside];
|
||||
[self addSubnode:_imageNode];
|
||||
|
||||
Reference in New Issue
Block a user