Merge commit '8edc9fe08febed871eab512a24917764c37ddbb0'
# Conflicts: # AsyncDisplayKit.xcodeproj/project.pbxproj # AsyncDisplayKit/Private/ASImageNode+CGExtras.m
@ -66,7 +66,7 @@
|
|||||||
058D0A40195D057000B7D73C /* ASTextNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 058D0A36195D057000B7D73C /* ASTextNodeTests.m */; };
|
058D0A40195D057000B7D73C /* ASTextNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 058D0A36195D057000B7D73C /* ASTextNodeTests.m */; };
|
||||||
058D0A41195D057000B7D73C /* ASTextNodeWordKernerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 058D0A37195D057000B7D73C /* ASTextNodeWordKernerTests.mm */; };
|
058D0A41195D057000B7D73C /* ASTextNodeWordKernerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 058D0A37195D057000B7D73C /* ASTextNodeWordKernerTests.mm */; };
|
||||||
05A6D05B19D0EB64002DD95E /* ASDealloc2MainObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 05A6D05919D0EB64002DD95E /* ASDealloc2MainObject.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
05A6D05B19D0EB64002DD95E /* ASDealloc2MainObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 05A6D05919D0EB64002DD95E /* ASDealloc2MainObject.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||||
05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */; };
|
05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.m */; };
|
||||||
18C2ED7F1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
18C2ED7F1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
18C2ED801B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; };
|
18C2ED801B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; };
|
||||||
18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; };
|
18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; };
|
||||||
@ -225,6 +225,7 @@
|
|||||||
8021EC1D1D2B00B100799119 /* UIImage+ASConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = 8021EC1A1D2B00B100799119 /* UIImage+ASConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
8021EC1D1D2B00B100799119 /* UIImage+ASConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = 8021EC1A1D2B00B100799119 /* UIImage+ASConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
8021EC1E1D2B00B100799119 /* UIImage+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 8021EC1B1D2B00B100799119 /* UIImage+ASConvenience.m */; };
|
8021EC1E1D2B00B100799119 /* UIImage+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 8021EC1B1D2B00B100799119 /* UIImage+ASConvenience.m */; };
|
||||||
8021EC1F1D2B00B100799119 /* UIImage+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 8021EC1B1D2B00B100799119 /* UIImage+ASConvenience.m */; };
|
8021EC1F1D2B00B100799119 /* UIImage+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 8021EC1B1D2B00B100799119 /* UIImage+ASConvenience.m */; };
|
||||||
|
81E95C141D62639600336598 /* ASTextNodeSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 81E95C131D62639600336598 /* ASTextNodeSnapshotTests.m */; };
|
||||||
81EE38501C8E94F000456208 /* ASRunLoopQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */; };
|
81EE38501C8E94F000456208 /* ASRunLoopQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */; };
|
||||||
83A7D95A1D44542100BF333E /* ASWeakMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A7D9591D44542100BF333E /* ASWeakMap.m */; };
|
83A7D95A1D44542100BF333E /* ASWeakMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A7D9591D44542100BF333E /* ASWeakMap.m */; };
|
||||||
83A7D95B1D44547700BF333E /* ASWeakMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A7D9591D44542100BF333E /* ASWeakMap.m */; };
|
83A7D95B1D44547700BF333E /* ASWeakMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A7D9591D44542100BF333E /* ASWeakMap.m */; };
|
||||||
@ -264,7 +265,7 @@
|
|||||||
9C70F20B1CDBE9A4007D6C76 /* ASDataController+Subclasses.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF61BBB3D690087C538 /* ASDataController+Subclasses.h */; };
|
9C70F20B1CDBE9A4007D6C76 /* ASDataController+Subclasses.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF61BBB3D690087C538 /* ASDataController+Subclasses.h */; };
|
||||||
9C70F20C1CDBE9B6007D6C76 /* ASCollectionDataController.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF21BBB3D690087C538 /* ASCollectionDataController.h */; };
|
9C70F20C1CDBE9B6007D6C76 /* ASCollectionDataController.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF21BBB3D690087C538 /* ASCollectionDataController.h */; };
|
||||||
9C70F20D1CDBE9CB007D6C76 /* ASDefaultPlayButton.h in Headers */ = {isa = PBXBuildFile; fileRef = AEB7B0181C5962EA00662EF4 /* ASDefaultPlayButton.h */; };
|
9C70F20D1CDBE9CB007D6C76 /* ASDefaultPlayButton.h in Headers */ = {isa = PBXBuildFile; fileRef = AEB7B0181C5962EA00662EF4 /* ASDefaultPlayButton.h */; };
|
||||||
9C70F20E1CDBE9E5007D6C76 /* NSArray+Diffing.h in Headers */ = {isa = PBXBuildFile; fileRef = DBC452D91C5BF64600B16017 /* NSArray+Diffing.h */; };
|
9C70F20E1CDBE9E5007D6C76 /* NSArray+Diffing.h in Headers */ = {isa = PBXBuildFile; fileRef = DBC452D91C5BF64600B16017 /* NSArray+Diffing.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
9C70F20F1CDBE9FF007D6C76 /* ASLayoutManager.h in Headers */ = {isa = PBXBuildFile; fileRef = B30BF6501C5964B0004FCD53 /* ASLayoutManager.h */; };
|
9C70F20F1CDBE9FF007D6C76 /* ASLayoutManager.h in Headers */ = {isa = PBXBuildFile; fileRef = B30BF6501C5964B0004FCD53 /* ASLayoutManager.h */; };
|
||||||
9C8221961BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; };
|
9C8221961BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; };
|
||||||
9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */; };
|
9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */; };
|
||||||
@ -406,10 +407,11 @@
|
|||||||
B350625E1B0111780018CF92 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 051943121A1575630030A7D0 /* AssetsLibrary.framework */; };
|
B350625E1B0111780018CF92 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 051943121A1575630030A7D0 /* AssetsLibrary.framework */; };
|
||||||
B350625F1B0111800018CF92 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 058D09AF195D04C000B7D73C /* Foundation.framework */; };
|
B350625F1B0111800018CF92 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 058D09AF195D04C000B7D73C /* Foundation.framework */; };
|
||||||
C78F7E2B1BF7809800CDEAFC /* ASTableNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F880581BEAEC7500D17647 /* ASTableNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
C78F7E2B1BF7809800CDEAFC /* ASTableNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F880581BEAEC7500D17647 /* ASTableNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
CC0AEEA41D66316E005D1C78 /* ASUICollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC0AEEA31D66316E005D1C78 /* ASUICollectionViewTests.m */; };
|
||||||
CC3B20841C3F76D600798563 /* ASPendingStateController.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20811C3F76D600798563 /* ASPendingStateController.h */; };
|
CC3B20841C3F76D600798563 /* ASPendingStateController.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20811C3F76D600798563 /* ASPendingStateController.h */; };
|
||||||
CC3B20851C3F76D600798563 /* ASPendingStateController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20821C3F76D600798563 /* ASPendingStateController.mm */; };
|
CC3B20851C3F76D600798563 /* ASPendingStateController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20821C3F76D600798563 /* ASPendingStateController.mm */; };
|
||||||
CC3B20861C3F76D600798563 /* ASPendingStateController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20821C3F76D600798563 /* ASPendingStateController.mm */; };
|
CC3B20861C3F76D600798563 /* ASPendingStateController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20821C3F76D600798563 /* ASPendingStateController.mm */; };
|
||||||
CC3B208A1C3F7A5400798563 /* ASWeakSet.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20871C3F7A5400798563 /* ASWeakSet.h */; };
|
CC3B208A1C3F7A5400798563 /* ASWeakSet.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20871C3F7A5400798563 /* ASWeakSet.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
CC3B208B1C3F7A5400798563 /* ASWeakSet.m in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20881C3F7A5400798563 /* ASWeakSet.m */; };
|
CC3B208B1C3F7A5400798563 /* ASWeakSet.m in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20881C3F7A5400798563 /* ASWeakSet.m */; };
|
||||||
CC3B208C1C3F7A5400798563 /* ASWeakSet.m in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20881C3F7A5400798563 /* ASWeakSet.m */; };
|
CC3B208C1C3F7A5400798563 /* ASWeakSet.m in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20881C3F7A5400798563 /* ASWeakSet.m */; };
|
||||||
CC3B208E1C3F7D0A00798563 /* ASWeakSetTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.m */; };
|
CC3B208E1C3F7D0A00798563 /* ASWeakSetTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.m */; };
|
||||||
@ -419,6 +421,7 @@
|
|||||||
CC7FD9DF1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */; };
|
CC7FD9DF1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */; };
|
||||||
CC7FD9E11BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */; };
|
CC7FD9E11BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */; };
|
||||||
CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
CCB2F34D1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */; };
|
||||||
CCF18FF41D2575E300DF5895 /* NSIndexSet+ASHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */; };
|
CCF18FF41D2575E300DF5895 /* NSIndexSet+ASHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */; };
|
||||||
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */ = {isa = PBXBuildFile; fileRef = D785F6611A74327E00291744 /* ASScrollNode.m */; };
|
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */ = {isa = PBXBuildFile; fileRef = D785F6611A74327E00291744 /* ASScrollNode.m */; };
|
||||||
DB55C2631C6408D6004EDCF5 /* _ASTransitionContext.m in Sources */ = {isa = PBXBuildFile; fileRef = DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.m */; };
|
DB55C2631C6408D6004EDCF5 /* _ASTransitionContext.m in Sources */ = {isa = PBXBuildFile; fileRef = DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.m */; };
|
||||||
@ -437,7 +440,6 @@
|
|||||||
DE4843DB1C93EAB100A1F33B /* ASLayoutTransition.mm in Sources */ = {isa = PBXBuildFile; fileRef = E52405B21C8FEF03004DC8E7 /* ASLayoutTransition.mm */; };
|
DE4843DB1C93EAB100A1F33B /* ASLayoutTransition.mm in Sources */ = {isa = PBXBuildFile; fileRef = E52405B21C8FEF03004DC8E7 /* ASLayoutTransition.mm */; };
|
||||||
DE4843DC1C93EAC100A1F33B /* ASLayoutTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = E52405B41C8FEF16004DC8E7 /* ASLayoutTransition.h */; };
|
DE4843DC1C93EAC100A1F33B /* ASLayoutTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = E52405B41C8FEF16004DC8E7 /* ASLayoutTransition.h */; };
|
||||||
DE6EA3231C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */; };
|
DE6EA3231C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */; };
|
||||||
DE72E2AC1D4D90E000DDB258 /* (null) in CopyFiles */ = {isa = PBXBuildFile; };
|
|
||||||
DE84918D1C8FFF2B003D89E9 /* ASRunLoopQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
DE84918D1C8FFF2B003D89E9 /* ASRunLoopQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
DE84918E1C8FFF9F003D89E9 /* ASRunLoopQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */; };
|
DE84918E1C8FFF9F003D89E9 /* ASRunLoopQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */; };
|
||||||
DE8BEAC21C2DF3FC00D57C12 /* ASDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = DE8BEABF1C2DF3FC00D57C12 /* ASDelegateProxy.h */; };
|
DE8BEAC21C2DF3FC00D57C12 /* ASDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = DE8BEABF1C2DF3FC00D57C12 /* ASDelegateProxy.h */; };
|
||||||
@ -708,7 +710,6 @@
|
|||||||
F7CE6C611D2CDB3E00BE4C15 /* ASLayoutable.h in CopyFiles */,
|
F7CE6C611D2CDB3E00BE4C15 /* ASLayoutable.h in CopyFiles */,
|
||||||
F7CE6C621D2CDB3E00BE4C15 /* ASLayoutablePrivate.h in CopyFiles */,
|
F7CE6C621D2CDB3E00BE4C15 /* ASLayoutablePrivate.h in CopyFiles */,
|
||||||
F7CE6C631D2CDB3E00BE4C15 /* ASLayoutSpec.h in CopyFiles */,
|
F7CE6C631D2CDB3E00BE4C15 /* ASLayoutSpec.h in CopyFiles */,
|
||||||
DE72E2AC1D4D90E000DDB258 /* (null) in CopyFiles */,
|
|
||||||
F7CE6C641D2CDB3E00BE4C15 /* ASOverlayLayoutSpec.h in CopyFiles */,
|
F7CE6C641D2CDB3E00BE4C15 /* ASOverlayLayoutSpec.h in CopyFiles */,
|
||||||
F7CE6C651D2CDB3E00BE4C15 /* ASRatioLayoutSpec.h in CopyFiles */,
|
F7CE6C651D2CDB3E00BE4C15 /* ASRatioLayoutSpec.h in CopyFiles */,
|
||||||
F7CE6C661D2CDB3E00BE4C15 /* ASRelativeLayoutSpec.h in CopyFiles */,
|
F7CE6C661D2CDB3E00BE4C15 /* ASRelativeLayoutSpec.h in CopyFiles */,
|
||||||
@ -874,7 +875,7 @@
|
|||||||
058D0A44195D058D00B7D73C /* ASBaseDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASBaseDefines.h; sourceTree = "<group>"; };
|
058D0A44195D058D00B7D73C /* ASBaseDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASBaseDefines.h; sourceTree = "<group>"; };
|
||||||
05A6D05819D0EB64002DD95E /* ASDealloc2MainObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASDealloc2MainObject.h; path = ../Details/ASDealloc2MainObject.h; sourceTree = "<group>"; };
|
05A6D05819D0EB64002DD95E /* ASDealloc2MainObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASDealloc2MainObject.h; path = ../Details/ASDealloc2MainObject.h; sourceTree = "<group>"; };
|
||||||
05A6D05919D0EB64002DD95E /* ASDealloc2MainObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASDealloc2MainObject.m; path = ../Details/ASDealloc2MainObject.m; sourceTree = "<group>"; };
|
05A6D05919D0EB64002DD95E /* ASDealloc2MainObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASDealloc2MainObject.m; path = ../Details/ASDealloc2MainObject.m; sourceTree = "<group>"; };
|
||||||
05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASSnapshotTestCase.mm; sourceTree = "<group>"; };
|
05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASSnapshotTestCase.m; sourceTree = "<group>"; };
|
||||||
05F20AA31A15733C00DCA68A /* ASImageProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageProtocols.h; sourceTree = "<group>"; };
|
05F20AA31A15733C00DCA68A /* ASImageProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageProtocols.h; sourceTree = "<group>"; };
|
||||||
18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionNode.h; sourceTree = "<group>"; };
|
18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionNode.h; sourceTree = "<group>"; };
|
||||||
18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionNode.mm; sourceTree = "<group>"; };
|
18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionNode.mm; sourceTree = "<group>"; };
|
||||||
@ -977,6 +978,7 @@
|
|||||||
7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRelativeLayoutSpecSnapshotTests.mm; sourceTree = "<group>"; };
|
7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRelativeLayoutSpecSnapshotTests.mm; sourceTree = "<group>"; };
|
||||||
8021EC1A1D2B00B100799119 /* UIImage+ASConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+ASConvenience.h"; sourceTree = "<group>"; };
|
8021EC1A1D2B00B100799119 /* UIImage+ASConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+ASConvenience.h"; sourceTree = "<group>"; };
|
||||||
8021EC1B1D2B00B100799119 /* UIImage+ASConvenience.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+ASConvenience.m"; sourceTree = "<group>"; };
|
8021EC1B1D2B00B100799119 /* UIImage+ASConvenience.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+ASConvenience.m"; sourceTree = "<group>"; };
|
||||||
|
81E95C131D62639600336598 /* ASTextNodeSnapshotTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTextNodeSnapshotTests.m; sourceTree = "<group>"; };
|
||||||
81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRunLoopQueue.h; path = ../ASRunLoopQueue.h; sourceTree = "<group>"; };
|
81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRunLoopQueue.h; path = ../ASRunLoopQueue.h; sourceTree = "<group>"; };
|
||||||
81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRunLoopQueue.mm; path = ../ASRunLoopQueue.mm; sourceTree = "<group>"; };
|
81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRunLoopQueue.mm; path = ../ASRunLoopQueue.mm; sourceTree = "<group>"; };
|
||||||
83A7D9581D44542100BF333E /* ASWeakMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakMap.h; sourceTree = "<group>"; };
|
83A7D9581D44542100BF333E /* ASWeakMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakMap.h; sourceTree = "<group>"; };
|
||||||
@ -1075,6 +1077,7 @@
|
|||||||
B35061DA1B010EDF0018CF92 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
B35061DA1B010EDF0018CF92 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B35061DD1B010EDF0018CF92 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "../AsyncDisplayKit-iOS/Info.plist"; sourceTree = "<group>"; };
|
B35061DD1B010EDF0018CF92 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "../AsyncDisplayKit-iOS/Info.plist"; sourceTree = "<group>"; };
|
||||||
BDC2D162BD55A807C1475DA5 /* Pods-AsyncDisplayKitTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.profile.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.profile.xcconfig"; sourceTree = "<group>"; };
|
BDC2D162BD55A807C1475DA5 /* Pods-AsyncDisplayKitTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.profile.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
CC0AEEA31D66316E005D1C78 /* ASUICollectionViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASUICollectionViewTests.m; sourceTree = "<group>"; };
|
||||||
CC3B20811C3F76D600798563 /* ASPendingStateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPendingStateController.h; sourceTree = "<group>"; };
|
CC3B20811C3F76D600798563 /* ASPendingStateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPendingStateController.h; sourceTree = "<group>"; };
|
||||||
CC3B20821C3F76D600798563 /* ASPendingStateController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASPendingStateController.mm; sourceTree = "<group>"; };
|
CC3B20821C3F76D600798563 /* ASPendingStateController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASPendingStateController.mm; sourceTree = "<group>"; };
|
||||||
CC3B20871C3F7A5400798563 /* ASWeakSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakSet.h; sourceTree = "<group>"; };
|
CC3B20871C3F7A5400798563 /* ASWeakSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakSet.h; sourceTree = "<group>"; };
|
||||||
@ -1087,6 +1090,7 @@
|
|||||||
CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPhotosFrameworkImageRequest.h; sourceTree = "<group>"; };
|
CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPhotosFrameworkImageRequest.h; sourceTree = "<group>"; };
|
||||||
CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPhotosFrameworkImageRequest.m; sourceTree = "<group>"; };
|
CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPhotosFrameworkImageRequest.m; sourceTree = "<group>"; };
|
||||||
CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPhotosFrameworkImageRequestTests.m; sourceTree = "<group>"; };
|
CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPhotosFrameworkImageRequestTests.m; sourceTree = "<group>"; };
|
||||||
|
CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayNodeSnapshotTests.m; sourceTree = "<group>"; };
|
||||||
D3779BCFF841AD3EB56537ED /* Pods-AsyncDisplayKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.release.xcconfig"; sourceTree = "<group>"; };
|
D3779BCFF841AD3EB56537ED /* Pods-AsyncDisplayKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = "<group>"; };
|
D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = "<group>"; };
|
||||||
D785F6611A74327E00291744 /* ASScrollNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASScrollNode.m; sourceTree = "<group>"; };
|
D785F6611A74327E00291744 /* ASScrollNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASScrollNode.m; sourceTree = "<group>"; };
|
||||||
@ -1320,6 +1324,8 @@
|
|||||||
058D09C5195D04C000B7D73C /* AsyncDisplayKitTests */ = {
|
058D09C5195D04C000B7D73C /* AsyncDisplayKitTests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CC0AEEA31D66316E005D1C78 /* ASUICollectionViewTests.m */,
|
||||||
|
CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */,
|
||||||
83A7D95D1D446A6E00BF333E /* ASWeakMapTests.m */,
|
83A7D95D1D446A6E00BF333E /* ASWeakMapTests.m */,
|
||||||
DBC453211C5FD97200B16017 /* ASDisplayNodeImplicitHierarchyTests.m */,
|
DBC453211C5FD97200B16017 /* ASDisplayNodeImplicitHierarchyTests.m */,
|
||||||
DBC452DD1C5C6A6A00B16017 /* ArrayDiffingTests.m */,
|
DBC452DD1C5C6A6A00B16017 /* ArrayDiffingTests.m */,
|
||||||
@ -1327,7 +1333,7 @@
|
|||||||
CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.m */,
|
CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.m */,
|
||||||
057D02C01AC0A66700C7AC3C /* AsyncDisplayKitTestHost */,
|
057D02C01AC0A66700C7AC3C /* AsyncDisplayKitTestHost */,
|
||||||
056D21501ABCEDA1001107EF /* ASSnapshotTestCase.h */,
|
056D21501ABCEDA1001107EF /* ASSnapshotTestCase.h */,
|
||||||
05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */,
|
05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.m */,
|
||||||
056D21541ABCEF50001107EF /* ASImageNodeSnapshotTests.m */,
|
056D21541ABCEF50001107EF /* ASImageNodeSnapshotTests.m */,
|
||||||
ACF6ED531B178DC700DA7C62 /* ASCenterLayoutSpecSnapshotTests.mm */,
|
ACF6ED531B178DC700DA7C62 /* ASCenterLayoutSpecSnapshotTests.mm */,
|
||||||
7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */,
|
7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */,
|
||||||
@ -1336,6 +1342,7 @@
|
|||||||
ACF6ED5A1B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm */,
|
ACF6ED5A1B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm */,
|
||||||
ACF6ED5B1B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm */,
|
ACF6ED5B1B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm */,
|
||||||
AC026B571BD3F61800BBC17E /* ASStaticLayoutSpecSnapshotTests.m */,
|
AC026B571BD3F61800BBC17E /* ASStaticLayoutSpecSnapshotTests.m */,
|
||||||
|
81E95C131D62639600336598 /* ASTextNodeSnapshotTests.m */,
|
||||||
ACF6ED571B178DC700DA7C62 /* ASLayoutSpecSnapshotTestsHelper.h */,
|
ACF6ED571B178DC700DA7C62 /* ASLayoutSpecSnapshotTestsHelper.h */,
|
||||||
ACF6ED581B178DC700DA7C62 /* ASLayoutSpecSnapshotTestsHelper.m */,
|
ACF6ED581B178DC700DA7C62 /* ASLayoutSpecSnapshotTestsHelper.m */,
|
||||||
242995D21B29743C00090100 /* ASBasicImageDownloaderTests.m */,
|
242995D21B29743C00090100 /* ASBasicImageDownloaderTests.m */,
|
||||||
@ -1443,6 +1450,10 @@
|
|||||||
058D09FF195D050800B7D73C /* UIView+ASConvenience.h */,
|
058D09FF195D050800B7D73C /* UIView+ASConvenience.h */,
|
||||||
9C70F2011CDA4EFA007D6C76 /* ASTraitCollection.h */,
|
9C70F2011CDA4EFA007D6C76 /* ASTraitCollection.h */,
|
||||||
9C70F2021CDA4EFA007D6C76 /* ASTraitCollection.m */,
|
9C70F2021CDA4EFA007D6C76 /* ASTraitCollection.m */,
|
||||||
|
CC3B20871C3F7A5400798563 /* ASWeakSet.h */,
|
||||||
|
CC3B20881C3F7A5400798563 /* ASWeakSet.m */,
|
||||||
|
DBC452D91C5BF64600B16017 /* NSArray+Diffing.h */,
|
||||||
|
DBC452DA1C5BF64600B16017 /* NSArray+Diffing.m */,
|
||||||
);
|
);
|
||||||
path = Details;
|
path = Details;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1511,10 +1522,6 @@
|
|||||||
ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */,
|
ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */,
|
||||||
83A7D9581D44542100BF333E /* ASWeakMap.h */,
|
83A7D9581D44542100BF333E /* ASWeakMap.h */,
|
||||||
83A7D9591D44542100BF333E /* ASWeakMap.m */,
|
83A7D9591D44542100BF333E /* ASWeakMap.m */,
|
||||||
CC3B20871C3F7A5400798563 /* ASWeakSet.h */,
|
|
||||||
CC3B20881C3F7A5400798563 /* ASWeakSet.m */,
|
|
||||||
DBC452D91C5BF64600B16017 /* NSArray+Diffing.h */,
|
|
||||||
DBC452DA1C5BF64600B16017 /* NSArray+Diffing.m */,
|
|
||||||
8B0768B11CE752EC002E1453 /* ASDefaultPlaybackButton.h */,
|
8B0768B11CE752EC002E1453 /* ASDefaultPlaybackButton.h */,
|
||||||
8B0768B21CE752EC002E1453 /* ASDefaultPlaybackButton.m */,
|
8B0768B21CE752EC002E1453 /* ASDefaultPlaybackButton.m */,
|
||||||
);
|
);
|
||||||
@ -2180,6 +2187,7 @@
|
|||||||
058D0A38195D057000B7D73C /* ASDisplayLayerTests.m in Sources */,
|
058D0A38195D057000B7D73C /* ASDisplayLayerTests.m in Sources */,
|
||||||
2538B6F31BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m in Sources */,
|
2538B6F31BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m in Sources */,
|
||||||
058D0A39195D057000B7D73C /* ASDisplayNodeAppearanceTests.m in Sources */,
|
058D0A39195D057000B7D73C /* ASDisplayNodeAppearanceTests.m in Sources */,
|
||||||
|
CCB2F34D1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m in Sources */,
|
||||||
058D0A3A195D057000B7D73C /* ASDisplayNodeTests.m in Sources */,
|
058D0A3A195D057000B7D73C /* ASDisplayNodeTests.m in Sources */,
|
||||||
CC4981B31D1A02BE004E13CC /* ASTableViewThrashTests.m in Sources */,
|
CC4981B31D1A02BE004E13CC /* ASTableViewThrashTests.m in Sources */,
|
||||||
058D0A3B195D057000B7D73C /* ASDisplayNodeTestsHelper.m in Sources */,
|
058D0A3B195D057000B7D73C /* ASDisplayNodeTestsHelper.m in Sources */,
|
||||||
@ -2193,11 +2201,13 @@
|
|||||||
058D0A3C195D057000B7D73C /* ASMutableAttributedStringBuilderTests.m in Sources */,
|
058D0A3C195D057000B7D73C /* ASMutableAttributedStringBuilderTests.m in Sources */,
|
||||||
697B315A1CFE4B410049936F /* ASEditableTextNodeTests.m in Sources */,
|
697B315A1CFE4B410049936F /* ASEditableTextNodeTests.m in Sources */,
|
||||||
ACF6ED611B178DC700DA7C62 /* ASOverlayLayoutSpecSnapshotTests.mm in Sources */,
|
ACF6ED611B178DC700DA7C62 /* ASOverlayLayoutSpecSnapshotTests.mm in Sources */,
|
||||||
|
CC0AEEA41D66316E005D1C78 /* ASUICollectionViewTests.m in Sources */,
|
||||||
ACF6ED621B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm in Sources */,
|
ACF6ED621B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm in Sources */,
|
||||||
7AB338691C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm in Sources */,
|
7AB338691C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm in Sources */,
|
||||||
254C6B541BF8FF2A003EC431 /* ASTextKitTests.mm in Sources */,
|
254C6B541BF8FF2A003EC431 /* ASTextKitTests.mm in Sources */,
|
||||||
05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.mm in Sources */,
|
05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.m in Sources */,
|
||||||
ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */,
|
ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */,
|
||||||
|
81E95C141D62639600336598 /* ASTextNodeSnapshotTests.m in Sources */,
|
||||||
3C9C128519E616EF00E942A0 /* ASTableViewTests.m in Sources */,
|
3C9C128519E616EF00E942A0 /* ASTableViewTests.m in Sources */,
|
||||||
AEEC47E41C21D3D200EC1693 /* ASVideoNodeTests.m in Sources */,
|
AEEC47E41C21D3D200EC1693 /* ASVideoNodeTests.m in Sources */,
|
||||||
254C6B521BF8FE6D003EC431 /* ASTextKitTruncationTests.mm in Sources */,
|
254C6B521BF8FE6D003EC431 /* ASTextKitTruncationTests.mm in Sources */,
|
||||||
@ -2491,6 +2501,7 @@
|
|||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
|
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
|
||||||
OTHER_CFLAGS = "-Wall";
|
OTHER_CFLAGS = "-Wall";
|
||||||
@ -2512,6 +2523,7 @@
|
|||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
|
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
|
||||||
OTHER_CFLAGS = "-Wall";
|
OTHER_CFLAGS = "-Wall";
|
||||||
@ -2697,6 +2709,7 @@
|
|||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
|
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
|
||||||
OTHER_CFLAGS = "-Wall";
|
OTHER_CFLAGS = "-Wall";
|
||||||
|
|||||||
@ -14,7 +14,6 @@
|
|||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
#import "ASBackgroundLayoutSpec.h"
|
#import "ASBackgroundLayoutSpec.h"
|
||||||
#import "ASInsetLayoutSpec.h"
|
#import "ASInsetLayoutSpec.h"
|
||||||
#import "ASDisplayNode+Beta.h"
|
|
||||||
#import "ASStaticLayoutSpec.h"
|
#import "ASStaticLayoutSpec.h"
|
||||||
|
|
||||||
@interface ASButtonNode ()
|
@interface ASButtonNode ()
|
||||||
@ -56,7 +55,7 @@
|
|||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
self.usesImplicitHierarchyManagement = YES;
|
self.automaticallyManagesSubnodes = YES;
|
||||||
|
|
||||||
_contentSpacing = 8.0;
|
_contentSpacing = 8.0;
|
||||||
_laysOutHorizontally = YES;
|
_laysOutHorizontally = YES;
|
||||||
|
|||||||
@ -115,13 +115,11 @@
|
|||||||
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)transitionLayoutWithAnimation:(BOOL)animated
|
- (void)transitionLayoutAnimated:(BOOL)animated
|
||||||
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
|
||||||
measurementCompletion:(void (^)())completion
|
measurementCompletion:(void (^)())completion
|
||||||
{
|
{
|
||||||
CGSize oldSize = self.calculatedSize;
|
CGSize oldSize = self.calculatedSize;
|
||||||
[super transitionLayoutWithAnimation:animated
|
[super transitionLayoutAnimated:animated
|
||||||
shouldMeasureAsync:shouldMeasureAsync
|
|
||||||
measurementCompletion:^{
|
measurementCompletion:^{
|
||||||
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
||||||
if (completion) {
|
if (completion) {
|
||||||
@ -131,15 +129,21 @@
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Deprecated
|
||||||
|
- (void)transitionLayoutWithAnimation:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(void(^)())completion
|
||||||
|
{
|
||||||
|
[self transitionLayoutAnimated:animated measurementCompletion:completion];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
animated:(BOOL)animated
|
animated:(BOOL)animated
|
||||||
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
|
||||||
measurementCompletion:(void (^)())completion
|
measurementCompletion:(void (^)())completion
|
||||||
{
|
{
|
||||||
CGSize oldSize = self.calculatedSize;
|
CGSize oldSize = self.calculatedSize;
|
||||||
[super transitionLayoutWithSizeRange:constrainedSize
|
[super transitionLayoutWithSizeRange:constrainedSize
|
||||||
animated:animated
|
animated:animated
|
||||||
shouldMeasureAsync:shouldMeasureAsync
|
|
||||||
measurementCompletion:^{
|
measurementCompletion:^{
|
||||||
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
[self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize];
|
||||||
if (completion) {
|
if (completion) {
|
||||||
@ -149,6 +153,15 @@
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Deprecated
|
||||||
|
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
|
animated:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(void(^)())completion
|
||||||
|
{
|
||||||
|
[self transitionLayoutWithSizeRange:constrainedSize animated:animated measurementCompletion:completion];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)didRelayoutFromOldSize:(CGSize)oldSize toNewSize:(CGSize)newSize
|
- (void)didRelayoutFromOldSize:(CGSize)oldSize toNewSize:(CGSize)newSize
|
||||||
{
|
{
|
||||||
if (_interactionDelegate != nil) {
|
if (_interactionDelegate != nil) {
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
#import "ASEnvironmentInternal.h"
|
#import "ASEnvironmentInternal.h"
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
#import "ASCellNode+Internal.h"
|
#import "ASCellNode+Internal.h"
|
||||||
|
#import "AsyncDisplayKit+Debug.h"
|
||||||
|
|
||||||
#pragma mark - _ASCollectionPendingState
|
#pragma mark - _ASCollectionPendingState
|
||||||
|
|
||||||
@ -171,6 +172,12 @@
|
|||||||
[self.view clearFetchedData];
|
[self.view clearFetchedData];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState
|
||||||
|
{
|
||||||
|
[super interfaceStateDidChange:newState fromState:oldState];
|
||||||
|
[ASRangeController layoutDebugOverlayIfNeeded];
|
||||||
|
}
|
||||||
|
|
||||||
#if ASRangeControllerLoggingEnabled
|
#if ASRangeControllerLoggingEnabled
|
||||||
- (void)visibleStateDidChange:(BOOL)isVisible
|
- (void)visibleStateDidChange:(BOOL)isVisible
|
||||||
{
|
{
|
||||||
|
|||||||
@ -400,17 +400,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
|
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the constrained size range for measuring the node at the index path.
|
|
||||||
*
|
|
||||||
* @param collectionView The sender.
|
|
||||||
*
|
|
||||||
* @param indexPath The index path of the node.
|
|
||||||
*
|
|
||||||
* @returns A constrained size range for layout the node at this index path.
|
|
||||||
*/
|
|
||||||
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicator to lock the data source for data fetching in async mode.
|
* Indicator to lock the data source for data fetching in async mode.
|
||||||
* We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistency or exception
|
* We should not update the data source until the data source has been unlocked. Otherwise, it will incur data inconsistency or exception
|
||||||
@ -442,6 +431,17 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@optional
|
@optional
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the constrained size range for measuring the node at the index path.
|
||||||
|
*
|
||||||
|
* @param collectionView The sender.
|
||||||
|
*
|
||||||
|
* @param indexPath The index path of the node.
|
||||||
|
*
|
||||||
|
* @returns A constrained size range for layout the node at this index path.
|
||||||
|
*/
|
||||||
|
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Informs the delegate that the collection view will add the node
|
* Informs the delegate that the collection view will add the node
|
||||||
* at the given index path to the view hierarchy.
|
* at the given index path to the view hierarchy.
|
||||||
|
|||||||
@ -18,7 +18,6 @@
|
|||||||
#import "ASCollectionViewFlowLayoutInspector.h"
|
#import "ASCollectionViewFlowLayoutInspector.h"
|
||||||
#import "ASDisplayNodeExtras.h"
|
#import "ASDisplayNodeExtras.h"
|
||||||
#import "ASDisplayNode+FrameworkPrivate.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
#import "ASDisplayNode+Beta.h"
|
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
#import "UICollectionViewLayout+ASConvenience.h"
|
#import "UICollectionViewLayout+ASConvenience.h"
|
||||||
#import "ASRangeController.h"
|
#import "ASRangeController.h"
|
||||||
@ -151,11 +150,9 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
} _asyncDelegateFlags;
|
} _asyncDelegateFlags;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned int asyncDataSourceConstrainedSizeForNode:1;
|
|
||||||
unsigned int asyncDataSourceNodeForItemAtIndexPath:1;
|
unsigned int asyncDataSourceNodeForItemAtIndexPath:1;
|
||||||
unsigned int asyncDataSourceNodeBlockForItemAtIndexPath:1;
|
unsigned int asyncDataSourceNodeBlockForItemAtIndexPath:1;
|
||||||
unsigned int asyncDataSourceNumberOfSectionsInCollectionView:1;
|
unsigned int asyncDataSourceNumberOfSectionsInCollectionView:1;
|
||||||
unsigned int asyncDataSourceCollectionViewConstrainedSizeForNodeAtIndexPath:1;
|
|
||||||
} _asyncDataSourceFlags;
|
} _asyncDataSourceFlags;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@ -354,11 +351,9 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
_asyncDataSource = asyncDataSource;
|
_asyncDataSource = asyncDataSource;
|
||||||
_proxyDataSource = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
|
_proxyDataSource = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
|
||||||
|
|
||||||
_asyncDataSourceFlags.asyncDataSourceConstrainedSizeForNode = [_asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
|
|
||||||
_asyncDataSourceFlags.asyncDataSourceNodeForItemAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:nodeForItemAtIndexPath:)];
|
_asyncDataSourceFlags.asyncDataSourceNodeForItemAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:nodeForItemAtIndexPath:)];
|
||||||
_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:nodeBlockForItemAtIndexPath:)];
|
_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:nodeBlockForItemAtIndexPath:)];
|
||||||
_asyncDataSourceFlags.asyncDataSourceNumberOfSectionsInCollectionView = [_asyncDataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)];
|
_asyncDataSourceFlags.asyncDataSourceNumberOfSectionsInCollectionView = [_asyncDataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)];
|
||||||
_asyncDataSourceFlags.asyncDataSourceCollectionViewConstrainedSizeForNodeAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
|
|
||||||
|
|
||||||
// Data-source must implement collectionView:nodeForItemAtIndexPath: or collectionView:nodeBlockForItemAtIndexPath:
|
// Data-source must implement collectionView:nodeForItemAtIndexPath: or collectionView:nodeBlockForItemAtIndexPath:
|
||||||
ASDisplayNodeAssertTrue(_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath || _asyncDataSourceFlags.asyncDataSourceNodeForItemAtIndexPath);
|
ASDisplayNodeAssertTrue(_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath || _asyncDataSourceFlags.asyncDataSourceNodeForItemAtIndexPath);
|
||||||
@ -1038,11 +1033,6 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
return [self.layoutInspector collectionView:self supplementaryNodesOfKind:kind inSection:section];
|
return [self.layoutInspector collectionView:self supplementaryNodesOfKind:kind inSection:section];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)dataController:(ASCollectionDataController *)dataController numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind;
|
|
||||||
{
|
|
||||||
return [self.layoutInspector collectionView:self numberOfSectionsForSupplementaryNodeOfKind:kind];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - ASRangeControllerDataSource
|
#pragma mark - ASRangeControllerDataSource
|
||||||
|
|
||||||
- (ASRangeController *)rangeController
|
- (ASRangeController *)rangeController
|
||||||
@ -1080,6 +1070,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
return [_dataController nodeAtIndexPath:indexPath];
|
return [_dataController nodeAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *)nameForRangeControllerDataSource
|
||||||
|
{
|
||||||
|
return self.asyncDataSource ? NSStringFromClass([self.asyncDataSource class]) : NSStringFromClass([self class]);
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - ASRangeControllerDelegate
|
#pragma mark - ASRangeControllerDelegate
|
||||||
|
|
||||||
- (void)didBeginUpdatesInRangeController:(ASRangeController *)rangeController
|
- (void)didBeginUpdatesInRangeController:(ASRangeController *)rangeController
|
||||||
|
|||||||
@ -10,7 +10,10 @@
|
|||||||
// of patent rights can be found in the PATENTS file in the same directory.
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import <AsyncDisplayKit/ASDisplayNode.h>
|
#import <AsyncDisplayKit/ASDimension.h>
|
||||||
|
|
||||||
|
@class ASDisplayNode;
|
||||||
|
@class ASLayout;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
// of patent rights can be found in the PATENTS file in the same directory.
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "ASContextTransitioning.h"
|
#import "ASDisplayNode.h"
|
||||||
#import "ASLayoutRangeType.h"
|
#import "ASLayoutRangeType.h"
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
@ -20,9 +20,6 @@ ASDISPLAYNODE_EXTERN_C_END
|
|||||||
|
|
||||||
@interface ASDisplayNode (Beta)
|
@interface ASDisplayNode (Beta)
|
||||||
|
|
||||||
+ (BOOL)usesImplicitHierarchyManagement;
|
|
||||||
+ (void)setUsesImplicitHierarchyManagement:(BOOL)enabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ASTableView and ASCollectionView now throw exceptions on invalid updates
|
* ASTableView and ASCollectionView now throw exceptions on invalid updates
|
||||||
* like their UIKit counterparts. If YES, these classes will log messages
|
* like their UIKit counterparts. If YES, these classes will log messages
|
||||||
@ -63,65 +60,12 @@ ASDISPLAYNODE_EXTERN_C_END
|
|||||||
|
|
||||||
/** @name Layout Transitioning */
|
/** @name Layout Transitioning */
|
||||||
|
|
||||||
@property (nonatomic) BOOL usesImplicitHierarchyManagement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @discussion A place to perform your animation. New nodes have been inserted here. You can also use this time to re-order the hierarchy.
|
|
||||||
*/
|
|
||||||
- (void)animateLayoutTransition:(id<ASContextTransitioning>)context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @discussion A place to clean up your nodes after the transition
|
|
||||||
*/
|
|
||||||
- (void)didCompleteLayoutTransition:(id<ASContextTransitioning>)context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract Transitions the current layout with a new constrained size. Must be called on main thread.
|
|
||||||
*
|
|
||||||
* @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`.
|
|
||||||
*
|
|
||||||
* @param shouldMeasureAsync Measure the layout asynchronously.
|
|
||||||
*
|
|
||||||
* @param measurementCompletion Optional completion block called only if a new layout is calculated.
|
|
||||||
* It is called on main, right after the measurement and before -animateLayoutTransition:.
|
|
||||||
*
|
|
||||||
* @discussion If the passed constrainedSize is the the same as the node's current constrained size, this method is noop.
|
|
||||||
*
|
|
||||||
* @see animateLayoutTransition:
|
|
||||||
*/
|
|
||||||
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
|
||||||
animated:(BOOL)animated
|
|
||||||
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
|
||||||
measurementCompletion:(nullable void(^)())completion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract Invalidates the current layout and begins a relayout of the node with the current `constrainedSize`. Must be called on main thread.
|
|
||||||
*
|
|
||||||
* @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`.
|
|
||||||
*
|
|
||||||
* @param shouldMeasureAsync Measure the layout asynchronously.
|
|
||||||
*
|
|
||||||
* @param measurementCompletion Optional completion block called only if a new layout is calculated.
|
|
||||||
* It is called right after the measurement and before -animateLayoutTransition:.
|
|
||||||
*
|
|
||||||
* @see animateLayoutTransition:
|
|
||||||
*/
|
|
||||||
- (void)transitionLayoutWithAnimation:(BOOL)animated
|
|
||||||
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
|
||||||
measurementCompletion:(nullable void(^)())completion;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract Currently used by ASNetworkImageNode and ASMultiplexImageNode to allow their placeholders to stay if they are loading an image from the network.
|
* @abstract Currently used by ASNetworkImageNode and ASMultiplexImageNode to allow their placeholders to stay if they are loading an image from the network.
|
||||||
* Otherwise, a display pass is scheduled and completes, but does not actually draw anything - and ASDisplayNode considers the element finished.
|
* Otherwise, a display pass is scheduled and completes, but does not actually draw anything - and ASDisplayNode considers the element finished.
|
||||||
*/
|
*/
|
||||||
- (BOOL)placeholderShouldPersist;
|
- (BOOL)placeholderShouldPersist;
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract Cancels all performing layout transitions. Can be called on any thread.
|
|
||||||
*/
|
|
||||||
- (void)cancelLayoutTransitionsInProgress;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract Indicates that the receiver and all subnodes have finished displaying. May be called more than once, for example if the receiver has
|
* @abstract Indicates that the receiver and all subnodes have finished displaying. May be called more than once, for example if the receiver has
|
||||||
* a network image node. This is called after the first display pass even if network image nodes have not downloaded anything (text would be done,
|
* a network image node. This is called after the first display pass even if network image nodes have not downloaded anything (text would be done,
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#import <AsyncDisplayKit/ASDimension.h>
|
#import <AsyncDisplayKit/ASDimension.h>
|
||||||
#import <AsyncDisplayKit/ASAsciiArtBoxCreator.h>
|
#import <AsyncDisplayKit/ASAsciiArtBoxCreator.h>
|
||||||
#import <AsyncDisplayKit/ASLayoutable.h>
|
#import <AsyncDisplayKit/ASLayoutable.h>
|
||||||
|
#import <AsyncDisplayKit/ASContextTransitioning.h>
|
||||||
|
|
||||||
#define ASDisplayNodeLoggingEnabled 0
|
#define ASDisplayNodeLoggingEnabled 0
|
||||||
|
|
||||||
@ -615,7 +616,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
/**
|
/**
|
||||||
* ## UIView bridge
|
* ## UIView bridge
|
||||||
*
|
*
|
||||||
@ -744,11 +745,92 @@ NS_ASSUME_NONNULL_END
|
|||||||
// Accessibility identification support
|
// Accessibility identification support
|
||||||
@property (nonatomic, copy, nullable) NSString *accessibilityIdentifier;
|
@property (nonatomic, copy, nullable) NSString *accessibilityIdentifier;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ASDisplayNode (LayoutTransitioning)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract The amount of time it takes to complete the default transition animation. Default is 0.2.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) NSTimeInterval defaultLayoutTransitionDuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract The amount of time (measured in seconds) to wait before beginning the default transition animation.
|
||||||
|
* Default is 0.0.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) NSTimeInterval defaultLayoutTransitionDelay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract A mask of options indicating how you want to perform the default transition animations.
|
||||||
|
* For a list of valid constants, see UIViewAnimationOptions.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) UIViewAnimationOptions defaultLayoutTransitionOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @discussion A place to perform your animation. New nodes have been inserted here. You can also use this time to re-order the hierarchy.
|
||||||
|
*/
|
||||||
|
- (void)animateLayoutTransition:(nonnull id<ASContextTransitioning>)context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @discussion A place to clean up your nodes after the transition
|
||||||
|
*/
|
||||||
|
- (void)didCompleteLayoutTransition:(nonnull id<ASContextTransitioning>)context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Transitions the current layout with a new constrained size. Must be called on main thread.
|
||||||
|
*
|
||||||
|
* @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`.
|
||||||
|
* @param shouldMeasureAsync Measure the layout asynchronously.
|
||||||
|
* @param measurementCompletion Optional completion block called only if a new layout is calculated.
|
||||||
|
*
|
||||||
|
* @discussion It is called on main, right after the measurement and before -animateLayoutTransition:. If the passed constrainedSize is the the same as the node's current constrained size, this method is noop.
|
||||||
|
*
|
||||||
|
* @see animateLayoutTransition:
|
||||||
|
*/
|
||||||
|
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
|
animated:(BOOL)animated
|
||||||
|
measurementCompletion:(nullable void(^)())completion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Invalidates the current layout and begins a relayout of the node with the current `constrainedSize`. Must be called on main thread.
|
||||||
|
*
|
||||||
|
* @discussion It is called right after the measurement and before -animateLayoutTransition:.
|
||||||
|
*
|
||||||
|
* @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`.
|
||||||
|
* @param measurementCompletion Optional completion block called only if a new layout is calculated.
|
||||||
|
*
|
||||||
|
* @see animateLayoutTransition:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
- (void)transitionLayoutAnimated:(BOOL)animated measurementCompletion:(nullable void(^)())completion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Cancels all performing layout transitions. Can be called on any thread.
|
||||||
|
*/
|
||||||
|
- (void)cancelLayoutTransition;
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ASDisplayNode participates in ASAsyncTransactions, so you can determine when your subnodes are done rendering.
|
* ASDisplayNode support for automatic subnode management.
|
||||||
See: -(void)asyncdisplaykit_asyncTransactionContainerStateDidChange in ASDisplayNodeSubclass.h
|
*/
|
||||||
|
@interface ASDisplayNode (AutomaticSubnodeManagement)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract A boolean that shows whether the node automatically inserts and removes nodes based on the presence or
|
||||||
|
* absence of the node and its subnodes is completely determined in its layoutSpecThatFits: method.
|
||||||
|
*
|
||||||
|
* @discussion If flag is YES the node no longer require addSubnode: or removeFromSupernode method calls. The presence
|
||||||
|
* or absence of subnodes is completely determined in its layoutSpecThatFits: method.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) BOOL automaticallyManagesSubnodes;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ASDisplayNode participates in ASAsyncTransactions, so you can determine when your subnodes are done rendering.
|
||||||
|
* See: -(void)asyncdisplaykit_asyncTransactionContainerStateDidChange in ASDisplayNodeSubclass.h
|
||||||
*/
|
*/
|
||||||
@interface ASDisplayNode (ASDisplayNodeAsyncTransactionContainer) <ASDisplayNodeAsyncTransactionContainer>
|
@interface ASDisplayNode (ASDisplayNodeAsyncTransactionContainer) <ASDisplayNodeAsyncTransactionContainer>
|
||||||
@end
|
@end
|
||||||
@ -763,7 +845,9 @@ NS_ASSUME_NONNULL_END
|
|||||||
- (void)addSubnode:(nonnull ASDisplayNode *)node;
|
- (void)addSubnode:(nonnull ASDisplayNode *)node;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/** CALayer(AsyncDisplayKit) defines convenience method for adding sub-ASDisplayNode to a CALayer. */
|
/*
|
||||||
|
* CALayer(AsyncDisplayKit) defines convenience method for adding sub-ASDisplayNode to a CALayer.
|
||||||
|
*/
|
||||||
@interface CALayer (AsyncDisplayKit)
|
@interface CALayer (AsyncDisplayKit)
|
||||||
/**
|
/**
|
||||||
* Convenience method, equivalent to [layer addSublayer:node.layer].
|
* Convenience method, equivalent to [layer addSublayer:node.layer].
|
||||||
@ -776,8 +860,69 @@ NS_ASSUME_NONNULL_END
|
|||||||
|
|
||||||
@interface ASDisplayNode (Deprecated)
|
@interface ASDisplayNode (Deprecated)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Transitions the current layout with a new constrained size. Must be called on main thread.
|
||||||
|
*
|
||||||
|
* @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`.
|
||||||
|
* @param shouldMeasureAsync Measure the layout asynchronously.
|
||||||
|
* @param measurementCompletion Optional completion block called only if a new layout is calculated.
|
||||||
|
* It is called on main, right after the measurement and before -animateLayoutTransition:.
|
||||||
|
*
|
||||||
|
* @discussion If the passed constrainedSize is the the same as the node's current constrained size, this method is noop.
|
||||||
|
*
|
||||||
|
* @see animateLayoutTransition:
|
||||||
|
*
|
||||||
|
* @deprecated Deprecated in version 2.0: Use transitionLayoutWithSizeRange:animated:measurementCompletion:.
|
||||||
|
* shouldMeasureAsync is enabled by default now.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
|
animated:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(nullable void(^)())completion ASDISPLAYNODE_DEPRECATED;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Invalidates the current layout and begins a relayout of the node with the current `constrainedSize`. Must be called on main thread.
|
||||||
|
*
|
||||||
|
* @discussion It is called right after the measurement and before -animateLayoutTransition:.
|
||||||
|
*
|
||||||
|
* @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`.
|
||||||
|
* @param shouldMeasureAsync Measure the layout asynchronously.
|
||||||
|
* @param measurementCompletion Optional completion block called only if a new layout is calculated.
|
||||||
|
*
|
||||||
|
* @see animateLayoutTransition:
|
||||||
|
*
|
||||||
|
* @deprecated Deprecated in version 2.0: Use transitionLayoutAnimated:measurementCompletion:
|
||||||
|
* shouldMeasureAsync is enabled by default now.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
- (void)transitionLayoutWithAnimation:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(nullable void(^)())completion ASDISPLAYNODE_DEPRECATED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Cancels all performing layout transitions. Can be called on any thread.
|
||||||
|
*
|
||||||
|
* @deprecated Deprecated in version 2.0: Use cancelLayoutTransition
|
||||||
|
*/
|
||||||
|
- (void)cancelLayoutTransitionsInProgress ASDISPLAYNODE_DEPRECATED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract A boolean that shows whether the node automatically inserts and removes nodes based on the presence or
|
||||||
|
* absence of the node and its subnodes is completely determined in its layoutSpecThatFits: method.
|
||||||
|
*
|
||||||
|
* @discussion If flag is YES the node no longer require addSubnode: or removeFromSupernode method calls. The presence
|
||||||
|
* or absence of subnodes is completely determined in its layoutSpecThatFits: method.
|
||||||
|
*
|
||||||
|
* @deprecated Deprecated in version 2.0: Use automaticallyManagesSubnodes
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) BOOL usesImplicitHierarchyManagement ASDISPLAYNODE_DEPRECATED;
|
||||||
|
|
||||||
- (void)reclaimMemory ASDISPLAYNODE_DEPRECATED;
|
- (void)reclaimMemory ASDISPLAYNODE_DEPRECATED;
|
||||||
- (void)recursivelyReclaimMemory ASDISPLAYNODE_DEPRECATED;
|
- (void)recursivelyReclaimMemory ASDISPLAYNODE_DEPRECATED;
|
||||||
@property (nonatomic, assign) BOOL placeholderFadesOut ASDISPLAYNODE_DEPRECATED;
|
@property (nonatomic, assign) BOOL placeholderFadesOut ASDISPLAYNODE_DEPRECATED;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@ -77,18 +77,6 @@ NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"AS
|
|||||||
@synthesize isFinalLayoutable = _isFinalLayoutable;
|
@synthesize isFinalLayoutable = _isFinalLayoutable;
|
||||||
@synthesize threadSafeBounds = _threadSafeBounds;
|
@synthesize threadSafeBounds = _threadSafeBounds;
|
||||||
|
|
||||||
static BOOL usesImplicitHierarchyManagement = NO;
|
|
||||||
|
|
||||||
+ (BOOL)usesImplicitHierarchyManagement
|
|
||||||
{
|
|
||||||
return usesImplicitHierarchyManagement;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)setUsesImplicitHierarchyManagement:(BOOL)enabled
|
|
||||||
{
|
|
||||||
usesImplicitHierarchyManagement = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL suppressesInvalidCollectionUpdateExceptions = YES;
|
static BOOL suppressesInvalidCollectionUpdateExceptions = YES;
|
||||||
|
|
||||||
+ (BOOL)suppressesInvalidCollectionUpdateExceptions
|
+ (BOOL)suppressesInvalidCollectionUpdateExceptions
|
||||||
@ -291,8 +279,12 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
|
|
||||||
_environmentState = ASEnvironmentStateMakeDefault();
|
_environmentState = ASEnvironmentStateMakeDefault();
|
||||||
|
|
||||||
|
_defaultLayoutTransitionDuration = 0.2;
|
||||||
|
_defaultLayoutTransitionDelay = 0.0;
|
||||||
|
_defaultLayoutTransitionOptions = UIViewAnimationOptionBeginFromCurrentState;
|
||||||
|
|
||||||
_flags.canClearContentsOfLayer = YES;
|
_flags.canClearContentsOfLayer = YES;
|
||||||
_flags.canCallNeedsDisplayOfLayer = NO;
|
_flags.canCallSetNeedsDisplayOfLayer = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
@ -462,12 +454,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update flags related to special handling of UIImageView layers. More details on the flags
|
// Update flags related to special handling of UIImageView layers. More details on the flags
|
||||||
if (_flags.synchronous) {
|
if (_flags.synchronous && [_viewClass isSubclassOfClass:[UIImageView class]]) {
|
||||||
if ([view isKindOfClass:[UIImageView class]]) {
|
|
||||||
_flags.canClearContentsOfLayer = NO;
|
_flags.canClearContentsOfLayer = NO;
|
||||||
} else {
|
_flags.canCallSetNeedsDisplayOfLayer = NO;
|
||||||
_flags.canCallNeedsDisplayOfLayer = YES;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
@ -646,7 +635,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
return _calculatedLayout ? : [ASLayout layoutWithLayoutableObject:self constrainedSizeRange:constrainedSize size:CGSizeZero];
|
return _calculatedLayout ? : [ASLayout layoutWithLayoutableObject:self constrainedSizeRange:constrainedSize size:CGSizeZero];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self cancelLayoutTransitionsInProgress];
|
[self cancelLayoutTransition];
|
||||||
|
|
||||||
ASLayout *previousLayout = _calculatedLayout;
|
ASLayout *previousLayout = _calculatedLayout;
|
||||||
ASLayout *newLayout = [self calculateLayoutThatFits:constrainedSize];
|
ASLayout *newLayout = [self calculateLayoutThatFits:constrainedSize];
|
||||||
@ -699,11 +688,23 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
return !self.isNodeLoaded;
|
return !self.isNodeLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Automatic Hierarchy
|
||||||
|
|
||||||
|
- (BOOL)automaticallyManagesSubnodes
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
return _automaticallyManagesSubnodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAutomaticallyManagesSubnodes:(BOOL)automaticallyManagesSubnodes
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
_automaticallyManagesSubnodes = automaticallyManagesSubnodes;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Layout Transition
|
#pragma mark - Layout Transition
|
||||||
|
|
||||||
- (void)transitionLayoutWithAnimation:(BOOL)animated
|
- (void)transitionLayoutAnimated:(BOOL)animated measurementCompletion:(void (^)())completion
|
||||||
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
|
||||||
measurementCompletion:(void(^)())completion
|
|
||||||
{
|
{
|
||||||
if (_calculatedLayout == nil) {
|
if (_calculatedLayout == nil) {
|
||||||
// constrainedSizeRange returns a struct and is invalid to call on nil.
|
// constrainedSizeRange returns a struct and is invalid to call on nil.
|
||||||
@ -714,13 +715,11 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
[self invalidateCalculatedLayout];
|
[self invalidateCalculatedLayout];
|
||||||
[self transitionLayoutWithSizeRange:_calculatedLayout.constrainedSizeRange
|
[self transitionLayoutWithSizeRange:_calculatedLayout.constrainedSizeRange
|
||||||
animated:animated
|
animated:animated
|
||||||
shouldMeasureAsync:shouldMeasureAsync
|
|
||||||
measurementCompletion:completion];
|
measurementCompletion:completion];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
animated:(BOOL)animated
|
animated:(BOOL)animated
|
||||||
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
|
||||||
measurementCompletion:(void (^)())completion
|
measurementCompletion:(void (^)())completion
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
@ -741,7 +740,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
node.pendingTransitionID = transitionID;
|
node.pendingTransitionID = transitionID;
|
||||||
});
|
});
|
||||||
|
|
||||||
void (^transitionBlock)() = ^{
|
ASPerformBlockOnBackgroundThread(^{
|
||||||
if ([self _shouldAbortTransitionWithID:transitionID]) {
|
if ([self _shouldAbortTransitionWithID:transitionID]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -751,11 +750,11 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
ASLayoutableSetCurrentContext(ASLayoutableContextMake(transitionID, NO));
|
ASLayoutableSetCurrentContext(ASLayoutableContextMake(transitionID, NO));
|
||||||
|
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
BOOL disableImplicitHierarchyManagement = self.usesImplicitHierarchyManagement == NO;
|
BOOL automaticallyManagesSubnodesDisabled = (self.automaticallyManagesSubnodes == NO);
|
||||||
self.usesImplicitHierarchyManagement = YES; // Temporary flag for 1.9.x
|
self.automaticallyManagesSubnodes = YES; // Temporary flag for 1.9.x
|
||||||
newLayout = [self calculateLayoutThatFits:constrainedSize];
|
newLayout = [self calculateLayoutThatFits:constrainedSize];
|
||||||
if (disableImplicitHierarchyManagement) {
|
if (automaticallyManagesSubnodesDisabled) {
|
||||||
self.usesImplicitHierarchyManagement = NO; // Temporary flag for 1.9.x
|
self.automaticallyManagesSubnodes = NO; // Temporary flag for 1.9.x
|
||||||
}
|
}
|
||||||
|
|
||||||
ASLayoutableClearCurrentContext();
|
ASLayoutableClearCurrentContext();
|
||||||
@ -789,12 +788,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup pending layout transition for animation
|
// Setup pending layout transition for animation
|
||||||
// The pending layout transition needs to stay alive at least until applySubnodeInsertions did finish execute as
|
_pendingLayoutTransition = [[ASLayoutTransition alloc] initWithNode:self
|
||||||
// it can happen that with Implicit Hierarchy Management new nodes gonna be added that internally call setNeedsLayout
|
pendingLayout:newLayout
|
||||||
// what will invalidate and deallocate the transition in the middle of inserting nodes
|
previousLayout:previousLayout];
|
||||||
NS_VALID_UNTIL_END_OF_SCOPE ASLayoutTransition *pendingLayoutTransition = [[ASLayoutTransition alloc] initWithNode:self pendingLayout:newLayout previousLayout:previousLayout];
|
|
||||||
_pendingLayoutTransition = pendingLayoutTransition;
|
|
||||||
|
|
||||||
// Setup context for pending layout transition. we need to hold a strong reference to the context
|
// Setup context for pending layout transition. we need to hold a strong reference to the context
|
||||||
_pendingLayoutTransitionContext = [[_ASTransitionContext alloc] initWithAnimation:animated
|
_pendingLayoutTransitionContext = [[_ASTransitionContext alloc] initWithAnimation:animated
|
||||||
layoutDelegate:_pendingLayoutTransition
|
layoutDelegate:_pendingLayoutTransition
|
||||||
@ -806,12 +802,10 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
// Kick off animating the layout transition
|
// Kick off animating the layout transition
|
||||||
[self animateLayoutTransition:_pendingLayoutTransitionContext];
|
[self animateLayoutTransition:_pendingLayoutTransitionContext];
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
|
|
||||||
ASPerformBlockOnBackgroundThread(transitionBlock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelLayoutTransitionsInProgress
|
- (void)cancelLayoutTransition
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
if ([self _isTransitionInProgress]) {
|
if ([self _isTransitionInProgress]) {
|
||||||
@ -825,18 +819,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)usesImplicitHierarchyManagement
|
|
||||||
{
|
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
|
||||||
return _usesImplicitHierarchyManagement ? : [[self class] usesImplicitHierarchyManagement];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setUsesImplicitHierarchyManagement:(BOOL)value
|
|
||||||
{
|
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
|
||||||
_usesImplicitHierarchyManagement = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)_isTransitionInProgress
|
- (BOOL)_isTransitionInProgress
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
@ -864,16 +846,126 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
return (!_transitionInProgress || _transitionID != transitionID);
|
return (!_transitionInProgress || _transitionID != transitionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Layout Transition API / ASDisplayNode (Beta)
|
#pragma mark Layout Transition API
|
||||||
|
|
||||||
|
- (void)setDefaultLayoutTransitionDuration:(NSTimeInterval)defaultLayoutTransitionDuration
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
_defaultLayoutTransitionDuration = defaultLayoutTransitionDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSTimeInterval)defaultLayoutTransitionDuration
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
return _defaultLayoutTransitionDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDefaultLayoutTransitionDelay:(NSTimeInterval)defaultLayoutTransitionDelay
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
_defaultLayoutTransitionDelay = defaultLayoutTransitionDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSTimeInterval)defaultLayoutTransitionDelay
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
return _defaultLayoutTransitionDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDefaultLayoutTransitionOptions:(UIViewAnimationOptions)defaultLayoutTransitionOptions
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
_defaultLayoutTransitionOptions = defaultLayoutTransitionOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIViewAnimationOptions)defaultLayoutTransitionOptions
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
return _defaultLayoutTransitionOptions;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hook for subclasse to perform an animation based on the given ASContextTransitioning. By default this just layouts
|
* Hook for subclasse to perform an animation based on the given ASContextTransitioning. By default a fade in and out
|
||||||
* applies all subnodes without animation and calls completes the transition on the context.
|
* animation is provided.
|
||||||
*/
|
*/
|
||||||
- (void)animateLayoutTransition:(id<ASContextTransitioning>)context
|
- (void)animateLayoutTransition:(id<ASContextTransitioning>)context
|
||||||
{
|
{
|
||||||
|
if ([context isAnimated] == NO) {
|
||||||
[self __layoutSublayouts];
|
[self __layoutSublayouts];
|
||||||
[context completeTransition:YES];
|
[context completeTransition:YES];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASDisplayNode *node = self;
|
||||||
|
|
||||||
|
NSAssert(node.isNodeLoaded == YES, @"Invalid node state");
|
||||||
|
NSAssert([context isAnimated] == YES, @"Can't animate a non-animatable context");
|
||||||
|
|
||||||
|
NSArray<ASDisplayNode *> *removedSubnodes = [context removedSubnodes];
|
||||||
|
NSMutableArray<UIView *> *removedViews = [NSMutableArray array];
|
||||||
|
NSMutableArray<ASDisplayNode *> *insertedSubnodes = [[context insertedSubnodes] mutableCopy];
|
||||||
|
NSMutableArray<ASDisplayNode *> *movedSubnodes = [NSMutableArray array];
|
||||||
|
|
||||||
|
for (ASDisplayNode *subnode in [context subnodesForKey:ASTransitionContextToLayoutKey]) {
|
||||||
|
if ([insertedSubnodes containsObject:subnode] == NO) {
|
||||||
|
// This is an existing subnode, check if it is resized, moved or both
|
||||||
|
CGRect fromFrame = [context initialFrameForNode:subnode];
|
||||||
|
CGRect toFrame = [context finalFrameForNode:subnode];
|
||||||
|
if (CGSizeEqualToSize(fromFrame.size, toFrame.size) == NO) {
|
||||||
|
// To crossfade resized subnodes, show a snapshot of it on top.
|
||||||
|
// The node itself can then be treated as a newly-inserted one.
|
||||||
|
UIView *snapshotView = [subnode.view snapshotViewAfterScreenUpdates:YES];
|
||||||
|
snapshotView.frame = [context initialFrameForNode:subnode];
|
||||||
|
snapshotView.alpha = 1;
|
||||||
|
|
||||||
|
[node.view insertSubview:snapshotView aboveSubview:subnode.view];
|
||||||
|
[removedViews addObject:snapshotView];
|
||||||
|
|
||||||
|
[insertedSubnodes addObject:subnode];
|
||||||
|
}
|
||||||
|
if (CGPointEqualToPoint(fromFrame.origin, toFrame.origin) == NO) {
|
||||||
|
[movedSubnodes addObject:subnode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ASDisplayNode *insertedSubnode in insertedSubnodes) {
|
||||||
|
insertedSubnode.frame = [context finalFrameForNode:insertedSubnode];
|
||||||
|
insertedSubnode.alpha = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[UIView animateWithDuration:self.defaultLayoutTransitionDuration delay:self.defaultLayoutTransitionDelay options:self.defaultLayoutTransitionOptions animations:^{
|
||||||
|
// Fade removed subnodes and views out
|
||||||
|
for (ASDisplayNode *removedSubnode in removedSubnodes) {
|
||||||
|
removedSubnode.alpha = 0;
|
||||||
|
}
|
||||||
|
for (UIView *removedView in removedViews) {
|
||||||
|
removedView.alpha = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fade inserted subnodes in
|
||||||
|
for (ASDisplayNode *insertedSubnode in insertedSubnodes) {
|
||||||
|
insertedSubnode.alpha = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update frame of self and moved subnodes
|
||||||
|
CGSize fromSize = [context layoutForKey:ASTransitionContextFromLayoutKey].size;
|
||||||
|
CGSize toSize = [context layoutForKey:ASTransitionContextToLayoutKey].size;
|
||||||
|
BOOL isResized = (CGSizeEqualToSize(fromSize, toSize) == NO);
|
||||||
|
if (isResized == YES) {
|
||||||
|
CGPoint position = node.frame.origin;
|
||||||
|
node.frame = CGRectMake(position.x, position.y, toSize.width, toSize.height);
|
||||||
|
}
|
||||||
|
for (ASDisplayNode *movedSubnode in movedSubnodes) {
|
||||||
|
movedSubnode.frame = [context finalFrameForNode:movedSubnode];
|
||||||
|
}
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
for (UIView *removedView in removedViews) {
|
||||||
|
[removedView removeFromSuperview];
|
||||||
|
}
|
||||||
|
// Subnode removals are automatically performed
|
||||||
|
[context completeTransition:finished];
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -885,7 +977,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
[_pendingLayoutTransition applySubnodeRemovals];
|
[_pendingLayoutTransition applySubnodeRemovals];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - _ASTransitionContextCompletionDelegate
|
#pragma mark _ASTransitionContextCompletionDelegate
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* After completeTransition: is called on the ASContextTransitioning object in animateLayoutTransition: this
|
* After completeTransition: is called on the ASContextTransitioning object in animateLayoutTransition: this
|
||||||
@ -920,8 +1012,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
*/
|
*/
|
||||||
- (void)_completeLayoutTransition:(ASLayoutTransition *)layoutTransition
|
- (void)_completeLayoutTransition:(ASLayoutTransition *)layoutTransition
|
||||||
{
|
{
|
||||||
// Layout transition is not supported for non implicit hierarchy managed nodes yet
|
// Layout transition is not supported for nodes that are not have automatic subnode management enabled
|
||||||
if (layoutTransition == nil || self.usesImplicitHierarchyManagement == NO) {
|
if (layoutTransition == nil || self.automaticallyManagesSubnodes == NO) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1087,7 +1179,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
|
||||||
// FIXME: Ideally we'd call this as soon as the node receives -setNeedsLayout
|
// FIXME: Ideally we'd call this as soon as the node receives -setNeedsLayout
|
||||||
// but implicit hierarchy management would require us to modify the node tree
|
// but automatic subnode management would require us to modify the node tree
|
||||||
// in the background on a loaded node, which isn't currently supported.
|
// in the background on a loaded node, which isn't currently supported.
|
||||||
if (_pendingViewState.hasSetNeedsLayout) {
|
if (_pendingViewState.hasSetNeedsLayout) {
|
||||||
[self __setNeedsLayout];
|
[self __setNeedsLayout];
|
||||||
@ -1883,7 +1975,7 @@ static NSInteger incrementIfFound(NSInteger i) {
|
|||||||
|
|
||||||
// If a node was added to a supernode, the supernode could be in a layout pending state. All of the hierarchy state
|
// If a node was added to a supernode, the supernode could be in a layout pending state. All of the hierarchy state
|
||||||
// properties related to the transition need to be copied over as well as propagated down the subtree.
|
// properties related to the transition need to be copied over as well as propagated down the subtree.
|
||||||
// This is especially important as with Implicit Hierarchy Management adding subnodes can happen while a transition
|
// This is especially important as with automatic subnode management, adding subnodes can happen while a transition
|
||||||
// is in fly
|
// is in fly
|
||||||
if (ASHierarchyStateIncludesLayoutPending(stateToEnterOrExit)) {
|
if (ASHierarchyStateIncludesLayoutPending(stateToEnterOrExit)) {
|
||||||
int32_t pendingTransitionId = newSupernode.pendingTransitionID;
|
int32_t pendingTransitionId = newSupernode.pendingTransitionID;
|
||||||
@ -1961,11 +2053,11 @@ static NSInteger incrementIfFound(NSInteger i) {
|
|||||||
_flags.implementsInstanceDrawRect || _flags.implementsInstanceImageDisplay;
|
_flags.implementsInstanceDrawRect || _flags.implementsInstanceImageDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to determine if it's save to call setNeedsDisplay on a layer without throwing away the content.
|
// Helper method to determine if it's safe to call setNeedsDisplay on a layer without throwing away the content.
|
||||||
// For details look at the comment on the canCallNeedsDisplayOfLayer flag
|
// For details look at the comment on the canCallSetNeedsDisplayOfLayer flag
|
||||||
- (BOOL)__canCallNeedsDisplayOfLayer
|
- (BOOL)__canCallSetNeedsDisplayOfLayer
|
||||||
{
|
{
|
||||||
return _flags.canCallNeedsDisplayOfLayer;
|
return _flags.canCallSetNeedsDisplayOfLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)placeholderShouldPersist
|
- (BOOL)placeholderShouldPersist
|
||||||
@ -2016,9 +2108,10 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
|||||||
|
|
||||||
ASDisplayNode *node = [layer asyncdisplaykit_node];
|
ASDisplayNode *node = [layer asyncdisplaykit_node];
|
||||||
|
|
||||||
if ([node __canCallNeedsDisplayOfLayer]) {
|
if (node.isSynchronous && [node __canCallSetNeedsDisplayOfLayer]) {
|
||||||
// Layers for UIKit components that are wrapped wtihin a node needs to be set to be displayed as the contents of
|
// Layers for UIKit components that are wrapped within a node needs to be set to be displayed as the contents of
|
||||||
// the layer get's cleared and would not be recreated otherwise
|
// the layer get's cleared and would not be recreated otherwise.
|
||||||
|
// We do not call this for _ASDisplayLayer as an optimization.
|
||||||
[layer setNeedsDisplay];
|
[layer setNeedsDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2602,7 +2695,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
|||||||
ASDisplayNodeAssertTrue(layout.size.width >= 0.0);
|
ASDisplayNodeAssertTrue(layout.size.width >= 0.0);
|
||||||
ASDisplayNodeAssertTrue(layout.size.height >= 0.0);
|
ASDisplayNodeAssertTrue(layout.size.height >= 0.0);
|
||||||
|
|
||||||
if (layoutTransition == nil || self.usesImplicitHierarchyManagement == NO) {
|
if (layoutTransition == nil || self.automaticallyManagesSubnodes == NO) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3175,6 +3268,36 @@ static const char *ASDisplayNodeAssociatedNodeKey = "ASAssociatedNode";
|
|||||||
|
|
||||||
@implementation ASDisplayNode (Deprecated)
|
@implementation ASDisplayNode (Deprecated)
|
||||||
|
|
||||||
|
- (void)transitionLayoutWithAnimation:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(void(^)())completion
|
||||||
|
{
|
||||||
|
[self transitionLayoutAnimated:animated measurementCompletion:completion];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
|
animated:(BOOL)animated
|
||||||
|
shouldMeasureAsync:(BOOL)shouldMeasureAsync
|
||||||
|
measurementCompletion:(void(^)())completion
|
||||||
|
{
|
||||||
|
[self transitionLayoutWithSizeRange:constrainedSize animated:animated measurementCompletion:completion];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cancelLayoutTransitionsInProgress
|
||||||
|
{
|
||||||
|
[self cancelLayoutTransition];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)usesImplicitHierarchyManagement
|
||||||
|
{
|
||||||
|
return self.automaticallyManagesSubnodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setUsesImplicitHierarchyManagement:(BOOL)enabled
|
||||||
|
{
|
||||||
|
self.automaticallyManagesSubnodes = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setPlaceholderFadesOut:(BOOL)placeholderFadesOut
|
- (void)setPlaceholderFadesOut:(BOOL)placeholderFadesOut
|
||||||
{
|
{
|
||||||
self.placeholderFadeDuration = placeholderFadesOut ? 0.1 : 0.0;
|
self.placeholderFadeDuration = placeholderFadesOut ? 0.1 : 0.0;
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#import "ASEditableTextNode.h"
|
#import "ASEditableTextNode.h"
|
||||||
|
|
||||||
#import <objc/message.h>
|
#import <objc/message.h>
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
#import "ASEqualityHelpers.h"
|
#import "ASEqualityHelpers.h"
|
||||||
@ -238,9 +239,9 @@
|
|||||||
{
|
{
|
||||||
ASTextKitComponents *displayedComponents = [self isDisplayingPlaceholder] ? _placeholderTextKitComponents : _textKitComponents;
|
ASTextKitComponents *displayedComponents = [self isDisplayingPlaceholder] ? _placeholderTextKitComponents : _textKitComponents;
|
||||||
CGSize textSize = [displayedComponents sizeForConstrainedWidth:constrainedSize.width];
|
CGSize textSize = [displayedComponents sizeForConstrainedWidth:constrainedSize.width];
|
||||||
CGFloat width = ceilf(textSize.width + _textContainerInset.left + _textContainerInset.right);
|
CGFloat width = std::ceil(textSize.width + _textContainerInset.left + _textContainerInset.right);
|
||||||
CGFloat height = ceilf(textSize.height + _textContainerInset.top + _textContainerInset.bottom);
|
CGFloat height = std::ceil(textSize.height + _textContainerInset.top + _textContainerInset.bottom);
|
||||||
return CGSizeMake(fminf(width, constrainedSize.width), fminf(height, constrainedSize.height));
|
return CGSizeMake(std::fmin(width, constrainedSize.width), std::fmin(height, constrainedSize.height));
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)layout
|
- (void)layout
|
||||||
|
|||||||
@ -12,7 +12,10 @@
|
|||||||
|
|
||||||
#if TARGET_OS_TV
|
#if TARGET_OS_TV
|
||||||
#import "ASImageNode+tvOS.h"
|
#import "ASImageNode+tvOS.h"
|
||||||
|
|
||||||
#import <GLKit/GLKit.h>
|
#import <GLKit/GLKit.h>
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
#import "ASDisplayNodeExtras.h"
|
#import "ASDisplayNodeExtras.h"
|
||||||
|
|
||||||
@implementation ASImageNode (tvOS)
|
@implementation ASImageNode (tvOS)
|
||||||
@ -75,8 +78,8 @@
|
|||||||
// BUT we apply our transforms to *view since we want to apply
|
// BUT we apply our transforms to *view since we want to apply
|
||||||
// the transforms to the root view (L: 107)
|
// the transforms to the root view (L: 107)
|
||||||
CGPoint point = [touch locationInView:self.view];
|
CGPoint point = [touch locationInView:self.view];
|
||||||
float pitch = 0;
|
CGFloat pitch = 0;
|
||||||
float yaw = 0;
|
CGFloat yaw = 0;
|
||||||
BOOL topHalf = NO;
|
BOOL topHalf = NO;
|
||||||
if (point.y > CGRectGetHeight(self.view.frame)) {
|
if (point.y > CGRectGetHeight(self.view.frame)) {
|
||||||
pitch = 15;
|
pitch = 15;
|
||||||
@ -100,7 +103,7 @@
|
|||||||
if (yaw > 0) {
|
if (yaw > 0) {
|
||||||
yaw = -yaw;
|
yaw = -yaw;
|
||||||
} else {
|
} else {
|
||||||
yaw = fabsf(yaw);
|
yaw = fabs(yaw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -85,7 +85,7 @@ typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image);
|
|||||||
*
|
*
|
||||||
* @discussion This value defines a rectangle that is to be featured by the
|
* @discussion This value defines a rectangle that is to be featured by the
|
||||||
* receiver. The rectangle is specified as a "unit rectangle," using
|
* receiver. The rectangle is specified as a "unit rectangle," using
|
||||||
* percentages of the source image's width and height, e.g. CGRectMake(0.5, 0,
|
* fractions of the source image's width and height, e.g. CGRectMake(0.5, 0,
|
||||||
* 0.5, 1.0) will feature the full right half a photo. If the cropRect is
|
* 0.5, 1.0) will feature the full right half a photo. If the cropRect is
|
||||||
* empty, the content mode of the receiver will be used to determine its
|
* empty, the content mode of the receiver will be used to determine its
|
||||||
* dimensions, and only the cropRect's origin will be used for positioning. The
|
* dimensions, and only the cropRect's origin will be used for positioning. The
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#import "ASImageNode.h"
|
#import "ASImageNode.h"
|
||||||
|
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
#import "_ASDisplayLayer.h"
|
#import "_ASDisplayLayer.h"
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
@ -52,9 +54,9 @@ struct ASImageNodeDrawParameters {
|
|||||||
@property CGRect imageDrawRect;
|
@property CGRect imageDrawRect;
|
||||||
@property BOOL isOpaque;
|
@property BOOL isOpaque;
|
||||||
@property (nonatomic, strong) UIColor *backgroundColor;
|
@property (nonatomic, strong) UIColor *backgroundColor;
|
||||||
@property ASDisplayNodeContextModifier preContextBlock;
|
@property (nonatomic, copy) ASDisplayNodeContextModifier preContextBlock;
|
||||||
@property ASDisplayNodeContextModifier postContextBlock;
|
@property (nonatomic, copy) ASDisplayNodeContextModifier postContextBlock;
|
||||||
@property asimagenode_modification_block_t imageModificationBlock;
|
@property (nonatomic, copy) asimagenode_modification_block_t imageModificationBlock;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -317,7 +319,7 @@ struct ASImageNodeDrawParameters {
|
|||||||
|
|
||||||
CGSize imageSize = image.size;
|
CGSize imageSize = image.size;
|
||||||
CGSize imageSizeInPixels = CGSizeMake(imageSize.width * image.scale, imageSize.height * image.scale);
|
CGSize imageSizeInPixels = CGSizeMake(imageSize.width * image.scale, imageSize.height * image.scale);
|
||||||
CGSize boundsSizeInPixels = CGSizeMake(floorf(bounds.size.width * contentsScale), floorf(bounds.size.height * contentsScale));
|
CGSize boundsSizeInPixels = CGSizeMake(std::floor(bounds.size.width * contentsScale), std::floor(bounds.size.height * contentsScale));
|
||||||
|
|
||||||
if (_debugLabelNode) {
|
if (_debugLabelNode) {
|
||||||
CGFloat pixelCountRatio = (imageSizeInPixels.width * imageSizeInPixels.height) / (boundsSizeInPixels.width * boundsSizeInPixels.height);
|
CGFloat pixelCountRatio = (imageSizeInPixels.width * imageSizeInPixels.height) / (boundsSizeInPixels.width * boundsSizeInPixels.height);
|
||||||
|
|||||||
@ -70,6 +70,12 @@ typedef NS_OPTIONS(NSUInteger, ASMapNodeShowAnnotationsOptions)
|
|||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) ASMapNodeShowAnnotationsOptions showAnnotationsOptions;
|
@property (nonatomic, assign) ASMapNodeShowAnnotationsOptions showAnnotationsOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract The block which should return annotation image for static map based on provided annotation.
|
||||||
|
* @discussion This block is executed on an arbitrary serial queue. If this block is nil, standard pin is used.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, copy, nullable) UIImage * _Nullable (^imageForStaticMapAnnotationBlock)(id<MKAnnotation> annotation, CGPoint *centerOffset);
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@ -10,6 +10,9 @@
|
|||||||
|
|
||||||
#if TARGET_OS_IOS
|
#if TARGET_OS_IOS
|
||||||
#import "ASMapNode.h"
|
#import "ASMapNode.h"
|
||||||
|
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
#import "ASDisplayNodeExtras.h"
|
#import "ASDisplayNodeExtras.h"
|
||||||
@ -164,6 +167,14 @@
|
|||||||
self.options = options;
|
self.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setMapDelegate:(id<MKMapViewDelegate>)mapDelegate {
|
||||||
|
_mapDelegate = mapDelegate;
|
||||||
|
|
||||||
|
if (_mapView) {
|
||||||
|
_mapView.delegate = mapDelegate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Snapshotter
|
#pragma mark - Snapshotter
|
||||||
|
|
||||||
- (void)takeSnapshot
|
- (void)takeSnapshot
|
||||||
@ -206,15 +217,27 @@
|
|||||||
UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
|
UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
|
||||||
[image drawAtPoint:CGPointZero];
|
[image drawAtPoint:CGPointZero];
|
||||||
|
|
||||||
// Get a standard annotation view pin. Future implementations should use a custom annotation image property.
|
UIImage *pinImage;
|
||||||
MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""];
|
CGPoint pinCenterOffset = CGPointZero;
|
||||||
UIImage *pinImage = pin.image;
|
|
||||||
CGSize pinSize = pin.bounds.size;
|
// Get a standard annotation view pin if there is no custom annotation block.
|
||||||
|
if (!strongSelf.imageForStaticMapAnnotationBlock) {
|
||||||
|
pinImage = [strongSelf.class defaultPinImageWithCenterOffset:&pinCenterOffset];
|
||||||
|
}
|
||||||
|
|
||||||
for (id<MKAnnotation> annotation in annotations) {
|
for (id<MKAnnotation> annotation in annotations) {
|
||||||
|
if (strongSelf.imageForStaticMapAnnotationBlock) {
|
||||||
|
// Get custom annotation image from custom annotation block.
|
||||||
|
pinImage = strongSelf.imageForStaticMapAnnotationBlock(annotation, &pinCenterOffset);
|
||||||
|
if (!pinImage) {
|
||||||
|
// just for case block returned nil, which can happen
|
||||||
|
pinImage = [strongSelf.class defaultPinImageWithCenterOffset:&pinCenterOffset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CGPoint point = [snapshot pointForCoordinate:annotation.coordinate];
|
CGPoint point = [snapshot pointForCoordinate:annotation.coordinate];
|
||||||
if (CGRectContainsPoint(finalImageRect, point)) {
|
if (CGRectContainsPoint(finalImageRect, point)) {
|
||||||
CGPoint pinCenterOffset = pin.centerOffset;
|
CGSize pinSize = pinImage.size;
|
||||||
point.x -= pinSize.width / 2.0;
|
point.x -= pinSize.width / 2.0;
|
||||||
point.y -= pinSize.height / 2.0;
|
point.y -= pinSize.height / 2.0;
|
||||||
point.x += pinCenterOffset.x;
|
point.x += pinCenterOffset.x;
|
||||||
@ -232,6 +255,17 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (UIImage *)defaultPinImageWithCenterOffset:(CGPoint *)centerOffset
|
||||||
|
{
|
||||||
|
static MKAnnotationView *pin;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""];
|
||||||
|
});
|
||||||
|
*centerOffset = pin.centerOffset;
|
||||||
|
return pin.image;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setUpSnapshotter
|
- (void)setUpSnapshotter
|
||||||
{
|
{
|
||||||
_snapshotter = [[MKMapSnapshotter alloc] initWithOptions:self.options];
|
_snapshotter = [[MKMapSnapshotter alloc] initWithOptions:self.options];
|
||||||
@ -320,16 +354,16 @@
|
|||||||
CLLocationCoordinate2D bottomRightCoord = CLLocationCoordinate2DMake(90, -180);
|
CLLocationCoordinate2D bottomRightCoord = CLLocationCoordinate2DMake(90, -180);
|
||||||
|
|
||||||
for (id<MKAnnotation> annotation in annotations) {
|
for (id<MKAnnotation> annotation in annotations) {
|
||||||
topLeftCoord = CLLocationCoordinate2DMake(fmax(topLeftCoord.latitude, annotation.coordinate.latitude),
|
topLeftCoord = CLLocationCoordinate2DMake(std::fmax(topLeftCoord.latitude, annotation.coordinate.latitude),
|
||||||
fmin(topLeftCoord.longitude, annotation.coordinate.longitude));
|
std::fmin(topLeftCoord.longitude, annotation.coordinate.longitude));
|
||||||
bottomRightCoord = CLLocationCoordinate2DMake(fmin(bottomRightCoord.latitude, annotation.coordinate.latitude),
|
bottomRightCoord = CLLocationCoordinate2DMake(std::fmin(bottomRightCoord.latitude, annotation.coordinate.latitude),
|
||||||
fmax(bottomRightCoord.longitude, annotation.coordinate.longitude));
|
std::fmax(bottomRightCoord.longitude, annotation.coordinate.longitude));
|
||||||
}
|
}
|
||||||
|
|
||||||
MKCoordinateRegion region = MKCoordinateRegionMake(CLLocationCoordinate2DMake(topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5,
|
MKCoordinateRegion region = MKCoordinateRegionMake(CLLocationCoordinate2DMake(topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5,
|
||||||
topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5),
|
topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5),
|
||||||
MKCoordinateSpanMake(fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 2,
|
MKCoordinateSpanMake(std::fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 2,
|
||||||
fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 2));
|
std::fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 2));
|
||||||
|
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,8 @@
|
|||||||
@class ASPagerNode;
|
@class ASPagerNode;
|
||||||
@class ASPagerFlowLayout;
|
@class ASPagerFlowLayout;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
#define ASPagerNodeDataSource ASPagerDataSource
|
#define ASPagerNodeDataSource ASPagerDataSource
|
||||||
@protocol ASPagerDataSource <NSObject>
|
@protocol ASPagerDataSource <NSObject>
|
||||||
|
|
||||||
@ -52,19 +54,21 @@
|
|||||||
*/
|
*/
|
||||||
- (ASCellNodeBlock)pagerNode:(ASPagerNode *)pagerNode nodeBlockAtIndex:(NSInteger)index;
|
- (ASCellNodeBlock)pagerNode:(ASPagerNode *)pagerNode nodeBlockAtIndex:(NSInteger)index;
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the constrained size range for measuring the node at the index path.
|
|
||||||
*
|
|
||||||
* @param pagerNode The sender.
|
|
||||||
* @param indexPath The index path of the node.
|
|
||||||
* @returns A constrained size range for layout the node at this index path.
|
|
||||||
*/
|
|
||||||
- (ASSizeRange)pagerNode:(ASPagerNode *)pagerNode constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@protocol ASPagerDelegate <ASCollectionDelegate>
|
@protocol ASPagerDelegate <ASCollectionDelegate>
|
||||||
|
|
||||||
|
@optional
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the constrained size range for measuring the node at the index.
|
||||||
|
*
|
||||||
|
* @param pagerNode The sender.
|
||||||
|
* @param index The index of the node.
|
||||||
|
* @returns A constrained size range for layout the node at this index.
|
||||||
|
*/
|
||||||
|
- (ASSizeRange)pagerNode:(ASPagerNode *)pagerNode constrainedSizeForNodeAtIndex:(NSInteger)index;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface ASPagerNode : ASCollectionNode
|
@interface ASPagerNode : ASCollectionNode
|
||||||
@ -82,14 +86,15 @@
|
|||||||
/**
|
/**
|
||||||
* Data Source is required, and uses a different protocol from ASCollectionNode.
|
* Data Source is required, and uses a different protocol from ASCollectionNode.
|
||||||
*/
|
*/
|
||||||
- (void)setDataSource:(id <ASPagerDataSource>)dataSource;
|
- (void)setDataSource:(nullable id <ASPagerDataSource>)dataSource;
|
||||||
- (id <ASPagerDataSource>)dataSource;
|
- (nullable id <ASPagerDataSource>)dataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate is optional, and uses the same protocol as ASCollectionNode.
|
* Delegate is optional.
|
||||||
* This includes UIScrollViewDelegate as well as most methods from UICollectionViewDelegate, like willDisplay...
|
* This includes UIScrollViewDelegate as well as most methods from UICollectionViewDelegate, like willDisplay...
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, weak) id <ASPagerDelegate> delegate;
|
- (void)setDelegate:(nullable id <ASPagerDelegate>)delegate;
|
||||||
|
- (nullable id <ASPagerDelegate>)delegate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The underlying ASCollectionView object.
|
* The underlying ASCollectionView object.
|
||||||
@ -112,3 +117,5 @@
|
|||||||
- (ASCellNode *)nodeForPageAtIndex:(NSInteger)index;
|
- (ASCellNode *)nodeForPageAtIndex:(NSInteger)index;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@ -15,18 +15,23 @@
|
|||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
#import "ASPagerFlowLayout.h"
|
#import "ASPagerFlowLayout.h"
|
||||||
|
|
||||||
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionViewDelegateFlowLayout, ASDelegateProxyInterceptor>
|
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionDelegate, ASCollectionViewDelegateFlowLayout, ASDelegateProxyInterceptor>
|
||||||
{
|
{
|
||||||
ASPagerFlowLayout *_flowLayout;
|
ASPagerFlowLayout *_flowLayout;
|
||||||
ASPagerNodeProxy *_proxy;
|
|
||||||
__weak id <ASPagerNodeDataSource> _pagerDataSource;
|
__weak id <ASPagerDataSource> _pagerDataSource;
|
||||||
|
ASPagerNodeProxy *_proxyDataSource;
|
||||||
BOOL _pagerDataSourceImplementsNodeBlockAtIndex;
|
BOOL _pagerDataSourceImplementsNodeBlockAtIndex;
|
||||||
BOOL _pagerDataSourceImplementsConstrainedSizeForNode;
|
|
||||||
|
__weak id <ASPagerDelegate> _pagerDelegate;
|
||||||
|
ASPagerNodeProxy *_proxyDelegate;
|
||||||
|
BOOL _pagerDelegateImplementsConstrainedSizeForNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ASPagerNode
|
@implementation ASPagerNode
|
||||||
|
|
||||||
@dynamic view, delegate, dataSource;
|
@dynamic view, delegate, dataSource;
|
||||||
|
|
||||||
#pragma mark - Lifecycle
|
#pragma mark - Lifecycle
|
||||||
@ -58,6 +63,8 @@
|
|||||||
[super didLoad];
|
[super didLoad];
|
||||||
|
|
||||||
ASCollectionView *cv = self.view;
|
ASCollectionView *cv = self.view;
|
||||||
|
cv.asyncDataSource = (id<ASCollectionViewDataSource>)_proxyDataSource ?: self;
|
||||||
|
cv.asyncDelegate = (id<ASCollectionViewDelegate>)_proxyDelegate ?: self;
|
||||||
#if TARGET_OS_IOS
|
#if TARGET_OS_IOS
|
||||||
cv.pagingEnabled = YES;
|
cv.pagingEnabled = YES;
|
||||||
cv.scrollsToTop = NO;
|
cv.scrollsToTop = NO;
|
||||||
@ -122,9 +129,10 @@
|
|||||||
|
|
||||||
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
if (_pagerDataSourceImplementsConstrainedSizeForNode) {
|
if (_pagerDelegateImplementsConstrainedSizeForNode) {
|
||||||
return [_pagerDataSource pagerNode:self constrainedSizeForNodeAtIndexPath:indexPath];
|
return [_pagerDelegate pagerNode:self constrainedSizeForNodeAtIndex:indexPath.item];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ASSizeRangeMake(CGSizeZero, self.view.bounds.size);
|
return ASSizeRangeMake(CGSizeZero, self.view.bounds.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,26 +143,38 @@
|
|||||||
return _pagerDataSource;
|
return _pagerDataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDataSource:(id <ASPagerDataSource>)pagerDataSource
|
- (void)setDataSource:(id <ASPagerDataSource>)dataSource
|
||||||
{
|
{
|
||||||
if (pagerDataSource != _pagerDataSource) {
|
if (dataSource != _pagerDataSource) {
|
||||||
_pagerDataSource = pagerDataSource;
|
_pagerDataSource = dataSource;
|
||||||
|
|
||||||
_pagerDataSourceImplementsNodeBlockAtIndex = [_pagerDataSource respondsToSelector:@selector(pagerNode:nodeBlockAtIndex:)];
|
_pagerDataSourceImplementsNodeBlockAtIndex = [_pagerDataSource respondsToSelector:@selector(pagerNode:nodeBlockAtIndex:)];
|
||||||
// Data source must implement pagerNode:nodeBlockAtIndex: or pagerNode:nodeAtIndex:
|
// Data source must implement pagerNode:nodeBlockAtIndex: or pagerNode:nodeAtIndex:
|
||||||
ASDisplayNodeAssertTrue(_pagerDataSourceImplementsNodeBlockAtIndex || [_pagerDataSource respondsToSelector:@selector(pagerNode:nodeAtIndex:)]);
|
ASDisplayNodeAssertTrue(_pagerDataSourceImplementsNodeBlockAtIndex || [_pagerDataSource respondsToSelector:@selector(pagerNode:nodeAtIndex:)]);
|
||||||
|
|
||||||
_pagerDataSourceImplementsConstrainedSizeForNode = [_pagerDataSource respondsToSelector:@selector(pagerNode:constrainedSizeForNodeAtIndexPath:)];
|
_proxyDataSource = dataSource ? [[ASPagerNodeProxy alloc] initWithTarget:dataSource interceptor:self] : nil;
|
||||||
|
|
||||||
_proxy = pagerDataSource ? [[ASPagerNodeProxy alloc] initWithTarget:pagerDataSource interceptor:self] : nil;
|
super.dataSource = (id <ASCollectionDataSource>)_proxyDataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super.dataSource = (id <ASCollectionDataSource>)_proxy;
|
- (void)setDelegate:(id<ASPagerDelegate>)delegate
|
||||||
|
{
|
||||||
|
if (delegate != _pagerDelegate) {
|
||||||
|
_pagerDelegate = delegate;
|
||||||
|
|
||||||
|
_pagerDelegateImplementsConstrainedSizeForNode = [_pagerDelegate respondsToSelector:@selector(pagerNode:constrainedSizeForNodeAtIndex:)];
|
||||||
|
|
||||||
|
_proxyDelegate = delegate ? [[ASPagerNodeProxy alloc] initWithTarget:delegate interceptor:self] : nil;
|
||||||
|
|
||||||
|
super.delegate = (id <ASCollectionDelegate>)_proxyDelegate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy
|
- (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy
|
||||||
{
|
{
|
||||||
[self setDataSource:nil];
|
[self setDataSource:nil];
|
||||||
|
[self setDelegate:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
#import "ASCellNode+Internal.h"
|
#import "ASCellNode+Internal.h"
|
||||||
|
#import "AsyncDisplayKit+Debug.h"
|
||||||
|
|
||||||
#pragma mark - _ASTablePendingState
|
#pragma mark - _ASTablePendingState
|
||||||
|
|
||||||
@ -125,6 +126,12 @@
|
|||||||
[self.view clearFetchedData];
|
[self.view clearFetchedData];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState
|
||||||
|
{
|
||||||
|
[super interfaceStateDidChange:newState fromState:oldState];
|
||||||
|
[ASRangeController layoutDebugOverlayIfNeeded];
|
||||||
|
}
|
||||||
|
|
||||||
#if ASRangeControllerLoggingEnabled
|
#if ASRangeControllerLoggingEnabled
|
||||||
- (void)visibleStateDidChange:(BOOL)isVisible
|
- (void)visibleStateDidChange:(BOOL)isVisible
|
||||||
{
|
{
|
||||||
|
|||||||
@ -17,7 +17,6 @@
|
|||||||
#import "ASChangeSetDataController.h"
|
#import "ASChangeSetDataController.h"
|
||||||
#import "ASDelegateProxy.h"
|
#import "ASDelegateProxy.h"
|
||||||
#import "ASDisplayNodeExtras.h"
|
#import "ASDisplayNodeExtras.h"
|
||||||
#import "ASDisplayNode+Beta.h"
|
|
||||||
#import "ASDisplayNode+FrameworkPrivate.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
#import "ASLayout.h"
|
#import "ASLayout.h"
|
||||||
@ -937,6 +936,11 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
return ASInterfaceStateForDisplayNode(self.tableNode, self.window);
|
return ASInterfaceStateForDisplayNode(self.tableNode, self.window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *)nameForRangeControllerDataSource
|
||||||
|
{
|
||||||
|
return self.asyncDataSource ? NSStringFromClass([self.asyncDataSource class]) : NSStringFromClass([self class]);
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - ASRangeControllerDelegate
|
#pragma mark - ASRangeControllerDelegate
|
||||||
|
|
||||||
- (void)didBeginUpdatesInRangeController:(ASRangeController *)rangeController
|
- (void)didBeginUpdatesInRangeController:(ASRangeController *)rangeController
|
||||||
@ -1159,8 +1163,12 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
|
|
||||||
- (void)didLayoutSubviewsOfTableViewCell:(_ASTableViewCell *)tableViewCell
|
- (void)didLayoutSubviewsOfTableViewCell:(_ASTableViewCell *)tableViewCell
|
||||||
{
|
{
|
||||||
CGFloat contentViewWidth = tableViewCell.contentView.bounds.size.width;
|
|
||||||
ASCellNode *node = tableViewCell.node;
|
ASCellNode *node = tableViewCell.node;
|
||||||
|
if (node == nil) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGFloat contentViewWidth = tableViewCell.contentView.bounds.size.width;
|
||||||
ASSizeRange constrainedSize = node.constrainedSizeForCalculatedLayout;
|
ASSizeRange constrainedSize = node.constrainedSizeForCalculatedLayout;
|
||||||
|
|
||||||
// Table view cells should always fill its content view width.
|
// Table view cells should always fill its content view width.
|
||||||
|
|||||||
@ -31,6 +31,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
@property (nullable, nonatomic, copy) NSTextStorage * (^textStorageCreationBlock)(NSAttributedString *_Nullable attributedString);
|
@property (nullable, nonatomic, copy) NSTextStorage * (^textStorageCreationBlock)(NSAttributedString *_Nullable attributedString);
|
||||||
|
|
||||||
|
/**
|
||||||
|
@abstract Text margins for text laid out in the text node.
|
||||||
|
@discussion defaults to UIEdgeInsetsZero.
|
||||||
|
This property can be useful for handling text which does not fit within the view by default. An example: like UILabel,
|
||||||
|
ASTextNode will clip the left and right of the string "judar" if it's rendered in an italicised font.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) UIEdgeInsets textContainerInset;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#import "ASTextNode+Beta.h"
|
#import "ASTextNode+Beta.h"
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
#import "_ASDisplayLayer.h"
|
#import "_ASDisplayLayer.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
@ -26,6 +27,8 @@
|
|||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
#import "ASLayout.h"
|
#import "ASLayout.h"
|
||||||
|
|
||||||
|
#import "CGRect+ASConvenience.h"
|
||||||
|
|
||||||
static const NSTimeInterval ASTextNodeHighlightFadeOutDuration = 0.15;
|
static const NSTimeInterval ASTextNodeHighlightFadeOutDuration = 0.15;
|
||||||
static const NSTimeInterval ASTextNodeHighlightFadeInDuration = 0.1;
|
static const NSTimeInterval ASTextNodeHighlightFadeInDuration = 0.1;
|
||||||
static const CGFloat ASTextNodeHighlightLightOpacity = 0.11;
|
static const CGFloat ASTextNodeHighlightLightOpacity = 0.11;
|
||||||
@ -44,9 +47,12 @@ struct ASTextNodeDrawParameter {
|
|||||||
@implementation ASTextNode {
|
@implementation ASTextNode {
|
||||||
CGSize _shadowOffset;
|
CGSize _shadowOffset;
|
||||||
CGColorRef _shadowColor;
|
CGColorRef _shadowColor;
|
||||||
|
UIColor *_cachedShadowUIColor;
|
||||||
CGFloat _shadowOpacity;
|
CGFloat _shadowOpacity;
|
||||||
CGFloat _shadowRadius;
|
CGFloat _shadowRadius;
|
||||||
|
|
||||||
|
UIEdgeInsets _textContainerInset;
|
||||||
|
|
||||||
NSArray *_exclusionPaths;
|
NSArray *_exclusionPaths;
|
||||||
|
|
||||||
NSAttributedString *_composedTruncationText;
|
NSAttributedString *_composedTruncationText;
|
||||||
@ -211,7 +217,15 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
|||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
|
||||||
if (_renderer == nil) {
|
if (_renderer == nil) {
|
||||||
CGSize constrainedSize = _constrainedSize.width != -INFINITY ? _constrainedSize : bounds.size;
|
CGSize constrainedSize;
|
||||||
|
if (_constrainedSize.width != -INFINITY) {
|
||||||
|
constrainedSize = _constrainedSize;
|
||||||
|
} else {
|
||||||
|
constrainedSize = bounds.size;
|
||||||
|
constrainedSize.width -= (_textContainerInset.left + _textContainerInset.right);
|
||||||
|
constrainedSize.height -= (_textContainerInset.top + _textContainerInset.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
_renderer = [[ASTextKitRenderer alloc] initWithTextKitAttributes:[self _rendererAttributes]
|
_renderer = [[ASTextKitRenderer alloc] initWithTextKitAttributes:[self _rendererAttributes]
|
||||||
constrainedSize:constrainedSize];
|
constrainedSize:constrainedSize];
|
||||||
}
|
}
|
||||||
@ -232,6 +246,10 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
|||||||
.pointSizeScaleFactors = self.pointSizeScaleFactors,
|
.pointSizeScaleFactors = self.pointSizeScaleFactors,
|
||||||
.layoutManagerCreationBlock = self.layoutManagerCreationBlock,
|
.layoutManagerCreationBlock = self.layoutManagerCreationBlock,
|
||||||
.textStorageCreationBlock = self.textStorageCreationBlock,
|
.textStorageCreationBlock = self.textStorageCreationBlock,
|
||||||
|
.shadowOffset = _shadowOffset,
|
||||||
|
.shadowColor = _cachedShadowUIColor,
|
||||||
|
.shadowOpacity = _shadowOpacity,
|
||||||
|
.shadowRadius = _shadowRadius
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,6 +291,24 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
|||||||
|
|
||||||
#pragma mark - Layout and Sizing
|
#pragma mark - Layout and Sizing
|
||||||
|
|
||||||
|
- (void)setTextContainerInset:(UIEdgeInsets)textContainerInset
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
|
||||||
|
BOOL needsUpdate = !UIEdgeInsetsEqualToEdgeInsets(textContainerInset, _textContainerInset);
|
||||||
|
if (needsUpdate) {
|
||||||
|
_textContainerInset = textContainerInset;
|
||||||
|
[self invalidateCalculatedLayout];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIEdgeInsets)textContainerInset
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
return _textContainerInset;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)_needInvalidateRendererForBoundsSize:(CGSize)boundsSize
|
- (BOOL)_needInvalidateRendererForBoundsSize:(CGSize)boundsSize
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
@ -285,6 +321,10 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
|||||||
// a new one. However, there are common cases where the constrained size doesn't need to be the same as calculated.
|
// a new one. However, there are common cases where the constrained size doesn't need to be the same as calculated.
|
||||||
CGSize rendererConstrainedSize = _renderer.constrainedSize;
|
CGSize rendererConstrainedSize = _renderer.constrainedSize;
|
||||||
|
|
||||||
|
//inset bounds
|
||||||
|
boundsSize.width -= _textContainerInset.left + _textContainerInset.right;
|
||||||
|
boundsSize.height -= _textContainerInset.top + _textContainerInset.bottom;
|
||||||
|
|
||||||
if (CGSizeEqualToSize(boundsSize, rendererConstrainedSize)) {
|
if (CGSizeEqualToSize(boundsSize, rendererConstrainedSize)) {
|
||||||
return NO;
|
return NO;
|
||||||
} else {
|
} else {
|
||||||
@ -315,9 +355,14 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
|||||||
|
|
||||||
if (layout != nil) {
|
if (layout != nil) {
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
if (CGSizeEqualToSize(_constrainedSize, layout.size) == NO) {
|
CGSize layoutSize = layout.size;
|
||||||
_constrainedSize = layout.size;
|
//Apply textContainerInset
|
||||||
_renderer.constrainedSize = layout.size;
|
layoutSize.width -= (_textContainerInset.left + _textContainerInset.right);
|
||||||
|
layoutSize.height -= (_textContainerInset.top + _textContainerInset.bottom);
|
||||||
|
|
||||||
|
if (CGSizeEqualToSize(_constrainedSize, layoutSize) == NO) {
|
||||||
|
_constrainedSize = layoutSize;
|
||||||
|
_renderer.constrainedSize = layoutSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,6 +374,10 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
|||||||
|
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
|
||||||
|
//remove textContainerInset
|
||||||
|
constrainedSize.width -= (_textContainerInset.left + _textContainerInset.right);
|
||||||
|
constrainedSize.height -= (_textContainerInset.top + _textContainerInset.bottom);
|
||||||
|
|
||||||
_constrainedSize = constrainedSize;
|
_constrainedSize = constrainedSize;
|
||||||
|
|
||||||
// Instead of invalidating the renderer, in case this is a new call with a different constrained size,
|
// Instead of invalidating the renderer, in case this is a new call with a different constrained size,
|
||||||
@ -347,6 +396,11 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
|||||||
self.descender *= _renderer.currentScaleFactor;
|
self.descender *= _renderer.currentScaleFactor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//add textContainerInset
|
||||||
|
size.width += (_textContainerInset.left + _textContainerInset.right);
|
||||||
|
size.height += (_textContainerInset.top + _textContainerInset.bottom);
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,6 +514,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
|||||||
|
|
||||||
CGContextSaveGState(context);
|
CGContextSaveGState(context);
|
||||||
|
|
||||||
|
CGContextTranslateCTM(context, _textContainerInset.left, _textContainerInset.top);
|
||||||
|
|
||||||
ASTextKitRenderer *renderer = [self _rendererWithBounds:drawParameterBounds];
|
ASTextKitRenderer *renderer = [self _rendererWithBounds:drawParameterBounds];
|
||||||
UIEdgeInsets shadowPadding = [self shadowPaddingWithRenderer:renderer];
|
UIEdgeInsets shadowPadding = [self shadowPaddingWithRenderer:renderer];
|
||||||
CGPoint boundsOrigin = drawParameterBounds.origin;
|
CGPoint boundsOrigin = drawParameterBounds.origin;
|
||||||
@ -519,7 +575,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
|||||||
|
|
||||||
[renderer enumerateTextIndexesAtPosition:point usingBlock:^(NSUInteger characterIndex, CGRect glyphBoundingRect, BOOL *stop) {
|
[renderer enumerateTextIndexesAtPosition:point usingBlock:^(NSUInteger characterIndex, CGRect glyphBoundingRect, BOOL *stop) {
|
||||||
CGPoint glyphLocation = CGPointMake(CGRectGetMidX(glyphBoundingRect), CGRectGetMidY(glyphBoundingRect));
|
CGPoint glyphLocation = CGPointMake(CGRectGetMidX(glyphBoundingRect), CGRectGetMidY(glyphBoundingRect));
|
||||||
CGFloat currentDistance = sqrtf(powf(point.x - glyphLocation.x, 2.f) + powf(point.y - glyphLocation.y, 2.f));
|
CGFloat currentDistance = std::sqrt(std::pow(point.x - glyphLocation.x, 2.f) + std::pow(point.y - glyphLocation.y, 2.f));
|
||||||
if (currentDistance >= minimumGlyphDistance) {
|
if (currentDistance >= minimumGlyphDistance) {
|
||||||
// If the distance computed from the touch to the glyph location is
|
// If the distance computed from the touch to the glyph location is
|
||||||
// not the minimum among the located link attributes, we can just skip
|
// not the minimum among the located link attributes, we can just skip
|
||||||
@ -727,6 +783,13 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
|||||||
for (NSValue *rectValue in highlightRects) {
|
for (NSValue *rectValue in highlightRects) {
|
||||||
UIEdgeInsets shadowPadding = _renderer.shadower.shadowPadding;
|
UIEdgeInsets shadowPadding = _renderer.shadower.shadowPadding;
|
||||||
CGRect rendererRect = ASTextNodeAdjustRenderRectForShadowPadding(rectValue.CGRectValue, shadowPadding);
|
CGRect rendererRect = ASTextNodeAdjustRenderRectForShadowPadding(rectValue.CGRectValue, shadowPadding);
|
||||||
|
|
||||||
|
// The rects returned from renderer don't have `textContainerInset`,
|
||||||
|
// as well as they are using the `constrainedSize` for layout,
|
||||||
|
// so we can simply increase the rect by insets to get the full blown layout.
|
||||||
|
rendererRect.size.width += _textContainerInset.left + _textContainerInset.right;
|
||||||
|
rendererRect.size.height += _textContainerInset.top + _textContainerInset.bottom;
|
||||||
|
|
||||||
CGRect highlightedRect = [self.layer convertRect:rendererRect toLayer:highlightTargetLayer];
|
CGRect highlightedRect = [self.layer convertRect:rendererRect toLayer:highlightTargetLayer];
|
||||||
|
|
||||||
// We set our overlay layer's frame to the bounds of the highlight target layer.
|
// We set our overlay layer's frame to the bounds of the highlight target layer.
|
||||||
@ -849,7 +912,7 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
|
|||||||
// FIXME: Replace this implementation with reusable CALayers that have .backgroundColor set.
|
// FIXME: Replace this implementation with reusable CALayers that have .backgroundColor set.
|
||||||
// This would completely eliminate the memory and performance cost of the backing store.
|
// This would completely eliminate the memory and performance cost of the backing store.
|
||||||
CGSize size = self.calculatedSize;
|
CGSize size = self.calculatedSize;
|
||||||
if (CGSizeEqualToSize(size, CGSizeZero)) {
|
if ((size.width * size.height) < CGFLOAT_EPSILON) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1043,7 +1106,11 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
|
|||||||
if (shadowColor != NULL) {
|
if (shadowColor != NULL) {
|
||||||
CGColorRetain(shadowColor);
|
CGColorRetain(shadowColor);
|
||||||
}
|
}
|
||||||
|
if (_shadowColor != NULL) {
|
||||||
|
CGColorRelease(_shadowColor);
|
||||||
|
}
|
||||||
_shadowColor = shadowColor;
|
_shadowColor = shadowColor;
|
||||||
|
_cachedShadowUIColor = [UIColor colorWithCGColor:shadowColor];
|
||||||
[self _invalidateRenderer];
|
[self _invalidateRenderer];
|
||||||
[self setNeedsDisplay];
|
[self setNeedsDisplay];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
#import <AsyncDisplayKit/ASButtonNode.h>
|
#import <AsyncDisplayKit/ASButtonNode.h>
|
||||||
#import <AsyncDisplayKit/ASNetworkImageNode.h>
|
#import <AsyncDisplayKit/ASNetworkImageNode.h>
|
||||||
|
|
||||||
@class AVAsset, AVPlayer, AVPlayerItem, AVVideoComposition, AVAudioMix;
|
@class AVAsset, AVPlayer, AVPlayerLayer, AVPlayerItem, AVVideoComposition, AVAudioMix;
|
||||||
@protocol ASVideoNodeDelegate;
|
@protocol ASVideoNodeDelegate;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -51,6 +51,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@property (nullable, nonatomic, strong, readwrite) AVAudioMix *audioMix;
|
@property (nullable, nonatomic, strong, readwrite) AVAudioMix *audioMix;
|
||||||
|
|
||||||
@property (nullable, nonatomic, strong, readonly) AVPlayer *player;
|
@property (nullable, nonatomic, strong, readonly) AVPlayer *player;
|
||||||
|
@property (nullable, nonatomic, strong, readonly) AVPlayerLayer *playerLayer;
|
||||||
@property (nullable, nonatomic, strong, readonly) AVPlayerItem *currentItem;
|
@property (nullable, nonatomic, strong, readonly) AVPlayerItem *currentItem;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,7 @@ static void *ASVideoNodeContext = &ASVideoNodeContext;
|
|||||||
static NSString * const kPlaybackLikelyToKeepUpKey = @"playbackLikelyToKeepUp";
|
static NSString * const kPlaybackLikelyToKeepUpKey = @"playbackLikelyToKeepUp";
|
||||||
static NSString * const kplaybackBufferEmpty = @"playbackBufferEmpty";
|
static NSString * const kplaybackBufferEmpty = @"playbackBufferEmpty";
|
||||||
static NSString * const kStatus = @"status";
|
static NSString * const kStatus = @"status";
|
||||||
|
static NSString * const kRate = @"rate";
|
||||||
|
|
||||||
@interface ASVideoNode ()
|
@interface ASVideoNode ()
|
||||||
{
|
{
|
||||||
@ -208,6 +209,25 @@ static NSString * const kStatus = @"status";
|
|||||||
[notificationCenter removeObserver:self name:AVPlayerItemNewErrorLogEntryNotification object:playerItem];
|
[notificationCenter removeObserver:self name:AVPlayerItemNewErrorLogEntryNotification object:playerItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)addPlayerObservers:(AVPlayer *)player
|
||||||
|
{
|
||||||
|
if (player == nil) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[player addObserver:self forKeyPath:kRate options:NSKeyValueObservingOptionNew context:ASVideoNodeContext];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) removePlayerObservers:(AVPlayer *)player
|
||||||
|
{
|
||||||
|
@try {
|
||||||
|
[player removeObserver:self forKeyPath:kRate context:ASVideoNodeContext];
|
||||||
|
}
|
||||||
|
@catch (NSException * __unused exception) {
|
||||||
|
NSLog(@"Unnecessary KVO removal");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)layout
|
- (void)layout
|
||||||
{
|
{
|
||||||
[super layout];
|
[super layout];
|
||||||
@ -267,6 +287,7 @@ static NSString * const kStatus = @"status";
|
|||||||
|
|
||||||
AVAssetImageGenerator *previewImageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
|
AVAssetImageGenerator *previewImageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
|
||||||
previewImageGenerator.appliesPreferredTrackTransform = YES;
|
previewImageGenerator.appliesPreferredTrackTransform = YES;
|
||||||
|
previewImageGenerator.videoComposition = _videoComposition;
|
||||||
|
|
||||||
[previewImageGenerator generateCGImagesAsynchronouslyForTimes:@[[NSValue valueWithCMTime:imageTime]]
|
[previewImageGenerator generateCGImagesAsynchronouslyForTimes:@[[NSValue valueWithCMTime:imageTime]]
|
||||||
completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) {
|
completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) {
|
||||||
@ -291,21 +312,28 @@ static NSString * const kStatus = @"status";
|
|||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
|
||||||
if (object != _currentPlayerItem) {
|
if (object == _currentPlayerItem) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([keyPath isEqualToString:kStatus]) {
|
if ([keyPath isEqualToString:kStatus]) {
|
||||||
if ([change[NSKeyValueChangeNewKey] integerValue] == AVPlayerItemStatusReadyToPlay) {
|
if ([change[NSKeyValueChangeNewKey] integerValue] == AVPlayerItemStatusReadyToPlay) {
|
||||||
|
if (self.playerState != ASVideoNodePlayerStatePlaying) {
|
||||||
self.playerState = ASVideoNodePlayerStateReadyToPlay;
|
self.playerState = ASVideoNodePlayerStateReadyToPlay;
|
||||||
|
}
|
||||||
// If we don't yet have a placeholder image update it now that we should have data available for it
|
// 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) {
|
if (self.image == nil && self.URL == nil) {
|
||||||
[self generatePlaceholderImage];
|
[self generatePlaceholderImage];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ([keyPath isEqualToString:kPlaybackLikelyToKeepUpKey]) {
|
} else if ([keyPath isEqualToString:kPlaybackLikelyToKeepUpKey]) {
|
||||||
|
BOOL likelyToKeepUp = [change[NSKeyValueChangeNewKey] boolValue];
|
||||||
|
if (likelyToKeepUp && self.playerState == ASVideoNodePlayerStatePlaying) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!likelyToKeepUp) {
|
||||||
|
self.playerState = ASVideoNodePlayerStateLoading;
|
||||||
|
} else if (self.playerState != ASVideoNodePlayerStateFinished) {
|
||||||
self.playerState = ASVideoNodePlayerStatePlaybackLikelyToKeepUpButNotPlaying;
|
self.playerState = ASVideoNodePlayerStatePlaybackLikelyToKeepUpButNotPlaying;
|
||||||
if (_shouldBePlaying && (_shouldAggressivelyRecoverFromStall || [change[NSKeyValueChangeNewKey] boolValue]) && ASInterfaceStateIncludesVisible(self.interfaceState)) {
|
}
|
||||||
|
if (_shouldBePlaying && (_shouldAggressivelyRecoverFromStall || likelyToKeepUp) && ASInterfaceStateIncludesVisible(self.interfaceState)) {
|
||||||
if (self.playerState == ASVideoNodePlayerStateLoading && _delegateFlags.delegateVideoNodeDidRecoverFromStall) {
|
if (self.playerState == ASVideoNodePlayerStateLoading && _delegateFlags.delegateVideoNodeDidRecoverFromStall) {
|
||||||
[_delegate videoNodeDidRecoverFromStall:self];
|
[_delegate videoNodeDidRecoverFromStall:self];
|
||||||
}
|
}
|
||||||
@ -316,6 +344,17 @@ static NSString * const kStatus = @"status";
|
|||||||
self.playerState = ASVideoNodePlayerStateLoading;
|
self.playerState = ASVideoNodePlayerStateLoading;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (object == _player) {
|
||||||
|
if ([keyPath isEqualToString:kRate]) {
|
||||||
|
if ([change[NSKeyValueChangeNewKey] floatValue] == 0.0) {
|
||||||
|
if (self.playerState == ASVideoNodePlayerStatePlaying) {
|
||||||
|
self.playerState = ASVideoNodePlayerStatePaused;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.playerState = ASVideoNodePlayerStatePlaying;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tapped
|
- (void)tapped
|
||||||
@ -345,14 +384,11 @@ static NSString * const kStatus = @"status";
|
|||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
AVAsset *asset = self.asset;
|
AVAsset *asset = self.asset;
|
||||||
// Return immediately if the asset is nil;
|
// Return immediately if the asset is nil;
|
||||||
if (asset == nil || self.playerState == ASVideoNodePlayerStateInitialLoading) {
|
if (asset == nil || self.playerState != ASVideoNodePlayerStateUnknown) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Nothing appears to prevent this method from sending the delegate notification / calling load on the asset
|
self.playerState = ASVideoNodePlayerStateLoading;
|
||||||
// multiple times, even after the asset is fully loaded and ready to play. There should probably be a playerState
|
|
||||||
// for NotLoaded or such, besides Unknown, so this can be easily checked before proceeding.
|
|
||||||
self.playerState = ASVideoNodePlayerStateInitialLoading;
|
|
||||||
if (_delegateFlags.delegateVideoNodeDidStartInitialLoading) {
|
if (_delegateFlags.delegateVideoNodeDidStartInitialLoading) {
|
||||||
[_delegate videoNodeDidStartInitialLoading:self];
|
[_delegate videoNodeDidStartInitialLoading:self];
|
||||||
}
|
}
|
||||||
@ -396,6 +432,7 @@ static NSString * const kStatus = @"status";
|
|||||||
|
|
||||||
self.player = nil;
|
self.player = nil;
|
||||||
self.currentItem = nil;
|
self.currentItem = nil;
|
||||||
|
self.playerState = ASVideoNodePlayerStateUnknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,6 +551,12 @@ static NSString * const kStatus = @"status";
|
|||||||
return _player;
|
return _player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (AVPlayerLayer *)playerLayer
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
return (AVPlayerLayer *)_playerNode.layer;
|
||||||
|
}
|
||||||
|
|
||||||
- (id<ASVideoNodeDelegate>)delegate{
|
- (id<ASVideoNodeDelegate>)delegate{
|
||||||
return _delegate;
|
return _delegate;
|
||||||
}
|
}
|
||||||
@ -603,12 +646,6 @@ static NSString * const kStatus = @"status";
|
|||||||
|
|
||||||
[_player play];
|
[_player play];
|
||||||
_shouldBePlaying = YES;
|
_shouldBePlaying = YES;
|
||||||
|
|
||||||
if (![self ready]) {
|
|
||||||
self.playerState = ASVideoNodePlayerStateLoading;
|
|
||||||
} else {
|
|
||||||
self.playerState = ASVideoNodePlayerStatePlaying;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)ready
|
- (BOOL)ready
|
||||||
@ -622,7 +659,6 @@ static NSString * const kStatus = @"status";
|
|||||||
if (![self isStateChangeValid:ASVideoNodePlayerStatePaused]) {
|
if (![self isStateChangeValid:ASVideoNodePlayerStatePaused]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.playerState = ASVideoNodePlayerStatePaused;
|
|
||||||
[_player pause];
|
[_player pause];
|
||||||
_shouldBePlaying = NO;
|
_shouldBePlaying = NO;
|
||||||
}
|
}
|
||||||
@ -731,9 +767,16 @@ static NSString * const kStatus = @"status";
|
|||||||
- (void)setPlayer:(AVPlayer *)player
|
- (void)setPlayer:(AVPlayer *)player
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
|
|
||||||
|
[self removePlayerObservers:_player];
|
||||||
|
|
||||||
_player = player;
|
_player = player;
|
||||||
player.muted = _muted;
|
player.muted = _muted;
|
||||||
((AVPlayerLayer *)_playerNode.layer).player = player;
|
((AVPlayerLayer *)_playerNode.layer).player = player;
|
||||||
|
|
||||||
|
if (player != nil) {
|
||||||
|
[self addPlayerObservers:player];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)shouldBePlaying
|
- (BOOL)shouldBePlaying
|
||||||
@ -755,6 +798,7 @@ static NSString * const kStatus = @"status";
|
|||||||
[_player removeTimeObserver:_timeObserver];
|
[_player removeTimeObserver:_timeObserver];
|
||||||
_timeObserver = nil;
|
_timeObserver = nil;
|
||||||
[self removePlayerItemObservers:_currentPlayerItem];
|
[self removePlayerItemObservers:_currentPlayerItem];
|
||||||
|
[self removePlayerObservers:_player];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -78,7 +78,7 @@ typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(C
|
|||||||
|
|
||||||
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil AS_UNAVAILABLE("ASViewController requires using -initWithNode:");
|
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil AS_UNAVAILABLE("ASViewController requires using -initWithNode:");
|
||||||
|
|
||||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder AS_UNAVAILABLE("ASViewController requires using -initWithNode:");
|
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder AS_UNAVAILABLE("ASViewController requires using -initWithNode:");
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@ -313,12 +313,13 @@ ASVisibilityDepthImplementation;
|
|||||||
{
|
{
|
||||||
[super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
|
[super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
|
||||||
|
|
||||||
// here we take the new UITraitCollection and use it to create a new ASEnvironmentTraitCollection on self.node
|
ASEnvironmentTraitCollection environmentTraitCollection = ASEnvironmentTraitCollectionFromUITraitCollection(newCollection);
|
||||||
// We will propagate when the corresponding viewWillTransitionToSize:withTransitionCoordinator: is called and we have the
|
// A call to willTransitionToTraitCollection:withTransitionCoordinator: is always followed by a call to viewWillTransitionToSize:withTransitionCoordinator:.
|
||||||
// new windowSize. There are cases when viewWillTransitionToSize: is called when willTransitionToTraitCollection: is not.
|
// However, it is not immediate and we may need the new trait collection before viewWillTransitionToSize:withTransitionCoordinator: is called. Our view already has the
|
||||||
// Since we do the propagation on viewWillTransitionToSize: our subnodes should always get the proper trait collection.
|
// new bounds, so go ahead and set the containerSize and propagate the traits here. As long as nothing else in the traits changes (which it shouldn't)
|
||||||
ASEnvironmentTraitCollection asyncTraitCollection = ASEnvironmentTraitCollectionFromUITraitCollection(newCollection);
|
// then we won't we will skip the propagation in viewWillTransitionToSize:withTransitionCoordinator:.
|
||||||
self.node.environmentTraitCollection = asyncTraitCollection;
|
environmentTraitCollection.containerSize = self.view.bounds.size;
|
||||||
|
[self progagateNewEnvironmentTraitCollection:environmentTraitCollection];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
|
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#import "ASControlNode.h"
|
#import "ASControlNode.h"
|
||||||
#import "ASImageNode.h"
|
#import "ASImageNode.h"
|
||||||
|
#import "ASRangeController.h"
|
||||||
|
|
||||||
@interface ASImageNode (Debugging)
|
@interface ASImageNode (Debugging)
|
||||||
|
|
||||||
@ -29,16 +30,40 @@
|
|||||||
@interface ASControlNode (Debugging)
|
@interface ASControlNode (Debugging)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Class method to enable a visualization overlay of the tappable area on the ASControlNode. For app debugging purposes only.
|
* Class method to enable a visualization overlay of the tappable area on the ASControlNode. For app debugging purposes only.
|
||||||
NOTE: GESTURE RECOGNIZERS, (including tap gesture recognizers on a control node) WILL NOT BE VISUALIZED!!!
|
* NOTE: GESTURE RECOGNIZERS, (including tap gesture recognizers on a control node) WILL NOT BE VISUALIZED!!!
|
||||||
Overlay = translucent GREEN color,
|
* Overlay = translucent GREEN color,
|
||||||
edges that are clipped by the tappable area of any parent (their bounds + hitTestSlop) in the hierarchy = DARK GREEN BORDERED EDGE,
|
* edges that are clipped by the tappable area of any parent (their bounds + hitTestSlop) in the hierarchy = DARK GREEN BORDERED EDGE,
|
||||||
edges that are clipped by clipToBounds = YES of any parent in the hierarchy = ORANGE BORDERED EDGE (may still receive touches beyond
|
* edges that are clipped by clipToBounds = YES of any parent in the hierarchy = ORANGE BORDERED EDGE (may still receive touches beyond
|
||||||
overlay rect, but can't be visualized).
|
* overlay rect, but can't be visualized).
|
||||||
@param enable Specify YES to make this debug feature enabled when messaging the ASControlNode class.
|
* @param enable Specify YES to make this debug feature enabled when messaging the ASControlNode class.
|
||||||
*/
|
*/
|
||||||
+ (void)setEnableHitTestDebug:(BOOL)enable;
|
+ (void)setEnableHitTestDebug:(BOOL)enable;
|
||||||
+ (BOOL)enableHitTestDebug;
|
+ (BOOL)enableHitTestDebug;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@interface ASRangeController (Debugging)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class method to enable a visualization overlay of the all ASRangeController's tuning parameters. For dev purposes only.
|
||||||
|
* To use, message ASRangeController in the AppDelegate --> [ASRangeController setShouldShowRangeDebugOverlay:YES];
|
||||||
|
* @param enable Specify YES to make this debug feature enabled when messaging the ASRangeController class.
|
||||||
|
*/
|
||||||
|
+ (void)setShouldShowRangeDebugOverlay:(BOOL)show;
|
||||||
|
+ (BOOL)shouldShowRangeDebugOverlay;
|
||||||
|
|
||||||
|
+ (void)layoutDebugOverlayIfNeeded;
|
||||||
|
|
||||||
|
- (void)addRangeControllerToRangeDebugOverlay;
|
||||||
|
|
||||||
|
- (void)updateRangeController:(ASRangeController *)controller
|
||||||
|
withScrollableDirections:(ASScrollDirection)scrollableDirections
|
||||||
|
scrollDirection:(ASScrollDirection)direction
|
||||||
|
rangeMode:(ASLayoutRangeMode)mode
|
||||||
|
displayTuningParameters:(ASRangeTuningParameters)displayTuningParameters
|
||||||
|
fetchDataTuningParameters:(ASRangeTuningParameters)fetchDataTuningParameters
|
||||||
|
interfaceState:(ASInterfaceState)interfaceState;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,16 @@
|
|||||||
#import "AsyncDisplayKit+Debug.h"
|
#import "AsyncDisplayKit+Debug.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
#import "ASDisplayNodeExtras.h"
|
#import "ASDisplayNodeExtras.h"
|
||||||
|
#import "ASWeakSet.h"
|
||||||
|
#import "UIImage+ASConvenience.h"
|
||||||
|
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
|
||||||
|
#import <AsyncDisplayKit/CGRect+ASConvenience.h>
|
||||||
|
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
|
||||||
|
#import <AsyncDisplayKit/ASTextNode.h>
|
||||||
|
#import <AsyncDisplayKit/ASRangeController.h>
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - ASImageNode (Debugging)
|
||||||
|
|
||||||
static BOOL __shouldShowImageScalingOverlay = NO;
|
static BOOL __shouldShowImageScalingOverlay = NO;
|
||||||
|
|
||||||
@ -30,6 +40,8 @@ static BOOL __shouldShowImageScalingOverlay = NO;
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark - ASControlNode (DebuggingInternal)
|
||||||
|
|
||||||
static BOOL __enableHitTestDebug = NO;
|
static BOOL __enableHitTestDebug = NO;
|
||||||
|
|
||||||
@interface ASControlNode (DebuggingInternal)
|
@interface ASControlNode (DebuggingInternal)
|
||||||
@ -191,3 +203,551 @@ static BOOL __enableHitTestDebug = NO;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark - ASRangeController (Debugging)
|
||||||
|
|
||||||
|
@interface _ASRangeDebugOverlayView : UIView
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance;
|
||||||
|
|
||||||
|
- (void)addRangeController:(ASRangeController *)rangeController;
|
||||||
|
|
||||||
|
- (void)updateRangeController:(ASRangeController *)controller
|
||||||
|
withScrollableDirections:(ASScrollDirection)scrollableDirections
|
||||||
|
scrollDirection:(ASScrollDirection)direction
|
||||||
|
rangeMode:(ASLayoutRangeMode)mode
|
||||||
|
displayTuningParameters:(ASRangeTuningParameters)displayTuningParameters
|
||||||
|
fetchDataTuningParameters:(ASRangeTuningParameters)fetchDataTuningParameters
|
||||||
|
interfaceState:(ASInterfaceState)interfaceState;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface _ASRangeDebugBarView : UIView
|
||||||
|
|
||||||
|
@property (nonatomic, weak) ASRangeController *rangeController;
|
||||||
|
@property (nonatomic, assign) BOOL destroyOnLayout;
|
||||||
|
@property (nonatomic, strong) NSString *debugString;
|
||||||
|
|
||||||
|
- (instancetype)initWithRangeController:(ASRangeController *)rangeController;
|
||||||
|
|
||||||
|
- (void)updateWithVisibleRatio:(CGFloat)visibleRatio
|
||||||
|
displayRatio:(CGFloat)displayRatio
|
||||||
|
leadingDisplayRatio:(CGFloat)leadingDisplayRatio
|
||||||
|
fetchDataRatio:(CGFloat)fetchDataRatio
|
||||||
|
leadingFetchDataRatio:(CGFloat)leadingFetchDataRatio
|
||||||
|
direction:(ASScrollDirection)direction;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
static BOOL __shouldShowRangeDebugOverlay = NO;
|
||||||
|
|
||||||
|
@implementation ASRangeController (Debugging)
|
||||||
|
|
||||||
|
+ (void)setShouldShowRangeDebugOverlay:(BOOL)show
|
||||||
|
{
|
||||||
|
__shouldShowRangeDebugOverlay = show;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)shouldShowRangeDebugOverlay
|
||||||
|
{
|
||||||
|
return __shouldShowRangeDebugOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)layoutDebugOverlayIfNeeded
|
||||||
|
{
|
||||||
|
[[_ASRangeDebugOverlayView sharedInstance] setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addRangeControllerToRangeDebugOverlay
|
||||||
|
{
|
||||||
|
[[_ASRangeDebugOverlayView sharedInstance] addRangeController:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateRangeController:(ASRangeController *)controller
|
||||||
|
withScrollableDirections:(ASScrollDirection)scrollableDirections
|
||||||
|
scrollDirection:(ASScrollDirection)direction
|
||||||
|
rangeMode:(ASLayoutRangeMode)mode
|
||||||
|
displayTuningParameters:(ASRangeTuningParameters)displayTuningParameters
|
||||||
|
fetchDataTuningParameters:(ASRangeTuningParameters)fetchDataTuningParameters
|
||||||
|
interfaceState:(ASInterfaceState)interfaceState
|
||||||
|
{
|
||||||
|
[[_ASRangeDebugOverlayView sharedInstance] updateRangeController:controller
|
||||||
|
withScrollableDirections:scrollableDirections
|
||||||
|
scrollDirection:direction
|
||||||
|
rangeMode:mode
|
||||||
|
displayTuningParameters:displayTuningParameters
|
||||||
|
fetchDataTuningParameters:fetchDataTuningParameters
|
||||||
|
interfaceState:interfaceState];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark _ASRangeDebugOverlayView
|
||||||
|
|
||||||
|
@interface _ASRangeDebugOverlayView () <UIGestureRecognizerDelegate>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _ASRangeDebugOverlayView
|
||||||
|
{
|
||||||
|
NSMutableArray *_rangeControllerViews;
|
||||||
|
NSInteger _newControllerCount;
|
||||||
|
NSInteger _removeControllerCount;
|
||||||
|
BOOL _animating;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (UIWindow *)keyWindow
|
||||||
|
{
|
||||||
|
// hack to work around app extensions not having UIApplication...not sure of a better way to do this?
|
||||||
|
return [[NSClassFromString(@"UIApplication") sharedApplication] keyWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)sharedInstance
|
||||||
|
{
|
||||||
|
static _ASRangeDebugOverlayView *__rangeDebugOverlay = nil;
|
||||||
|
|
||||||
|
if (!__rangeDebugOverlay && [ASRangeController shouldShowRangeDebugOverlay]) {
|
||||||
|
__rangeDebugOverlay = [[self alloc] initWithFrame:CGRectZero];
|
||||||
|
[[self keyWindow] addSubview:__rangeDebugOverlay];
|
||||||
|
}
|
||||||
|
|
||||||
|
return __rangeDebugOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OVERLAY_INSET 10
|
||||||
|
#define OVERLAY_SCALE 3
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:frame];
|
||||||
|
|
||||||
|
if (self) {
|
||||||
|
_rangeControllerViews = [[NSMutableArray alloc] init];
|
||||||
|
self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
|
||||||
|
self.layer.zPosition = 1000;
|
||||||
|
self.clipsToBounds = YES;
|
||||||
|
|
||||||
|
CGSize windowSize = [[[self class] keyWindow] bounds].size;
|
||||||
|
self.frame = CGRectMake(windowSize.width - (windowSize.width / OVERLAY_SCALE) - OVERLAY_INSET, windowSize.height - OVERLAY_INSET,
|
||||||
|
windowSize.width / OVERLAY_SCALE, 0.0);
|
||||||
|
|
||||||
|
UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(rangeDebugOverlayWasPanned:)];
|
||||||
|
[self addGestureRecognizer:panGR];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BAR_THICKNESS 24
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
[super layoutSubviews];
|
||||||
|
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
|
||||||
|
[self layoutToFitAllBarsExcept:0];
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutToFitAllBarsExcept:(NSInteger)barsToClip
|
||||||
|
{
|
||||||
|
CGSize boundsSize = self.bounds.size;
|
||||||
|
CGFloat totalHeight = 0.0;
|
||||||
|
|
||||||
|
CGRect barRect = CGRectMake(0, boundsSize.height - BAR_THICKNESS, self.bounds.size.width, BAR_THICKNESS);
|
||||||
|
NSMutableArray *displayedBars = [NSMutableArray array];
|
||||||
|
|
||||||
|
for (_ASRangeDebugBarView *barView in [_rangeControllerViews copy]) {
|
||||||
|
barView.frame = barRect;
|
||||||
|
|
||||||
|
ASInterfaceState interfaceState = [barView.rangeController.dataSource interfaceStateForRangeController:barView.rangeController];
|
||||||
|
|
||||||
|
if (!(interfaceState & (ASInterfaceStateVisible))) {
|
||||||
|
if (barView.destroyOnLayout && barView.alpha == 0.0) {
|
||||||
|
[_rangeControllerViews removeObjectIdenticalTo:barView];
|
||||||
|
[barView removeFromSuperview];
|
||||||
|
} else {
|
||||||
|
barView.alpha = 0.0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(!barView.destroyOnLayout); // In this case we should not have a visible interfaceState
|
||||||
|
barView.alpha = 1.0;
|
||||||
|
totalHeight += BAR_THICKNESS;
|
||||||
|
barRect.origin.y -= BAR_THICKNESS;
|
||||||
|
[displayedBars addObject:barView];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalHeight > 0) {
|
||||||
|
totalHeight -= (BAR_THICKNESS * barsToClip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (barsToClip == 0) {
|
||||||
|
CGRect overlayFrame = self.frame;
|
||||||
|
CGFloat heightChange = (overlayFrame.size.height - totalHeight);
|
||||||
|
|
||||||
|
overlayFrame.origin.y += heightChange;
|
||||||
|
overlayFrame.size.height = totalHeight;
|
||||||
|
self.frame = overlayFrame;
|
||||||
|
|
||||||
|
for (_ASRangeDebugBarView *barView in displayedBars) {
|
||||||
|
[self offsetYOrigin:-heightChange forView:barView];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setOrigin:(CGPoint)origin forView:(UIView *)view
|
||||||
|
{
|
||||||
|
CGRect newFrame = view.frame;
|
||||||
|
newFrame.origin = origin;
|
||||||
|
view.frame = newFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)offsetYOrigin:(CGFloat)offset forView:(UIView *)view
|
||||||
|
{
|
||||||
|
CGRect newFrame = view.frame;
|
||||||
|
newFrame.origin = CGPointMake(newFrame.origin.x, newFrame.origin.y + offset);
|
||||||
|
view.frame = newFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addRangeController:(ASRangeController *)rangeController
|
||||||
|
{
|
||||||
|
for (_ASRangeDebugBarView *rangeView in _rangeControllerViews) {
|
||||||
|
if (rangeView.rangeController == rangeController) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ASRangeDebugBarView *rangeView = [[_ASRangeDebugBarView alloc] initWithRangeController:rangeController];
|
||||||
|
[_rangeControllerViews addObject:rangeView];
|
||||||
|
[self addSubview:rangeView];
|
||||||
|
|
||||||
|
if (!_animating) {
|
||||||
|
[self layoutToFitAllBarsExcept:1];
|
||||||
|
}
|
||||||
|
|
||||||
|
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
|
||||||
|
_animating = YES;
|
||||||
|
[self layoutToFitAllBarsExcept:0];
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
_animating = NO;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateRangeController:(ASRangeController *)controller
|
||||||
|
withScrollableDirections:(ASScrollDirection)scrollableDirections
|
||||||
|
scrollDirection:(ASScrollDirection)scrollDirection
|
||||||
|
rangeMode:(ASLayoutRangeMode)rangeMode
|
||||||
|
displayTuningParameters:(ASRangeTuningParameters)displayTuningParameters
|
||||||
|
fetchDataTuningParameters:(ASRangeTuningParameters)fetchDataTuningParameters
|
||||||
|
interfaceState:(ASInterfaceState)interfaceState;
|
||||||
|
{
|
||||||
|
_ASRangeDebugBarView *viewToUpdate = [self barViewForRangeController:controller];
|
||||||
|
|
||||||
|
CGRect boundsRect = self.bounds;
|
||||||
|
CGRect visibleRect = CGRectExpandToRangeWithScrollableDirections(boundsRect, ASRangeTuningParametersZero, scrollableDirections, scrollDirection);
|
||||||
|
CGRect displayRect = CGRectExpandToRangeWithScrollableDirections(boundsRect, displayTuningParameters, scrollableDirections, scrollDirection);
|
||||||
|
CGRect fetchDataRect = CGRectExpandToRangeWithScrollableDirections(boundsRect, fetchDataTuningParameters, scrollableDirections, scrollDirection);
|
||||||
|
|
||||||
|
// figure out which is biggest and assume that is full bounds
|
||||||
|
BOOL displayRangeLargerThanFetch = NO;
|
||||||
|
CGFloat visibleRatio = 0;
|
||||||
|
CGFloat displayRatio = 0;
|
||||||
|
CGFloat fetchDataRatio = 0;
|
||||||
|
CGFloat leadingDisplayTuningRatio = 0;
|
||||||
|
CGFloat leadingFetchDataTuningRatio = 0;
|
||||||
|
|
||||||
|
if (!((displayTuningParameters.leadingBufferScreenfuls + displayTuningParameters.trailingBufferScreenfuls) == 0)) {
|
||||||
|
leadingDisplayTuningRatio = displayTuningParameters.leadingBufferScreenfuls / (displayTuningParameters.leadingBufferScreenfuls + displayTuningParameters.trailingBufferScreenfuls);
|
||||||
|
}
|
||||||
|
if (!((fetchDataTuningParameters.leadingBufferScreenfuls + fetchDataTuningParameters.trailingBufferScreenfuls) == 0)) {
|
||||||
|
leadingFetchDataTuningRatio = fetchDataTuningParameters.leadingBufferScreenfuls / (fetchDataTuningParameters.leadingBufferScreenfuls + fetchDataTuningParameters.trailingBufferScreenfuls);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ASScrollDirectionContainsVerticalDirection(scrollDirection)) {
|
||||||
|
|
||||||
|
if (displayRect.size.height >= fetchDataRect.size.height) {
|
||||||
|
displayRangeLargerThanFetch = YES;
|
||||||
|
} else {
|
||||||
|
displayRangeLargerThanFetch = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayRangeLargerThanFetch) {
|
||||||
|
visibleRatio = visibleRect.size.height / displayRect.size.height;
|
||||||
|
displayRatio = 1.0;
|
||||||
|
fetchDataRatio = fetchDataRect.size.height / displayRect.size.height;
|
||||||
|
} else {
|
||||||
|
visibleRatio = visibleRect.size.height / fetchDataRect.size.height;
|
||||||
|
displayRatio = displayRect.size.height / fetchDataRect.size.height;
|
||||||
|
fetchDataRatio = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (displayRect.size.width >= fetchDataRect.size.width) {
|
||||||
|
displayRangeLargerThanFetch = YES;
|
||||||
|
} else {
|
||||||
|
displayRangeLargerThanFetch = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayRangeLargerThanFetch) {
|
||||||
|
visibleRatio = visibleRect.size.width / displayRect.size.width;
|
||||||
|
displayRatio = 1.0;
|
||||||
|
fetchDataRatio = fetchDataRect.size.width / displayRect.size.width;
|
||||||
|
} else {
|
||||||
|
visibleRatio = visibleRect.size.width / fetchDataRect.size.width;
|
||||||
|
displayRatio = displayRect.size.width / fetchDataRect.size.width;
|
||||||
|
fetchDataRatio = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[viewToUpdate updateWithVisibleRatio:visibleRatio
|
||||||
|
displayRatio:displayRatio
|
||||||
|
leadingDisplayRatio:leadingDisplayTuningRatio
|
||||||
|
fetchDataRatio:fetchDataRatio
|
||||||
|
leadingFetchDataRatio:leadingFetchDataTuningRatio
|
||||||
|
direction:scrollDirection];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_ASRangeDebugBarView *)barViewForRangeController:(ASRangeController *)controller
|
||||||
|
{
|
||||||
|
_ASRangeDebugBarView *rangeControllerBarView = nil;
|
||||||
|
|
||||||
|
for (_ASRangeDebugBarView *rangeView in [[_rangeControllerViews reverseObjectEnumerator] allObjects]) {
|
||||||
|
// remove barView if its rangeController has been deleted
|
||||||
|
if (!rangeView.rangeController) {
|
||||||
|
rangeView.destroyOnLayout = YES;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
ASInterfaceState interfaceState = [rangeView.rangeController.dataSource interfaceStateForRangeController:rangeView.rangeController];
|
||||||
|
if (!(interfaceState & (ASInterfaceStateVisible | ASInterfaceStateDisplay))) {
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([rangeView.rangeController isEqual:controller]) {
|
||||||
|
rangeControllerBarView = rangeView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rangeControllerBarView;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MIN_VISIBLE_INSET 40
|
||||||
|
- (void)rangeDebugOverlayWasPanned:(UIPanGestureRecognizer *)recognizer
|
||||||
|
{
|
||||||
|
CGPoint translation = [recognizer translationInView:recognizer.view];
|
||||||
|
CGFloat newCenterX = recognizer.view.center.x + translation.x;
|
||||||
|
CGFloat newCenterY = recognizer.view.center.y + translation.y;
|
||||||
|
CGSize boundsSize = recognizer.view.bounds.size;
|
||||||
|
CGSize superBoundsSize = recognizer.view.superview.bounds.size;
|
||||||
|
CGFloat minAllowableX = -boundsSize.width / 2.0 + MIN_VISIBLE_INSET;
|
||||||
|
CGFloat maxAllowableX = superBoundsSize.width + boundsSize.width / 2.0 - MIN_VISIBLE_INSET;
|
||||||
|
|
||||||
|
if (newCenterX > maxAllowableX) {
|
||||||
|
newCenterX = maxAllowableX;
|
||||||
|
} else if (newCenterX < minAllowableX) {
|
||||||
|
newCenterX = minAllowableX;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGFloat minAllowableY = -boundsSize.height / 2.0 + MIN_VISIBLE_INSET;
|
||||||
|
CGFloat maxAllowableY = superBoundsSize.height + boundsSize.height / 2.0 - MIN_VISIBLE_INSET;
|
||||||
|
|
||||||
|
if (newCenterY > maxAllowableY) {
|
||||||
|
newCenterY = maxAllowableY;
|
||||||
|
} else if (newCenterY < minAllowableY) {
|
||||||
|
newCenterY = minAllowableY;
|
||||||
|
}
|
||||||
|
|
||||||
|
recognizer.view.center = CGPointMake(newCenterX, newCenterY);
|
||||||
|
[recognizer setTranslation:CGPointMake(0, 0) inView:recognizer.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark _ASRangeDebugBarView
|
||||||
|
|
||||||
|
@implementation _ASRangeDebugBarView
|
||||||
|
{
|
||||||
|
ASTextNode *_debugText;
|
||||||
|
ASTextNode *_leftDebugText;
|
||||||
|
ASTextNode *_rightDebugText;
|
||||||
|
ASImageNode *_visibleRect;
|
||||||
|
ASImageNode *_displayRect;
|
||||||
|
ASImageNode *_fetchDataRect;
|
||||||
|
CGFloat _visibleRatio;
|
||||||
|
CGFloat _displayRatio;
|
||||||
|
CGFloat _fetchDataRatio;
|
||||||
|
CGFloat _leadingDisplayRatio;
|
||||||
|
CGFloat _leadingFetchDataRatio;
|
||||||
|
ASScrollDirection _scrollDirection;
|
||||||
|
BOOL _firstLayoutOfRects;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithRangeController:(ASRangeController *)rangeController
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:CGRectZero];
|
||||||
|
if (self) {
|
||||||
|
_firstLayoutOfRects = YES;
|
||||||
|
_rangeController = rangeController;
|
||||||
|
_debugText = [self createDebugTextNode];
|
||||||
|
_leftDebugText = [self createDebugTextNode];
|
||||||
|
_rightDebugText = [self createDebugTextNode];
|
||||||
|
_fetchDataRect = [self createRangeNodeWithColor:[UIColor orangeColor]];
|
||||||
|
_displayRect = [self createRangeNodeWithColor:[UIColor yellowColor]];
|
||||||
|
_visibleRect = [self createRangeNodeWithColor:[UIColor greenColor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HORIZONTAL_INSET 10
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
[super layoutSubviews];
|
||||||
|
|
||||||
|
CGSize boundsSize = self.bounds.size;
|
||||||
|
CGFloat subCellHeight = 9.0;
|
||||||
|
[self setBarDebugLabelsWithSize:subCellHeight];
|
||||||
|
[self setBarSubviewOrder];
|
||||||
|
|
||||||
|
CGRect rect = CGRectIntegral(CGRectMake(0, 0, boundsSize.width, floorf(boundsSize.height / 2.0)));
|
||||||
|
rect.size = [_debugText measure:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
|
||||||
|
rect.origin.x = (boundsSize.width - rect.size.width) / 2.0;
|
||||||
|
_debugText.frame = rect;
|
||||||
|
rect.origin.y += rect.size.height;
|
||||||
|
|
||||||
|
rect.origin.x = 0;
|
||||||
|
rect.size = CGSizeMake(HORIZONTAL_INSET, boundsSize.height / 2.0);
|
||||||
|
_leftDebugText.frame = rect;
|
||||||
|
|
||||||
|
rect.origin.x = boundsSize.width - HORIZONTAL_INSET;
|
||||||
|
_rightDebugText.frame = rect;
|
||||||
|
|
||||||
|
CGFloat visibleDimension = (boundsSize.width - 2 * HORIZONTAL_INSET) * _visibleRatio;
|
||||||
|
CGFloat displayDimension = (boundsSize.width - 2 * HORIZONTAL_INSET) * _displayRatio;
|
||||||
|
CGFloat fetchDataDimension = (boundsSize.width - 2 * HORIZONTAL_INSET) * _fetchDataRatio;
|
||||||
|
CGFloat visiblePoint = 0;
|
||||||
|
CGFloat displayPoint = 0;
|
||||||
|
CGFloat fetchDataPoint = 0;
|
||||||
|
|
||||||
|
BOOL displayLargerThanFetchData = (_displayRatio == 1.0) ? YES : NO;
|
||||||
|
|
||||||
|
if (ASScrollDirectionContainsLeft(_scrollDirection) || ASScrollDirectionContainsUp(_scrollDirection)) {
|
||||||
|
|
||||||
|
if (displayLargerThanFetchData) {
|
||||||
|
visiblePoint = (displayDimension - visibleDimension) * _leadingDisplayRatio;
|
||||||
|
fetchDataPoint = visiblePoint - (fetchDataDimension - visibleDimension) * _leadingFetchDataRatio;
|
||||||
|
} else {
|
||||||
|
visiblePoint = (fetchDataDimension - visibleDimension) * _leadingFetchDataRatio;
|
||||||
|
displayPoint = visiblePoint - (displayDimension - visibleDimension) * _leadingDisplayRatio;
|
||||||
|
}
|
||||||
|
} else if (ASScrollDirectionContainsRight(_scrollDirection) || ASScrollDirectionContainsDown(_scrollDirection)) {
|
||||||
|
|
||||||
|
if (displayLargerThanFetchData) {
|
||||||
|
visiblePoint = (displayDimension - visibleDimension) * (1 - _leadingDisplayRatio);
|
||||||
|
fetchDataPoint = visiblePoint - (fetchDataDimension - visibleDimension) * (1 - _leadingFetchDataRatio);
|
||||||
|
} else {
|
||||||
|
visiblePoint = (fetchDataDimension - visibleDimension) * (1 - _leadingFetchDataRatio);
|
||||||
|
displayPoint = visiblePoint - (displayDimension - visibleDimension) * (1 - _leadingDisplayRatio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL animate = !_firstLayoutOfRects;
|
||||||
|
[UIView animateWithDuration:animate ? 0.3 : 0.0 delay:0.0 options:UIViewAnimationOptionLayoutSubviews animations:^{
|
||||||
|
_visibleRect.frame = CGRectMake(HORIZONTAL_INSET + visiblePoint, rect.origin.y, visibleDimension, subCellHeight);
|
||||||
|
_displayRect.frame = CGRectMake(HORIZONTAL_INSET + displayPoint, rect.origin.y, displayDimension, subCellHeight);
|
||||||
|
_fetchDataRect.frame = CGRectMake(HORIZONTAL_INSET + fetchDataPoint, rect.origin.y, fetchDataDimension, subCellHeight);
|
||||||
|
} completion:^(BOOL finished) {}];
|
||||||
|
|
||||||
|
if (!animate) {
|
||||||
|
_visibleRect.alpha = _displayRect.alpha = _fetchDataRect.alpha = 0;
|
||||||
|
[UIView animateWithDuration:0.3 animations:^{
|
||||||
|
_visibleRect.alpha = _displayRect.alpha = _fetchDataRect.alpha = 1;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
_firstLayoutOfRects = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateWithVisibleRatio:(CGFloat)visibleRatio
|
||||||
|
displayRatio:(CGFloat)displayRatio
|
||||||
|
leadingDisplayRatio:(CGFloat)leadingDisplayRatio
|
||||||
|
fetchDataRatio:(CGFloat)fetchDataRatio
|
||||||
|
leadingFetchDataRatio:(CGFloat)leadingFetchDataRatio
|
||||||
|
direction:(ASScrollDirection)scrollDirection
|
||||||
|
{
|
||||||
|
_visibleRatio = visibleRatio;
|
||||||
|
_displayRatio = displayRatio;
|
||||||
|
_leadingDisplayRatio = leadingDisplayRatio;
|
||||||
|
_fetchDataRatio = fetchDataRatio;
|
||||||
|
_leadingFetchDataRatio = leadingFetchDataRatio;
|
||||||
|
_scrollDirection = scrollDirection;
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBarSubviewOrder
|
||||||
|
{
|
||||||
|
if (_fetchDataRatio == 1.0) {
|
||||||
|
[self sendSubviewToBack:_fetchDataRect.view];
|
||||||
|
} else {
|
||||||
|
[self sendSubviewToBack:_displayRect.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self bringSubviewToFront:_visibleRect.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBarDebugLabelsWithSize:(CGFloat)size
|
||||||
|
{
|
||||||
|
if (!_debugString) {
|
||||||
|
_debugString = [[_rangeController dataSource] nameForRangeControllerDataSource];
|
||||||
|
}
|
||||||
|
if (_debugString) {
|
||||||
|
_debugText.attributedString = [_ASRangeDebugBarView whiteAttributedStringFromString:_debugString withSize:size];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ASScrollDirectionContainsVerticalDirection(_scrollDirection)) {
|
||||||
|
_leftDebugText.attributedText = [_ASRangeDebugBarView whiteAttributedStringFromString:@"▲" withSize:size];
|
||||||
|
_rightDebugText.attributedText = [_ASRangeDebugBarView whiteAttributedStringFromString:@"▼" withSize:size];
|
||||||
|
} else if (ASScrollDirectionContainsHorizontalDirection(_scrollDirection)) {
|
||||||
|
_leftDebugText.attributedText = [_ASRangeDebugBarView whiteAttributedStringFromString:@"◀︎" withSize:size];
|
||||||
|
_rightDebugText.attributedText = [_ASRangeDebugBarView whiteAttributedStringFromString:@"▶︎" withSize:size];
|
||||||
|
}
|
||||||
|
|
||||||
|
_leftDebugText.hidden = (_scrollDirection != ASScrollDirectionLeft && _scrollDirection != ASScrollDirectionUp);
|
||||||
|
_rightDebugText.hidden = (_scrollDirection != ASScrollDirectionRight && _scrollDirection != ASScrollDirectionDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (ASTextNode *)createDebugTextNode
|
||||||
|
{
|
||||||
|
ASTextNode *label = [[ASTextNode alloc] init];
|
||||||
|
[self addSubnode:label];
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RANGE_BAR_CORNER_RADIUS 3
|
||||||
|
#define RANGE_BAR_BORDER_WIDTH 1
|
||||||
|
- (ASImageNode *)createRangeNodeWithColor:(UIColor *)color
|
||||||
|
{
|
||||||
|
ASImageNode *rangeBarImageNode = [[ASImageNode alloc] init];
|
||||||
|
rangeBarImageNode.image = [UIImage as_resizableRoundedImageWithCornerRadius:RANGE_BAR_CORNER_RADIUS
|
||||||
|
cornerColor:[UIColor clearColor]
|
||||||
|
fillColor:[color colorWithAlphaComponent:0.5]
|
||||||
|
borderColor:[[UIColor blackColor] colorWithAlphaComponent:0.9]
|
||||||
|
borderWidth:RANGE_BAR_BORDER_WIDTH
|
||||||
|
roundedCorners:UIRectCornerAllCorners
|
||||||
|
scale:[[UIScreen mainScreen] scale]];
|
||||||
|
[self addSubnode:rangeBarImageNode];
|
||||||
|
|
||||||
|
return rangeBarImageNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSAttributedString *)whiteAttributedStringFromString:(NSString *)string withSize:(CGFloat)size
|
||||||
|
{
|
||||||
|
NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor whiteColor],
|
||||||
|
NSFontAttributeName : [UIFont systemFontOfSize:size]};
|
||||||
|
return [[NSAttributedString alloc] initWithString:string attributes:attributes];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
@ -84,6 +84,18 @@
|
|||||||
return batchUpdating;
|
return batchUpdating;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)waitUntilAllUpdatesAreCommitted
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssertMainThread();
|
||||||
|
if (self.batchUpdating) {
|
||||||
|
// This assertion will be enabled soon.
|
||||||
|
// ASDisplayNodeFailAssert(@"Should not call %@ during batch update", NSStringFromSelector(_cmd));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[super waitUntilAllUpdatesAreCommitted];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Section Editing (External API)
|
#pragma mark - Section Editing (External API)
|
||||||
|
|
||||||
- (void)insertSections:(NSIndexSet *)sections withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)insertSections:(NSIndexSet *)sections withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
|
|||||||
@ -26,8 +26,6 @@
|
|||||||
|
|
||||||
- (NSArray *)supplementaryNodeKindsInDataController:(ASCollectionDataController *)dataController;
|
- (NSArray *)supplementaryNodeKindsInDataController:(ASCollectionDataController *)dataController;
|
||||||
|
|
||||||
- (NSUInteger)dataController:(ASCollectionDataController *)dataController numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind;
|
|
||||||
|
|
||||||
- (NSUInteger)dataController:(ASCollectionDataController *)dataController supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section;
|
- (NSUInteger)dataController:(ASCollectionDataController *)dataController supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section;
|
||||||
|
|
||||||
@optional
|
@optional
|
||||||
|
|||||||
@ -43,17 +43,18 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForReloadData
|
- (void)prepareForReloadDataWithSectionCount:(NSInteger)newSectionCount
|
||||||
{
|
{
|
||||||
|
NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, newSectionCount)];
|
||||||
for (NSString *kind in [self supplementaryKinds]) {
|
for (NSString *kind in [self supplementaryKinds]) {
|
||||||
LOG(@"Populating elements of kind: %@", kind);
|
LOG(@"Populating elements of kind: %@", kind);
|
||||||
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||||
[self _populateSupplementaryNodesOfKind:kind withMutableContexts:contexts];
|
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableContexts:contexts];
|
||||||
_pendingContexts[kind] = contexts;
|
_pendingContexts[kind] = contexts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)willReloadData
|
- (void)willReloadDataWithSectionCount:(NSInteger)newSectionCount
|
||||||
{
|
{
|
||||||
[_pendingContexts enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull kind, NSMutableArray<ASIndexedNodeContext *> * _Nonnull contexts, __unused BOOL * _Nonnull stop) {
|
[_pendingContexts enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull kind, NSMutableArray<ASIndexedNodeContext *> * _Nonnull contexts, __unused BOOL * _Nonnull stop) {
|
||||||
// Remove everything that existed before the reload, now that we're ready to insert replacements
|
// Remove everything that existed before the reload, now that we're ready to insert replacements
|
||||||
@ -65,12 +66,11 @@
|
|||||||
[self deleteSectionsOfKind:kind atIndexSet:indexSet completion:nil];
|
[self deleteSectionsOfKind:kind atIndexSet:indexSet completion:nil];
|
||||||
|
|
||||||
// Insert each section
|
// Insert each section
|
||||||
NSUInteger sectionCount = [self.collectionDataSource dataController:self numberOfSectionsForSupplementaryNodeOfKind:kind];
|
NSMutableArray *sections = [NSMutableArray arrayWithCapacity:newSectionCount];
|
||||||
NSMutableArray *sections = [NSMutableArray arrayWithCapacity:sectionCount];
|
for (int i = 0; i < newSectionCount; i++) {
|
||||||
for (int i = 0; i < sectionCount; i++) {
|
|
||||||
[sections addObject:[NSMutableArray array]];
|
[sections addObject:[NSMutableArray array]];
|
||||||
}
|
}
|
||||||
[self insertSections:sections ofKind:kind atIndexSet:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] completion:nil];
|
[self insertSections:sections ofKind:kind atIndexSet:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, newSectionCount)] completion:nil];
|
||||||
|
|
||||||
[self batchLayoutNodesFromContexts:contexts batchCompletion:^(NSArray<ASCellNode *> *nodes, NSArray<NSIndexPath *> *indexPaths) {
|
[self batchLayoutNodesFromContexts:contexts batchCompletion:^(NSArray<ASCellNode *> *nodes, NSArray<NSIndexPath *> *indexPaths) {
|
||||||
[self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
[self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
||||||
@ -188,22 +188,6 @@
|
|||||||
[_pendingContexts removeAllObjects];
|
[_pendingContexts removeAllObjects];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_populateSupplementaryNodesOfKind:(NSString *)kind withMutableContexts:(NSMutableArray<ASIndexedNodeContext *> *)contexts
|
|
||||||
{
|
|
||||||
id<ASEnvironment> environment = [self.environmentDelegate dataControllerEnvironment];
|
|
||||||
ASEnvironmentTraitCollection environmentTraitCollection = environment.environmentTraitCollection;
|
|
||||||
|
|
||||||
id<ASCollectionDataControllerSource> source = self.collectionDataSource;
|
|
||||||
NSUInteger sectionCount = [source dataController:self numberOfSectionsForSupplementaryNodeOfKind:kind];
|
|
||||||
for (NSUInteger i = 0; i < sectionCount; i++) {
|
|
||||||
NSUInteger rowCount = [source dataController:self supplementaryNodesOfKind:kind inSection:i];
|
|
||||||
for (NSUInteger j = 0; j < rowCount; j++) {
|
|
||||||
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:j inSection:i];
|
|
||||||
[self _populateSupplementaryNodeOfKind:kind atIndexPath:indexPath mutableContexts:contexts environmentTraitCollection:environmentTraitCollection];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)_populateSupplementaryNodesOfKind:(NSString *)kind withSections:(NSIndexSet *)sections mutableContexts:(NSMutableArray<ASIndexedNodeContext *> *)contexts
|
- (void)_populateSupplementaryNodesOfKind:(NSString *)kind withSections:(NSIndexSet *)sections mutableContexts:(NSMutableArray<ASIndexedNodeContext *> *)contexts
|
||||||
{
|
{
|
||||||
id<ASEnvironment> environment = [self.environmentDelegate dataControllerEnvironment];
|
id<ASEnvironment> environment = [self.environmentDelegate dataControllerEnvironment];
|
||||||
|
|||||||
@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@protocol ASCollectionViewLayoutInspecting <NSObject>
|
@protocol ASCollectionViewLayoutInspecting <NSObject>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asks the inspector to provide a constarained size range for the given collection view node.
|
* Asks the inspector to provide a constrained size range for the given collection view node.
|
||||||
*/
|
*/
|
||||||
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath;
|
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
@ -33,11 +33,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
|
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
/**
|
|
||||||
* Asks the inspector for the number of supplementary sections in the collection view for the given kind.
|
|
||||||
*/
|
|
||||||
- (NSUInteger)collectionView:(ASCollectionView *)collectionView numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asks the inspector for the number of supplementary views for the given kind in the specified section.
|
* Asks the inspector for the number of supplementary views for the given kind in the specified section.
|
||||||
*/
|
*/
|
||||||
@ -57,6 +52,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (void)didChangeCollectionViewDataSource:(nullable id<ASCollectionDataSource>)dataSource;
|
- (void)didChangeCollectionViewDataSource:(nullable id<ASCollectionDataSource>)dataSource;
|
||||||
|
|
||||||
|
#pragma mark Deprecated Methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks the inspector for the number of supplementary sections in the collection view for the given kind.
|
||||||
|
*
|
||||||
|
* @deprecated This method will not be called, and it is only deprecated as a reminder to remove it.
|
||||||
|
* Supplementary elements must exist in the same sections as regular collection view items i.e. -numberOfSectionsInCollectionView:
|
||||||
|
*/
|
||||||
|
- (NSUInteger)collectionView:(ASCollectionView *)collectionView numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind ASDISPLAYNODE_DEPRECATED;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -34,7 +34,7 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
|
|||||||
@implementation ASCollectionViewLayoutInspector {
|
@implementation ASCollectionViewLayoutInspector {
|
||||||
struct {
|
struct {
|
||||||
unsigned int implementsConstrainedSizeForNodeAtIndexPath:1;
|
unsigned int implementsConstrainedSizeForNodeAtIndexPath:1;
|
||||||
} _dataSourceFlags;
|
} _delegateFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Lifecycle
|
#pragma mark Lifecycle
|
||||||
@ -43,26 +43,26 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
|
|||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
[self didChangeCollectionViewDataSource:collectionView.asyncDataSource];
|
[self didChangeCollectionViewDelegate:collectionView.asyncDelegate];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark ASCollectionViewLayoutInspecting
|
#pragma mark ASCollectionViewLayoutInspecting
|
||||||
|
|
||||||
- (void)didChangeCollectionViewDataSource:(id<ASCollectionDataSource>)dataSource
|
- (void)didChangeCollectionViewDelegate:(id<ASCollectionDelegate>)delegate
|
||||||
{
|
{
|
||||||
if (dataSource == nil) {
|
if (delegate == nil) {
|
||||||
memset(&_dataSourceFlags, 0, sizeof(_dataSourceFlags));
|
memset(&_delegateFlags, 0, sizeof(_delegateFlags));
|
||||||
} else {
|
} else {
|
||||||
_dataSourceFlags.implementsConstrainedSizeForNodeAtIndexPath = [dataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
|
_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath = [delegate respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
if (_dataSourceFlags.implementsConstrainedSizeForNodeAtIndexPath) {
|
if (_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath) {
|
||||||
return [collectionView.asyncDataSource collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
|
return [collectionView.asyncDelegate collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
return NodeConstrainedSizeForScrollDirection(collectionView);
|
return NodeConstrainedSizeForScrollDirection(collectionView);
|
||||||
@ -74,12 +74,6 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
|
|||||||
return ASSizeRangeMake(CGSizeZero, CGSizeZero);
|
return ASSizeRangeMake(CGSizeZero, CGSizeZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)collectionView:(ASCollectionView *)collectionView numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind
|
|
||||||
{
|
|
||||||
ASDisplayNodeAssert(NO, @"To support supplementary nodes in ASCollectionView, it must have a layoutInspector for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section
|
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(NO, @"To support supplementary nodes in ASCollectionView, it must have a layoutInspector for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)");
|
ASDisplayNodeAssert(NO, @"To support supplementary nodes in ASCollectionView, it must have a layoutInspector for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)");
|
||||||
@ -99,10 +93,10 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
|
|||||||
struct {
|
struct {
|
||||||
unsigned int implementsReferenceSizeForHeader:1;
|
unsigned int implementsReferenceSizeForHeader:1;
|
||||||
unsigned int implementsReferenceSizeForFooter:1;
|
unsigned int implementsReferenceSizeForFooter:1;
|
||||||
|
unsigned int implementsConstrainedSizeForNodeAtIndexPath:1;
|
||||||
} _delegateFlags;
|
} _delegateFlags;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned int implementsConstrainedSizeForNodeAtIndexPath:1;
|
|
||||||
unsigned int implementsNumberOfSectionsInCollectionView:1;
|
unsigned int implementsNumberOfSectionsInCollectionView:1;
|
||||||
} _dataSourceFlags;
|
} _dataSourceFlags;
|
||||||
}
|
}
|
||||||
@ -132,6 +126,7 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
|
|||||||
} else {
|
} else {
|
||||||
_delegateFlags.implementsReferenceSizeForHeader = [delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForHeaderInSection:)];
|
_delegateFlags.implementsReferenceSizeForHeader = [delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForHeaderInSection:)];
|
||||||
_delegateFlags.implementsReferenceSizeForFooter = [delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)];
|
_delegateFlags.implementsReferenceSizeForFooter = [delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)];
|
||||||
|
_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath = [delegate respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,15 +135,14 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
|
|||||||
if (dataSource == nil) {
|
if (dataSource == nil) {
|
||||||
memset(&_dataSourceFlags, 0, sizeof(_dataSourceFlags));
|
memset(&_dataSourceFlags, 0, sizeof(_dataSourceFlags));
|
||||||
} else {
|
} else {
|
||||||
_dataSourceFlags.implementsConstrainedSizeForNodeAtIndexPath = [dataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
|
|
||||||
_dataSourceFlags.implementsNumberOfSectionsInCollectionView = [dataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)];
|
_dataSourceFlags.implementsNumberOfSectionsInCollectionView = [dataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
if (_dataSourceFlags.implementsConstrainedSizeForNodeAtIndexPath) {
|
if (_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath) {
|
||||||
return [collectionView.asyncDataSource collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
|
return [collectionView.asyncDelegate collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
CGSize itemSize = _layout.itemSize;
|
CGSize itemSize = _layout.itemSize;
|
||||||
@ -171,15 +165,6 @@ static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView
|
|||||||
return ASSizeRangeMake(CGSizeZero, constrainedSize);
|
return ASSizeRangeMake(CGSizeZero, constrainedSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)collectionView:(ASCollectionView *)collectionView numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind
|
|
||||||
{
|
|
||||||
if (_dataSourceFlags.implementsNumberOfSectionsInCollectionView) {
|
|
||||||
return [collectionView.asyncDataSource numberOfSectionsInCollectionView:collectionView];
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section
|
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section
|
||||||
{
|
{
|
||||||
return [self layoutHasSupplementaryViewOfKind:kind inSection:section collectionView:collectionView] ? 1 : 0;
|
return [self layoutHasSupplementaryViewOfKind:kind inSection:section collectionView:collectionView] ? 1 : 0;
|
||||||
|
|||||||
@ -50,7 +50,6 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
|
|
||||||
ASMainSerialQueue *_mainSerialQueue;
|
ASMainSerialQueue *_mainSerialQueue;
|
||||||
|
|
||||||
NSMutableArray *_pendingEditCommandBlocks; // To be run on the main thread. Handles begin/endUpdates tracking.
|
|
||||||
dispatch_queue_t _editingTransactionQueue; // Serial background queue. Dispatches concurrent layout and manages _editingNodes.
|
dispatch_queue_t _editingTransactionQueue; // Serial background queue. Dispatches concurrent layout and manages _editingNodes.
|
||||||
dispatch_group_t _editingTransactionGroup; // Group of all edit transaction blocks. Useful for waiting.
|
dispatch_group_t _editingTransactionGroup; // Group of all edit transaction blocks. Useful for waiting.
|
||||||
|
|
||||||
@ -62,8 +61,6 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
BOOL _delegateDidDeleteSections;
|
BOOL _delegateDidDeleteSections;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, assign) NSUInteger batchUpdateCounter;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ASDataController
|
@implementation ASDataController
|
||||||
@ -87,15 +84,11 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
|
|
||||||
_mainSerialQueue = [[ASMainSerialQueue alloc] init];
|
_mainSerialQueue = [[ASMainSerialQueue alloc] init];
|
||||||
|
|
||||||
_pendingEditCommandBlocks = [NSMutableArray array];
|
|
||||||
|
|
||||||
const char *queueName = [[NSString stringWithFormat:@"org.AsyncDisplayKit.ASDataController.editingTransactionQueue:%p", self] cStringUsingEncoding:NSASCIIStringEncoding];
|
const char *queueName = [[NSString stringWithFormat:@"org.AsyncDisplayKit.ASDataController.editingTransactionQueue:%p", self] cStringUsingEncoding:NSASCIIStringEncoding];
|
||||||
_editingTransactionQueue = dispatch_queue_create(queueName, DISPATCH_QUEUE_SERIAL);
|
_editingTransactionQueue = dispatch_queue_create(queueName, DISPATCH_QUEUE_SERIAL);
|
||||||
dispatch_queue_set_specific(_editingTransactionQueue, &kASDataControllerEditingQueueKey, &kASDataControllerEditingQueueContext, NULL);
|
dispatch_queue_set_specific(_editingTransactionQueue, &kASDataControllerEditingQueueKey, &kASDataControllerEditingQueueContext, NULL);
|
||||||
_editingTransactionGroup = dispatch_group_create();
|
_editingTransactionGroup = dispatch_group_create();
|
||||||
|
|
||||||
_batchUpdateCounter = 0;
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,9 +388,9 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
|
|
||||||
- (void)_reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions synchronously:(BOOL)synchronously completion:(void (^)())completion
|
- (void)_reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions synchronously:(BOOL)synchronously completion:(void (^)())completion
|
||||||
{
|
{
|
||||||
_initialReloadDataHasBeenCalled = YES;
|
|
||||||
[self performEditCommandWithBlock:^{
|
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|
||||||
|
_initialReloadDataHasBeenCalled = YES;
|
||||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
[self invalidateDataSourceItemCounts];
|
[self invalidateDataSourceItemCounts];
|
||||||
@ -406,7 +399,7 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
NSArray<ASIndexedNodeContext *> *contexts = [self _populateFromDataSourceWithSectionIndexSet:sectionIndexSet];
|
NSArray<ASIndexedNodeContext *> *contexts = [self _populateFromDataSourceWithSectionIndexSet:sectionIndexSet];
|
||||||
|
|
||||||
// Allow subclasses to perform setup before going into the edit transaction
|
// Allow subclasses to perform setup before going into the edit transaction
|
||||||
[self prepareForReloadData];
|
[self prepareForReloadDataWithSectionCount:sectionCount];
|
||||||
|
|
||||||
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
||||||
LOG(@"Edit Transaction - reloadData");
|
LOG(@"Edit Transaction - reloadData");
|
||||||
@ -421,7 +414,7 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
[self _deleteSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions];
|
[self _deleteSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self willReloadData];
|
[self willReloadDataWithSectionCount:sectionCount];
|
||||||
|
|
||||||
// Insert empty sections
|
// Insert empty sections
|
||||||
NSMutableArray *sections = [NSMutableArray arrayWithCapacity:sectionCount];
|
NSMutableArray *sections = [NSMutableArray arrayWithCapacity:sectionCount];
|
||||||
@ -439,16 +432,11 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
if (synchronously) {
|
if (synchronously) {
|
||||||
[self waitUntilAllUpdatesAreCommitted];
|
[self waitUntilAllUpdatesAreCommitted];
|
||||||
}
|
}
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)waitUntilAllUpdatesAreCommitted
|
- (void)waitUntilAllUpdatesAreCommitted
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
ASDisplayNodeAssert(_batchUpdateCounter == 0, @"Should not be called between beginUpdate or endUpdate");
|
|
||||||
|
|
||||||
// This should never be called in a batch update, return immediately therefore
|
|
||||||
if (_batchUpdateCounter > 0) { return; }
|
|
||||||
|
|
||||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
@ -516,10 +504,20 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
|
|
||||||
- (void)beginUpdates
|
- (void)beginUpdates
|
||||||
{
|
{
|
||||||
|
ASDisplayNodeAssertMainThread();
|
||||||
|
// TODO: make this -waitUntilAllUpdatesAreCommitted?
|
||||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||||
// Begin queuing up edit calls that happen on the main thread.
|
|
||||||
// This will prevent further operations from being scheduled on _editingTransactionQueue.
|
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
||||||
_batchUpdateCounter++;
|
[_mainSerialQueue performBlockOnMainThread:^{
|
||||||
|
// Deep copy _completedNodes to _externalCompletedNodes.
|
||||||
|
// Any external queries from now on will be done on _externalCompletedNodes, to guarantee data consistency with the delegate.
|
||||||
|
_externalCompletedNodes = ASTwoDimensionalArrayDeepMutableCopy(_completedNodes[ASDataControllerRowNodeKind]);
|
||||||
|
|
||||||
|
LOG(@"beginUpdates - begin updates call to delegate");
|
||||||
|
[_delegate dataControllerBeginUpdates:self];
|
||||||
|
}];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)endUpdates
|
- (void)endUpdates
|
||||||
@ -529,32 +527,11 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
|
|
||||||
- (void)endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
|
- (void)endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
|
||||||
{
|
{
|
||||||
_batchUpdateCounter--;
|
|
||||||
|
|
||||||
if (_batchUpdateCounter == 0) {
|
|
||||||
LOG(@"endUpdatesWithCompletion - beginning");
|
LOG(@"endUpdatesWithCompletion - beginning");
|
||||||
|
ASDisplayNodeAssertMainThread();
|
||||||
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
|
||||||
[_mainSerialQueue performBlockOnMainThread:^{
|
|
||||||
// Deep copy _completedNodes to _externalCompletedNodes.
|
|
||||||
// Any external queries from now on will be done on _externalCompletedNodes, to guarantee data consistency with the delegate.
|
|
||||||
_externalCompletedNodes = ASTwoDimensionalArrayDeepMutableCopy(_completedNodes[ASDataControllerRowNodeKind]);
|
|
||||||
|
|
||||||
LOG(@"endUpdatesWithCompletion - begin updates call to delegate");
|
|
||||||
[_delegate dataControllerBeginUpdates:self];
|
|
||||||
}];
|
|
||||||
});
|
|
||||||
|
|
||||||
// Running these commands may result in blocking on an _editingTransactionQueue operation that started even before -beginUpdates.
|
// Running these commands may result in blocking on an _editingTransactionQueue operation that started even before -beginUpdates.
|
||||||
// Each subsequent command in the queue will also wait on the full asynchronous completion of the prior command's edit transaction.
|
// Each subsequent command in the queue will also wait on the full asynchronous completion of the prior command's edit transaction.
|
||||||
LOG(@"endUpdatesWithCompletion - %zd blocks to run", _pendingEditCommandBlocks.count);
|
|
||||||
NSUInteger i = 0;
|
|
||||||
for (dispatch_block_t block in _pendingEditCommandBlocks) {
|
|
||||||
LOG(@"endUpdatesWithCompletion - running block #%zd", i);
|
|
||||||
block();
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
[_pendingEditCommandBlocks removeAllObjects];
|
|
||||||
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
||||||
[_mainSerialQueue performBlockOnMainThread:^{
|
[_mainSerialQueue performBlockOnMainThread:^{
|
||||||
// Now that the transaction is done, _completedNodes can be accessed externally again.
|
// Now that the transaction is done, _completedNodes can be accessed externally again.
|
||||||
@ -565,43 +542,17 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queues the given operation until an `endUpdates` synchronize update is completed.
|
|
||||||
*
|
|
||||||
* If this method is called outside of a begin/endUpdates batch update, the block is
|
|
||||||
* executed immediately.
|
|
||||||
*/
|
|
||||||
- (void)performEditCommandWithBlock:(void (^)(void))block
|
|
||||||
{
|
|
||||||
// This method needs to block the thread and synchronously perform the operation if we are not
|
|
||||||
// queuing commands for begin/endUpdates. If we are queuing, it needs to return immediately.
|
|
||||||
if (!_initialReloadDataHasBeenCalled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (block == nil) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have never performed a reload, there is no value in executing edit operations as the initial
|
|
||||||
// reload will directly re-query the latest state of the datasource - so completely skip the block in this case.
|
|
||||||
if (_batchUpdateCounter == 0) {
|
|
||||||
block();
|
|
||||||
} else {
|
|
||||||
[_pendingEditCommandBlocks addObject:block];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Section Editing (External API)
|
#pragma mark - Section Editing (External API)
|
||||||
|
|
||||||
- (void)insertSections:(NSIndexSet *)sections withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)insertSections:(NSIndexSet *)sections withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
[self performEditCommandWithBlock:^{
|
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|
||||||
LOG(@"Edit Command - insertSections: %@", sections);
|
LOG(@"Edit Command - insertSections: %@", sections);
|
||||||
|
if (!_initialReloadDataHasBeenCalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
NSArray<ASIndexedNodeContext *> *contexts = [self _populateFromDataSourceWithSectionIndexSet:sections];
|
NSArray<ASIndexedNodeContext *> *contexts = [self _populateFromDataSourceWithSectionIndexSet:sections];
|
||||||
@ -621,14 +572,16 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
|
|
||||||
[self _batchLayoutAndInsertNodesFromContexts:contexts withAnimationOptions:animationOptions];
|
[self _batchLayoutAndInsertNodesFromContexts:contexts withAnimationOptions:animationOptions];
|
||||||
});
|
});
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)deleteSections:(NSIndexSet *)sections withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)deleteSections:(NSIndexSet *)sections withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
[self performEditCommandWithBlock:^{
|
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
LOG(@"Edit Command - deleteSections: %@", sections);
|
LOG(@"Edit Command - deleteSections: %@", sections);
|
||||||
|
if (!_initialReloadDataHasBeenCalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||||
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
||||||
[self willDeleteSections:sections];
|
[self willDeleteSections:sections];
|
||||||
@ -640,7 +593,6 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||||
[self _deleteSectionsAtIndexSet:sections withAnimationOptions:animationOptions];
|
[self _deleteSectionsAtIndexSet:sections withAnimationOptions:animationOptions];
|
||||||
});
|
});
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reloadSections:(NSIndexSet *)sections withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)reloadSections:(NSIndexSet *)sections withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
@ -650,10 +602,13 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
|
|
||||||
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
[self performEditCommandWithBlock:^{
|
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
LOG(@"Edit Command - moveSection");
|
LOG(@"Edit Command - moveSection");
|
||||||
|
|
||||||
|
if (!_initialReloadDataHasBeenCalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||||
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
dispatch_group_async(_editingTransactionGroup, _editingTransactionQueue, ^{
|
||||||
[self willMoveSection:section toSection:newSection];
|
[self willMoveSection:section toSection:newSection];
|
||||||
@ -676,18 +631,17 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
// Don't re-calculate size for moving
|
// Don't re-calculate size for moving
|
||||||
[self _insertNodes:nodes atIndexPaths:updatedIndexPaths withAnimationOptions:animationOptions];
|
[self _insertNodes:nodes atIndexPaths:updatedIndexPaths withAnimationOptions:animationOptions];
|
||||||
});
|
});
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Backing store manipulation optional hooks (Subclass API)
|
#pragma mark - Backing store manipulation optional hooks (Subclass API)
|
||||||
|
|
||||||
- (void)prepareForReloadData
|
- (void)prepareForReloadDataWithSectionCount:(NSInteger)newSectionCount
|
||||||
{
|
{
|
||||||
// Optional template hook for subclasses (See ASDataController+Subclasses.h)
|
// Optional template hook for subclasses (See ASDataController+Subclasses.h)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)willReloadData
|
- (void)willReloadDataWithSectionCount:(NSInteger)newSectionCount
|
||||||
{
|
{
|
||||||
// Optional template hook for subclasses (See ASDataController+Subclasses.h)
|
// Optional template hook for subclasses (See ASDataController+Subclasses.h)
|
||||||
}
|
}
|
||||||
@ -736,8 +690,11 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
|
|
||||||
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
[self performEditCommandWithBlock:^{
|
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
if (!_initialReloadDataHasBeenCalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LOG(@"Edit Command - insertRows: %@", indexPaths);
|
LOG(@"Edit Command - insertRows: %@", indexPaths);
|
||||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
@ -765,13 +722,16 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
LOG(@"Edit Transaction - insertRows: %@", indexPaths);
|
LOG(@"Edit Transaction - insertRows: %@", indexPaths);
|
||||||
[self _batchLayoutAndInsertNodesFromContexts:contexts withAnimationOptions:animationOptions];
|
[self _batchLayoutAndInsertNodesFromContexts:contexts withAnimationOptions:animationOptions];
|
||||||
});
|
});
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
[self performEditCommandWithBlock:^{
|
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|
||||||
|
if (!_initialReloadDataHasBeenCalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LOG(@"Edit Command - deleteRows: %@", indexPaths);
|
LOG(@"Edit Command - deleteRows: %@", indexPaths);
|
||||||
|
|
||||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||||
@ -788,7 +748,6 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
LOG(@"Edit Transaction - deleteRows: %@", indexPaths);
|
LOG(@"Edit Transaction - deleteRows: %@", indexPaths);
|
||||||
[self _deleteNodesAtIndexPaths:sortedIndexPaths withAnimationOptions:animationOptions];
|
[self _deleteNodesAtIndexPaths:sortedIndexPaths withAnimationOptions:animationOptions];
|
||||||
});
|
});
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
@ -798,8 +757,11 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
|
|
||||||
- (void)relayoutAllNodes
|
- (void)relayoutAllNodes
|
||||||
{
|
{
|
||||||
[self performEditCommandWithBlock:^{
|
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
if (!_initialReloadDataHasBeenCalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LOG(@"Edit Command - relayoutRows");
|
LOG(@"Edit Command - relayoutRows");
|
||||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
@ -813,7 +775,6 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_relayoutNodesOfKind:(NSString *)kind
|
- (void)_relayoutNodesOfKind:(NSString *)kind
|
||||||
@ -840,8 +801,11 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
|
|
||||||
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
[self performEditCommandWithBlock:^{
|
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
if (!_initialReloadDataHasBeenCalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LOG(@"Edit Command - moveRow: %@ > %@", indexPath, newIndexPath);
|
LOG(@"Edit Command - moveRow: %@ > %@", indexPath, newIndexPath);
|
||||||
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
@ -855,7 +819,6 @@ NSString * const ASDataControllerRowNodeKind = @"_ASDataControllerRowNodeKind";
|
|||||||
NSArray *newIndexPaths = @[newIndexPath];
|
NSArray *newIndexPaths = @[newIndexPath];
|
||||||
[self _insertNodes:nodes atIndexPaths:newIndexPaths withAnimationOptions:animationOptions];
|
[self _insertNodes:nodes atIndexPaths:newIndexPaths withAnimationOptions:animationOptions];
|
||||||
});
|
});
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Data Querying (Subclass API)
|
#pragma mark - Data Querying (Subclass API)
|
||||||
|
|||||||
@ -91,8 +91,7 @@
|
|||||||
selector == @selector(collectionView:nodeForItemAtIndexPath:) ||
|
selector == @selector(collectionView:nodeForItemAtIndexPath:) ||
|
||||||
selector == @selector(collectionView:nodeBlockForItemAtIndexPath:) ||
|
selector == @selector(collectionView:nodeBlockForItemAtIndexPath:) ||
|
||||||
selector == @selector(collectionView:numberOfItemsInSection:) ||
|
selector == @selector(collectionView:numberOfItemsInSection:) ||
|
||||||
selector == @selector(collectionView:constrainedSizeForNodeAtIndexPath:) ||
|
selector == @selector(collectionView:constrainedSizeForNodeAtIndexPath:)
|
||||||
selector == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,17 +36,17 @@ ASEnvironmentTraitCollection ASEnvironmentTraitCollectionMakeDefault()
|
|||||||
|
|
||||||
ASEnvironmentTraitCollection ASEnvironmentTraitCollectionFromUITraitCollection(UITraitCollection *traitCollection)
|
ASEnvironmentTraitCollection ASEnvironmentTraitCollectionFromUITraitCollection(UITraitCollection *traitCollection)
|
||||||
{
|
{
|
||||||
ASEnvironmentTraitCollection asyncTraitCollection;
|
ASEnvironmentTraitCollection environmentTraitCollection = ASEnvironmentTraitCollectionMakeDefault();
|
||||||
if (AS_AT_LEAST_IOS8) {
|
if (AS_AT_LEAST_IOS8) {
|
||||||
asyncTraitCollection.displayScale = traitCollection.displayScale;
|
environmentTraitCollection.displayScale = traitCollection.displayScale;
|
||||||
asyncTraitCollection.horizontalSizeClass = traitCollection.horizontalSizeClass;
|
environmentTraitCollection.horizontalSizeClass = traitCollection.horizontalSizeClass;
|
||||||
asyncTraitCollection.verticalSizeClass = traitCollection.verticalSizeClass;
|
environmentTraitCollection.verticalSizeClass = traitCollection.verticalSizeClass;
|
||||||
asyncTraitCollection.userInterfaceIdiom = traitCollection.userInterfaceIdiom;
|
environmentTraitCollection.userInterfaceIdiom = traitCollection.userInterfaceIdiom;
|
||||||
if (AS_AT_LEAST_IOS9) {
|
if (AS_AT_LEAST_IOS9) {
|
||||||
asyncTraitCollection.forceTouchCapability = traitCollection.forceTouchCapability;
|
environmentTraitCollection.forceTouchCapability = traitCollection.forceTouchCapability;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return asyncTraitCollection;
|
return environmentTraitCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnvironmentTraitCollection lhs, ASEnvironmentTraitCollection rhs)
|
BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnvironmentTraitCollection lhs, ASEnvironmentTraitCollection rhs)
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#import "ASHighlightOverlayLayer.h"
|
#import "ASHighlightOverlayLayer.h"
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ static const UIEdgeInsets padding = {2, 4, 1.5, 4};
|
|||||||
if (targetLayer != nil) {
|
if (targetLayer != nil) {
|
||||||
rect = [self convertRect:rect fromLayer:targetLayer];
|
rect = [self convertRect:rect fromLayer:targetLayer];
|
||||||
}
|
}
|
||||||
rect = CGRectMake(roundf(rect.origin.x), roundf(rect.origin.y), roundf(rect.size.width), roundf(rect.size.height));
|
rect = CGRectMake(std::round(rect.origin.x), std::round(rect.origin.y), std::round(rect.size.width), std::round(rect.size.height));
|
||||||
|
|
||||||
CGFloat minX = rect.origin.x - padding.left;
|
CGFloat minX = rect.origin.x - padding.left;
|
||||||
CGFloat maxX = CGRectGetMaxX(rect) + padding.right;
|
CGFloat maxX = CGRectGetMaxX(rect) + padding.right;
|
||||||
|
|||||||
@ -134,6 +134,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
- (NSArray<NSArray <ASCellNode *> *> *)completedNodes;
|
- (NSArray<NSArray <ASCellNode *> *> *)completedNodes;
|
||||||
|
|
||||||
|
- (NSString *)nameForRangeControllerDataSource;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -11,13 +11,16 @@
|
|||||||
#import "ASRangeController.h"
|
#import "ASRangeController.h"
|
||||||
|
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASWeakSet.h"
|
#import "ASCellNode.h"
|
||||||
#import "ASDisplayNodeExtras.h"
|
#import "ASDisplayNodeExtras.h"
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
#import "ASMultidimensionalArrayUtils.h"
|
#import "ASMultidimensionalArrayUtils.h"
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
|
#import "ASMultiDimensionalArrayUtils.h"
|
||||||
|
#import "ASWeakSet.h"
|
||||||
|
|
||||||
#import "ASDisplayNode+FrameworkPrivate.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
#import "ASCellNode.h"
|
#import "AsyncDisplayKit+Debug.h"
|
||||||
|
|
||||||
#define AS_RANGECONTROLLER_LOG_UPDATE_FREQ 0
|
#define AS_RANGECONTROLLER_LOG_UPDATE_FREQ 0
|
||||||
|
|
||||||
@ -64,6 +67,10 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
|||||||
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if ([ASRangeController shouldShowRangeDebugOverlay]) {
|
||||||
|
[self addRangeControllerToRangeDebugOverlay];
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,6 +342,25 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This code is for debugging only, but would be great to clean up with a delegate method implementation.
|
||||||
|
if ([ASRangeController shouldShowRangeDebugOverlay]) {
|
||||||
|
ASScrollDirection scrollableDirections = ASScrollDirectionUp | ASScrollDirectionDown;
|
||||||
|
if ([_dataSource isKindOfClass:NSClassFromString(@"ASCollectionView")]) {
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
||||||
|
scrollableDirections = (ASScrollDirection)[_dataSource performSelector:@selector(scrollableDirections)];
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
}
|
||||||
|
|
||||||
|
[self updateRangeController:self
|
||||||
|
withScrollableDirections:scrollableDirections
|
||||||
|
scrollDirection:scrollDirection
|
||||||
|
rangeMode:rangeMode
|
||||||
|
displayTuningParameters:parametersDisplay
|
||||||
|
fetchDataTuningParameters:parametersFetchData
|
||||||
|
interfaceState:selfInterfaceState];
|
||||||
|
}
|
||||||
|
|
||||||
_rangeIsValid = YES;
|
_rangeIsValid = YES;
|
||||||
|
|
||||||
#if ASRangeControllerLoggingEnabled
|
#if ASRangeControllerLoggingEnabled
|
||||||
|
|||||||
@ -34,6 +34,8 @@ static inline BOOL ASDisplayNodeThreadIsMain()
|
|||||||
#import <QuartzCore/QuartzCore.h>
|
#import <QuartzCore/QuartzCore.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
For use with ASDN::StaticMutex only.
|
For use with ASDN::StaticMutex only.
|
||||||
*/
|
*/
|
||||||
@ -98,6 +100,50 @@ namespace ASDN {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class SharedLocker
|
||||||
|
{
|
||||||
|
std::shared_ptr<T> _l;
|
||||||
|
|
||||||
|
#if TIME_LOCKER
|
||||||
|
CFTimeInterval _ti;
|
||||||
|
const char *_name;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
#if !TIME_LOCKER
|
||||||
|
|
||||||
|
SharedLocker (std::shared_ptr<T> const& l) ASDISPLAYNODE_NOTHROW : _l (l) {
|
||||||
|
assert(_l != nullptr);
|
||||||
|
_l->lock ();
|
||||||
|
}
|
||||||
|
|
||||||
|
~SharedLocker () {
|
||||||
|
_l->unlock ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// non-copyable.
|
||||||
|
SharedLocker(const SharedLocker<T>&) = delete;
|
||||||
|
SharedLocker &operator=(const SharedLocker<T>&) = delete;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
SharedLocker (std::shared_ptr<T> const& l, const char *name = NULL) ASDISPLAYNODE_NOTHROW : _l (l), _name(name) {
|
||||||
|
_ti = CACurrentMediaTime();
|
||||||
|
_l->lock ();
|
||||||
|
}
|
||||||
|
|
||||||
|
~SharedLocker () {
|
||||||
|
_l->unlock ();
|
||||||
|
if (_name) {
|
||||||
|
printf(_name, NULL);
|
||||||
|
printf(" dt:%f\n", CACurrentMediaTime() - _ti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class Unlocker
|
class Unlocker
|
||||||
@ -110,6 +156,17 @@ namespace ASDN {
|
|||||||
Unlocker &operator=(Unlocker<T>&) = delete;
|
Unlocker &operator=(Unlocker<T>&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class SharedUnlocker
|
||||||
|
{
|
||||||
|
std::shared_ptr<T> _l;
|
||||||
|
public:
|
||||||
|
SharedUnlocker (std::shared_ptr<T> const& l) ASDISPLAYNODE_NOTHROW : _l (l) { _l->unlock (); }
|
||||||
|
~SharedUnlocker () { _l->lock (); }
|
||||||
|
SharedUnlocker(SharedUnlocker<T>&) = delete;
|
||||||
|
SharedUnlocker &operator=(SharedUnlocker<T>&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
struct Mutex
|
struct Mutex
|
||||||
{
|
{
|
||||||
/// Constructs a non-recursive mutex (the default).
|
/// Constructs a non-recursive mutex (the default).
|
||||||
@ -164,7 +221,9 @@ namespace ASDN {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef Locker<Mutex> MutexLocker;
|
typedef Locker<Mutex> MutexLocker;
|
||||||
|
typedef SharedLocker<Mutex> MutexSharedLocker;
|
||||||
typedef Unlocker<Mutex> MutexUnlocker;
|
typedef Unlocker<Mutex> MutexUnlocker;
|
||||||
|
typedef SharedUnlocker<Mutex> MutexSharedUnlocker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If you are creating a static mutex, use StaticMutex and specify its default value as one of ASDISPLAYNODE_MUTEX_INITIALIZER
|
If you are creating a static mutex, use StaticMutex and specify its default value as one of ASDISPLAYNODE_MUTEX_INITIALIZER
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
@interface ASWeakProxy : NSObject
|
@interface ASWeakProxy : NSProxy
|
||||||
|
|
||||||
@property (nonatomic, weak, readonly) id target;
|
@property (nonatomic, weak, readonly) id target;
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
- (instancetype)initWithTarget:(id)target
|
- (instancetype)initWithTarget:(id)target
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self) {
|
||||||
_target = target;
|
_target = target;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@ -32,4 +32,24 @@
|
|||||||
return _target;
|
return _target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
|
||||||
|
{
|
||||||
|
// Check for a compiled definition for the selector
|
||||||
|
NSMethodSignature *methodSignature = [[_target class] instanceMethodSignatureForSelector:aSelector];
|
||||||
|
|
||||||
|
// Unfortunately, in order to get this object to work properly, the use of a method which creates an NSMethodSignature
|
||||||
|
// from a C string. -methodSignatureForSelector is called when a compiled definition for the selector cannot be found.
|
||||||
|
// This is the place where we have to create our own dud NSMethodSignature. This is necessary because if this method
|
||||||
|
// returns nil, a selector not found exception is raised. The string argument to -signatureWithObjCTypes: outlines
|
||||||
|
// the return type and arguments to the message. To return a dud NSMethodSignature, pretty much any signature will
|
||||||
|
// suffice. Since the -forwardInvocation call will do nothing if the delegate does not respond to the selector,
|
||||||
|
// the dud NSMethodSignature simply gets us around the exception.
|
||||||
|
return methodSignature ?: [NSMethodSignature signatureWithObjCTypes:"@^v^c"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)forwardInvocation:(NSInvocation *)invocation
|
||||||
|
{
|
||||||
|
// If we are down here this means _target where nil. Just don't do anything to prevent a crash
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -14,6 +14,14 @@
|
|||||||
#import "ASBaseDefines.h"
|
#import "ASBaseDefines.h"
|
||||||
#import "ASLayoutController.h"
|
#import "ASLayoutController.h"
|
||||||
|
|
||||||
|
#ifndef CGFLOAT_EPSILON
|
||||||
|
#if CGFLOAT_IS_DOUBLE
|
||||||
|
#define CGFLOAT_EPSILON DBL_EPSILON
|
||||||
|
#else
|
||||||
|
#define CGFLOAT_EPSILON FLT_EPSILON
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
ASDISPLAYNODE_EXTERN_C_BEGIN
|
ASDISPLAYNODE_EXTERN_C_BEGIN
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "NSArray+Diffing.h"
|
#import "NSArray+Diffing.h"
|
||||||
|
#import "ASAssert.h"
|
||||||
|
|
||||||
@implementation NSArray (Diffing)
|
@implementation NSArray (Diffing)
|
||||||
|
|
||||||
@ -58,12 +59,24 @@
|
|||||||
NSInteger selfCount = self.count;
|
NSInteger selfCount = self.count;
|
||||||
NSInteger arrayCount = array.count;
|
NSInteger arrayCount = array.count;
|
||||||
|
|
||||||
NSInteger lengths[selfCount+1][arrayCount+1];
|
// Allocate the diff map in the heap so we don't blow the stack for large arrays.
|
||||||
|
NSInteger (*lengths)[arrayCount+1] = NULL;
|
||||||
|
size_t lengthsSize = ((selfCount+1) * sizeof(*lengths));
|
||||||
|
// Would rather use initWithCapacity: to skip the zeroing, but TECHNICALLY
|
||||||
|
// `mutableBytes` is only guaranteed to be non-NULL if the data object has a non-zero length.
|
||||||
|
NS_VALID_UNTIL_END_OF_SCOPE NSMutableData *lengthsData = [[NSMutableData alloc] initWithLength:lengthsSize];
|
||||||
|
lengths = lengthsData.mutableBytes;
|
||||||
|
if (lengths == NULL) {
|
||||||
|
ASDisplayNodeFailAssert(@"Failed to allocate memory for diffing with size %tu", lengthsSize);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
for (NSInteger i = 0; i <= selfCount; i++) {
|
for (NSInteger i = 0; i <= selfCount; i++) {
|
||||||
|
id selfObj = i > 0 ? self[i-1] : nil;
|
||||||
for (NSInteger j = 0; j <= arrayCount; j++) {
|
for (NSInteger j = 0; j <= arrayCount; j++) {
|
||||||
if (i == 0 || j == 0) {
|
if (i == 0 || j == 0) {
|
||||||
lengths[i][j] = 0;
|
lengths[i][j] = 0;
|
||||||
} else if (comparison(self[i-1], array[j-1])) {
|
} else if (comparison(selfObj, array[j-1])) {
|
||||||
lengths[i][j] = 1 + lengths[i-1][j-1];
|
lengths[i][j] = 1 + lengths[i-1][j-1];
|
||||||
} else {
|
} else {
|
||||||
lengths[i][j] = MAX(lengths[i-1][j], lengths[i][j-1]);
|
lengths[i][j] = MAX(lengths[i-1][j], lengths[i][j-1]);
|
||||||
@ -102,17 +102,10 @@
|
|||||||
|
|
||||||
- (void)layoutSublayers
|
- (void)layoutSublayers
|
||||||
{
|
{
|
||||||
|
ASDisplayNodeAssertMainThread();
|
||||||
[super layoutSublayers];
|
[super layoutSublayers];
|
||||||
|
|
||||||
ASDisplayNode *node = self.asyncdisplaykit_node;
|
[self.asyncdisplaykit_node __layout];
|
||||||
if (ASDisplayNodeThreadIsMain()) {
|
|
||||||
[node __layout];
|
|
||||||
} else {
|
|
||||||
ASDisplayNodeFailAssert(@"not reached assertion");
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
|
||||||
[node __layout];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setNeedsDisplay
|
- (void)setNeedsDisplay
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "_ASDisplayView.h"
|
#import "_ASDisplayView.h"
|
||||||
|
#import "_ASDisplayViewAccessiblity.h"
|
||||||
|
|
||||||
#import "_ASCoreAnimationExtras.h"
|
#import "_ASCoreAnimationExtras.h"
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
@ -26,9 +27,12 @@
|
|||||||
@implementation _ASDisplayView
|
@implementation _ASDisplayView
|
||||||
{
|
{
|
||||||
__unsafe_unretained ASDisplayNode *_node; // Though UIView has a .node property added via category, since we can add an ivar to a subclass, use that for performance.
|
__unsafe_unretained ASDisplayNode *_node; // Though UIView has a .node property added via category, since we can add an ivar to a subclass, use that for performance.
|
||||||
|
|
||||||
BOOL _inHitTest;
|
BOOL _inHitTest;
|
||||||
BOOL _inPointInside;
|
BOOL _inPointInside;
|
||||||
|
|
||||||
NSArray *_accessibleElements;
|
NSArray *_accessibleElements;
|
||||||
|
CGRect _lastAccessibleElementsFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@synthesize asyncdisplaykit_node = _node;
|
@synthesize asyncdisplaykit_node = _node;
|
||||||
@ -39,10 +43,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - NSObject Overrides
|
#pragma mark - NSObject Overrides
|
||||||
- (instancetype)init
|
|
||||||
{
|
|
||||||
return [self initWithFrame:CGRectZero];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
@ -53,14 +53,6 @@
|
|||||||
|
|
||||||
#pragma mark - UIView Overrides
|
#pragma mark - UIView Overrides
|
||||||
|
|
||||||
- (instancetype)initWithFrame:(CGRect)frame
|
|
||||||
{
|
|
||||||
if (!(self = [super initWithFrame:frame]))
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)willMoveToWindow:(UIWindow *)newWindow
|
- (void)willMoveToWindow:(UIWindow *)newWindow
|
||||||
{
|
{
|
||||||
BOOL visible = (newWindow != nil);
|
BOOL visible = (newWindow != nil);
|
||||||
@ -126,7 +118,6 @@
|
|||||||
[newSuperview.asyncdisplaykit_node addSubnode:_node];
|
[newSuperview.asyncdisplaykit_node addSubnode:_node];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didMoveToSuperview
|
- (void)didMoveToSuperview
|
||||||
@ -169,27 +160,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setNeedsDisplay
|
- (void)addSubview:(UIView *)view
|
||||||
{
|
{
|
||||||
// Standard implementation does not actually get to the layer, at least for views that don't implement drawRect:.
|
[super addSubview:view];
|
||||||
if (ASDisplayNodeThreadIsMain()) {
|
|
||||||
[self.layer setNeedsDisplay];
|
#ifndef ASDK_ACCESSIBILITY_DISABLE
|
||||||
} else {
|
self.accessibleElements = nil;
|
||||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
#endif
|
||||||
[self.layer setNeedsDisplay];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setNeedsLayout
|
- (void)willRemoveSubview:(UIView *)subview
|
||||||
{
|
{
|
||||||
if (ASDisplayNodeThreadIsMain()) {
|
[super willRemoveSubview:subview];
|
||||||
[super setNeedsLayout];
|
|
||||||
} else {
|
#ifndef ASDK_ACCESSIBILITY_DISABLE
|
||||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
self.accessibleElements = nil;
|
||||||
[super setNeedsLayout];
|
#endif
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setNeedsDisplay
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssertMainThread();
|
||||||
|
// Standard implementation does not actually get to the layer, at least for views that don't implement drawRect:.
|
||||||
|
[self.layer setNeedsDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIViewContentMode)contentMode
|
- (UIViewContentMode)contentMode
|
||||||
|
|||||||
@ -9,3 +9,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface _ASDisplayView (UIAccessibilityContainer)
|
||||||
|
@property (copy, nonatomic) NSArray *accessibleElements;
|
||||||
|
@end
|
||||||
|
|||||||
@ -8,17 +8,55 @@
|
|||||||
// of patent rights can be found in the PATENTS file in the same directory.
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#ifndef ASDK_ACCESSIBILITY_DISABLE
|
||||||
|
|
||||||
#import "_ASDisplayView.h"
|
#import "_ASDisplayView.h"
|
||||||
#import "ASDisplayNodeExtras.h"
|
#import "ASDisplayNodeExtras.h"
|
||||||
#import "ASDisplayNode+FrameworkPrivate.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
|
|
||||||
#pragma mark - UIAccessibilityElement
|
#pragma mark - UIAccessibilityElement
|
||||||
|
|
||||||
@implementation UIAccessibilityElement (_ASDisplayView)
|
typedef NSComparisonResult (^SortAccessibilityElementsComparator)(UIAccessibilityElement *, UIAccessibilityElement *);
|
||||||
|
|
||||||
+ (UIAccessibilityElement *)accessibilityElementWithContainer:(id)container node:(ASDisplayNode *)node
|
/// Sort accessiblity elements first by y and than by x origin.
|
||||||
|
static void SortAccessibilityElements(NSMutableArray *elements)
|
||||||
{
|
{
|
||||||
UIAccessibilityElement *accessibilityElement = [[UIAccessibilityElement alloc] initWithAccessibilityContainer:container];
|
ASDisplayNodeCAssertNotNil(elements, @"Should pass in a NSMutableArray");
|
||||||
|
|
||||||
|
static SortAccessibilityElementsComparator comparator = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
comparator = ^NSComparisonResult(UIAccessibilityElement *a, UIAccessibilityElement *b) {
|
||||||
|
CGPoint originA = a.accessibilityFrame.origin;
|
||||||
|
CGPoint originB = b.accessibilityFrame.origin;
|
||||||
|
if (originA.y == originB.y) {
|
||||||
|
if (originA.x == originB.x) {
|
||||||
|
return NSOrderedSame;
|
||||||
|
}
|
||||||
|
return (originA.x < originB.x) ? NSOrderedAscending : NSOrderedDescending;
|
||||||
|
}
|
||||||
|
return (originA.y < originB.y) ? NSOrderedAscending : NSOrderedDescending;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
[elements sortUsingComparator:comparator];
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface ASAccessibilityElement : UIAccessibilityElement
|
||||||
|
|
||||||
|
@property (nonatomic, strong) ASDisplayNode *node;
|
||||||
|
@property (nonatomic, strong) ASDisplayNode *containerNode;
|
||||||
|
|
||||||
|
+ (ASAccessibilityElement *)accessibilityElementWithContainer:(UIView *)container node:(ASDisplayNode *)node containerNode:(ASDisplayNode *)containerNode;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ASAccessibilityElement
|
||||||
|
|
||||||
|
+ (ASAccessibilityElement *)accessibilityElementWithContainer:(UIView *)container node:(ASDisplayNode *)node containerNode:(ASDisplayNode *)containerNode
|
||||||
|
{
|
||||||
|
ASAccessibilityElement *accessibilityElement = [[ASAccessibilityElement alloc] initWithAccessibilityContainer:container];
|
||||||
|
accessibilityElement.node = node;
|
||||||
|
accessibilityElement.containerNode = containerNode;
|
||||||
accessibilityElement.accessibilityIdentifier = node.accessibilityIdentifier;
|
accessibilityElement.accessibilityIdentifier = node.accessibilityIdentifier;
|
||||||
accessibilityElement.accessibilityLabel = node.accessibilityLabel;
|
accessibilityElement.accessibilityLabel = node.accessibilityLabel;
|
||||||
accessibilityElement.accessibilityHint = node.accessibilityHint;
|
accessibilityElement.accessibilityHint = node.accessibilityHint;
|
||||||
@ -27,101 +65,116 @@
|
|||||||
return accessibilityElement;
|
return accessibilityElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
- (CGRect)accessibilityFrame
|
||||||
|
{
|
||||||
|
CGRect accessibilityFrame = [self.containerNode convertRect:self.node.bounds fromNode:self.node];
|
||||||
|
accessibilityFrame = UIAccessibilityConvertFrameToScreenCoordinates(accessibilityFrame, self.accessibilityContainer);
|
||||||
|
return accessibilityFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
#pragma mark - _ASDisplayView / UIAccessibilityContainer
|
#pragma mark - _ASDisplayView / UIAccessibilityContainer
|
||||||
|
|
||||||
static NSArray *ASCollectUIAccessibilityElementsForNode(ASDisplayNode *viewNode, ASDisplayNode *subnode, id container) {
|
/// Collect all subnodes for the given node by walking down the subnode tree and calculates the screen coordinates based on the containerNode and container
|
||||||
NSMutableArray *accessibleElements = [NSMutableArray array];
|
static void CollectUIAccessibilityElementsForNode(ASDisplayNode *node, ASDisplayNode *containerNode, id container, NSMutableArray *elements)
|
||||||
ASDisplayNodePerformBlockOnEveryNodeBFS(subnode, ^(ASDisplayNode * _Nonnull currentNode) {
|
{
|
||||||
|
ASDisplayNodeCAssertNotNil(elements, @"Should pass in a NSMutableArray");
|
||||||
|
|
||||||
|
ASDisplayNodePerformBlockOnEveryNodeBFS(node, ^(ASDisplayNode * _Nonnull currentNode) {
|
||||||
// For every subnode that is layer backed or it's supernode has shouldRasterizeDescendants enabled
|
// For every subnode that is layer backed or it's supernode has shouldRasterizeDescendants enabled
|
||||||
// we have to create a UIAccessibilityElement as no view for this node exists
|
// we have to create a UIAccessibilityElement as no view for this node exists
|
||||||
if (currentNode != viewNode && currentNode.isAccessibilityElement) {
|
if (currentNode != containerNode && currentNode.isAccessibilityElement) {
|
||||||
UIAccessibilityElement *accessibilityElement = [UIAccessibilityElement accessibilityElementWithContainer:container node:currentNode];
|
UIAccessibilityElement *accessibilityElement = [ASAccessibilityElement accessibilityElementWithContainer:container node:currentNode containerNode:containerNode];
|
||||||
// As the node hierarchy is flattened it's necessary to convert the frame for each subnode in the tree to the
|
[elements addObject:accessibilityElement];
|
||||||
// coordinate system of the supernode
|
|
||||||
CGRect frame = [viewNode convertRect:currentNode.bounds fromNode:currentNode];
|
|
||||||
accessibilityElement.accessibilityFrame = UIAccessibilityConvertFrameToScreenCoordinates(frame, container);
|
|
||||||
[accessibleElements addObject:accessibilityElement];
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return [accessibleElements copy];
|
/// Collect all accessibliity elements for a given view and view node
|
||||||
|
static void CollectAccessibilityElementsForView(_ASDisplayView *view, NSMutableArray *elements)
|
||||||
|
{
|
||||||
|
ASDisplayNodeCAssertNotNil(elements, @"Should pass in a NSMutableArray");
|
||||||
|
|
||||||
|
ASDisplayNode *node = view.asyncdisplaykit_node;
|
||||||
|
|
||||||
|
// Handle rasterize case
|
||||||
|
if (node.shouldRasterizeDescendants) {
|
||||||
|
CollectUIAccessibilityElementsForNode(node, node, view, elements);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ASDisplayNode *subnode in node.subnodes) {
|
||||||
|
if (subnode.isAccessibilityElement) {
|
||||||
|
|
||||||
|
// An accessiblityElement can either be a UIView or a UIAccessibilityElement
|
||||||
|
if (subnode.isLayerBacked) {
|
||||||
|
// No view for layer backed nodes exist. It's necessary to create a UIAccessibilityElement that represents this node
|
||||||
|
UIAccessibilityElement *accessiblityElement = [ASAccessibilityElement accessibilityElementWithContainer:view node:subnode containerNode:node];
|
||||||
|
[elements addObject:accessiblityElement];
|
||||||
|
} else {
|
||||||
|
// Accessiblity element is not layer backed just add the view as accessibility element
|
||||||
|
[elements addObject:subnode.view];
|
||||||
|
}
|
||||||
|
} else if (subnode.isLayerBacked) {
|
||||||
|
// Go down the hierarchy of the layer backed subnode and collect all of the UIAccessibilityElement
|
||||||
|
CollectUIAccessibilityElementsForNode(subnode, node, view, elements);
|
||||||
|
} else if ([subnode accessibilityElementCount] > 0) {
|
||||||
|
// UIView is itself a UIAccessibilityContainer just add it
|
||||||
|
[elements addObject:subnode.view];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface _ASDisplayView () {
|
@interface _ASDisplayView () {
|
||||||
NSArray *_accessibleElements;
|
NSArray *_accessibleElements;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _ASDisplayView (UIAccessibilityContainer)
|
@implementation _ASDisplayView (UIAccessibilityContainer)
|
||||||
|
|
||||||
#pragma mark - UIAccessibility
|
#pragma mark - UIAccessibility
|
||||||
|
|
||||||
|
- (void)setAccessibleElements:(NSArray *)accessibleElements
|
||||||
|
{
|
||||||
|
_accessibleElements = nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSArray *)accessibleElements
|
- (NSArray *)accessibleElements
|
||||||
{
|
{
|
||||||
ASDisplayNode *viewNode = self.asyncdisplaykit_node;
|
ASDisplayNode *viewNode = self.asyncdisplaykit_node;
|
||||||
if (viewNode == nil) {
|
if (viewNode == nil) {
|
||||||
return nil;
|
return @[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle rasterize case
|
if (_accessibleElements != nil) {
|
||||||
if (viewNode.shouldRasterizeDescendants) {
|
|
||||||
_accessibleElements = ASCollectUIAccessibilityElementsForNode(viewNode, viewNode, self);
|
|
||||||
return _accessibleElements;
|
return _accessibleElements;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle not rasterize case
|
|
||||||
NSMutableArray *accessibleElements = [NSMutableArray array];
|
NSMutableArray *accessibleElements = [NSMutableArray array];
|
||||||
|
CollectAccessibilityElementsForView(self, accessibleElements);
|
||||||
for (ASDisplayNode *subnode in viewNode.subnodes) {
|
SortAccessibilityElements(accessibleElements);
|
||||||
if (subnode.isAccessibilityElement) {
|
_accessibleElements = accessibleElements;
|
||||||
// An accessiblityElement can either be a UIView or a UIAccessibilityElement
|
|
||||||
id accessiblityElement = nil;
|
|
||||||
if (subnode.isLayerBacked) {
|
|
||||||
// No view for layer backed nodes exist. It's necessary to create a UIAccessibilityElement that represents this node
|
|
||||||
accessiblityElement = [UIAccessibilityElement accessibilityElementWithContainer:self node:subnode];
|
|
||||||
} else {
|
|
||||||
accessiblityElement = subnode.view;
|
|
||||||
}
|
|
||||||
[accessiblityElement setAccessibilityFrame:UIAccessibilityConvertFrameToScreenCoordinates(subnode.frame, self)];
|
|
||||||
[accessibleElements addObject:accessiblityElement];
|
|
||||||
} else if (subnode.isLayerBacked) {
|
|
||||||
// Go down the hierarchy of the layer backed subnode and collect all of the UIAccessibilityElement
|
|
||||||
[accessibleElements addObjectsFromArray:ASCollectUIAccessibilityElementsForNode(viewNode, subnode, self)];
|
|
||||||
} else if ([subnode accessibilityElementCount] > 0) {
|
|
||||||
// Add UIAccessibilityContainer
|
|
||||||
[accessibleElements addObject:subnode.view];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_accessibleElements = [accessibleElements copy];
|
|
||||||
|
|
||||||
return _accessibleElements;
|
return _accessibleElements;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSInteger)accessibilityElementCount
|
- (NSInteger)accessibilityElementCount
|
||||||
{
|
{
|
||||||
return [self accessibleElements].count;
|
return self.accessibleElements.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)accessibilityElementAtIndex:(NSInteger)index
|
- (id)accessibilityElementAtIndex:(NSInteger)index
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertNotNil(_accessibleElements, @"At this point _accessibleElements should be created.");
|
return self.accessibleElements[index];
|
||||||
if (_accessibleElements == nil) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _accessibleElements[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSInteger)indexOfAccessibilityElement:(id)element
|
- (NSInteger)indexOfAccessibilityElement:(id)element
|
||||||
{
|
{
|
||||||
if (_accessibleElements == nil) {
|
return [self.accessibleElements indexOfObjectIdenticalTo:element];
|
||||||
return NSNotFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [_accessibleElements indexOfObject:element];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#import "ASAsciiArtBoxCreator.h"
|
#import "ASAsciiArtBoxCreator.h"
|
||||||
|
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
static const NSUInteger kDebugBoxPadding = 2;
|
static const NSUInteger kDebugBoxPadding = 2;
|
||||||
|
|
||||||
typedef NS_ENUM(NSUInteger, PIDebugBoxPaddingLocation)
|
typedef NS_ENUM(NSUInteger, PIDebugBoxPaddingLocation)
|
||||||
@ -69,7 +71,7 @@ typedef NS_ENUM(NSUInteger, PIDebugBoxPaddingLocation)
|
|||||||
|
|
||||||
for (NSString *child in children) {
|
for (NSString *child in children) {
|
||||||
NSMutableArray *lines = [[child componentsSeparatedByString:@"\n"] mutableCopy];
|
NSMutableArray *lines = [[child componentsSeparatedByString:@"\n"] mutableCopy];
|
||||||
NSUInteger topPadding = ceilf((CGFloat)(lineCountPerChild - [lines count])/2.0);
|
NSUInteger topPadding = ceil((CGFloat)(lineCountPerChild - [lines count])/2.0);
|
||||||
NSUInteger bottomPadding = (lineCountPerChild - [lines count])/2.0;
|
NSUInteger bottomPadding = (lineCountPerChild - [lines count])/2.0;
|
||||||
NSUInteger lineLength = [lines[0] length];
|
NSUInteger lineLength = [lines[0] length];
|
||||||
|
|
||||||
@ -98,7 +100,7 @@ typedef NS_ENUM(NSUInteger, PIDebugBoxPaddingLocation)
|
|||||||
NSUInteger totalLineLength = [concatenatedLines[0] length];
|
NSUInteger totalLineLength = [concatenatedLines[0] length];
|
||||||
if (totalLineLength < [parent length]) {
|
if (totalLineLength < [parent length]) {
|
||||||
NSUInteger difference = [parent length] + (2 * kDebugBoxPadding) - totalLineLength;
|
NSUInteger difference = [parent length] + (2 * kDebugBoxPadding) - totalLineLength;
|
||||||
NSUInteger leftPadding = ceilf((CGFloat)difference/2.0);
|
NSUInteger leftPadding = ceil((CGFloat)difference/2.0);
|
||||||
NSUInteger rightPadding = difference/2;
|
NSUInteger rightPadding = difference/2;
|
||||||
|
|
||||||
NSString *leftString = [@"|" debugbox_stringByAddingPadding:@" " count:leftPadding location:PIDebugBoxPaddingLocationEnd];
|
NSString *leftString = [@"|" debugbox_stringByAddingPadding:@" " count:leftPadding location:PIDebugBoxPaddingLocationEnd];
|
||||||
@ -137,7 +139,7 @@ typedef NS_ENUM(NSUInteger, PIDebugBoxPaddingLocation)
|
|||||||
|
|
||||||
if (maxChildLength < [parent length]) {
|
if (maxChildLength < [parent length]) {
|
||||||
NSUInteger difference = [parent length] + (2 * kDebugBoxPadding) - maxChildLength;
|
NSUInteger difference = [parent length] + (2 * kDebugBoxPadding) - maxChildLength;
|
||||||
leftPadding = ceilf((CGFloat)difference/2.0);
|
leftPadding = ceil((CGFloat)difference/2.0);
|
||||||
rightPadding = difference/2;
|
rightPadding = difference/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +149,7 @@ typedef NS_ENUM(NSUInteger, PIDebugBoxPaddingLocation)
|
|||||||
for (NSString *child in children) {
|
for (NSString *child in children) {
|
||||||
NSMutableArray *lines = [[child componentsSeparatedByString:@"\n"] mutableCopy];
|
NSMutableArray *lines = [[child componentsSeparatedByString:@"\n"] mutableCopy];
|
||||||
|
|
||||||
NSUInteger leftLinePadding = ceilf((CGFloat)(maxChildLength - [lines[0] length])/2.0);
|
NSUInteger leftLinePadding = ceil((CGFloat)(maxChildLength - [lines[0] length])/2.0);
|
||||||
NSUInteger rightLinePadding = (maxChildLength - [lines[0] length])/2.0;
|
NSUInteger rightLinePadding = (maxChildLength - [lines[0] length])/2.0;
|
||||||
|
|
||||||
for (NSString *line in lines) {
|
for (NSString *line in lines) {
|
||||||
@ -171,7 +173,7 @@ typedef NS_ENUM(NSUInteger, PIDebugBoxPaddingLocation)
|
|||||||
NSUInteger totalLineLength = [boxStrings[0] length];
|
NSUInteger totalLineLength = [boxStrings[0] length];
|
||||||
[boxStrings addObject:[NSString debugbox_stringWithString:@"-" repeatedCount:totalLineLength]];
|
[boxStrings addObject:[NSString debugbox_stringWithString:@"-" repeatedCount:totalLineLength]];
|
||||||
|
|
||||||
NSUInteger leftPadding = ceilf(((CGFloat)(totalLineLength - [parent length]))/2.0);
|
NSUInteger leftPadding = ceil(((CGFloat)(totalLineLength - [parent length]))/2.0);
|
||||||
NSUInteger rightPadding = (totalLineLength - [parent length])/2;
|
NSUInteger rightPadding = (totalLineLength - [parent length])/2;
|
||||||
|
|
||||||
NSString *topLine = [parent debugbox_stringByAddingPadding:@"-" count:leftPadding location:PIDebugBoxPaddingLocationFront];
|
NSString *topLine = [parent debugbox_stringByAddingPadding:@"-" count:leftPadding location:PIDebugBoxPaddingLocationFront];
|
||||||
|
|||||||
@ -17,7 +17,7 @@ typedef NS_ENUM(NSInteger, ASRelativeDimensionType) {
|
|||||||
/** Just a number. It will always resolve to exactly this amount. This is the default type. */
|
/** Just a number. It will always resolve to exactly this amount. This is the default type. */
|
||||||
ASRelativeDimensionTypePoints,
|
ASRelativeDimensionTypePoints,
|
||||||
/** Multiplied to a provided parent amount to resolve a final amount. */
|
/** Multiplied to a provided parent amount to resolve a final amount. */
|
||||||
ASRelativeDimensionTypePercent,
|
ASRelativeDimensionTypeFraction,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -44,7 +44,7 @@ extern ASRelativeDimension ASRelativeDimensionMake(ASRelativeDimensionType type,
|
|||||||
|
|
||||||
extern ASRelativeDimension ASRelativeDimensionMakeWithPoints(CGFloat points);
|
extern ASRelativeDimension ASRelativeDimensionMakeWithPoints(CGFloat points);
|
||||||
|
|
||||||
extern ASRelativeDimension ASRelativeDimensionMakeWithPercent(CGFloat percent);
|
extern ASRelativeDimension ASRelativeDimensionMakeWithFraction(CGFloat fraction);
|
||||||
|
|
||||||
extern ASRelativeDimension ASRelativeDimensionCopy(ASRelativeDimension aDimension);
|
extern ASRelativeDimension ASRelativeDimensionCopy(ASRelativeDimension aDimension);
|
||||||
|
|
||||||
|
|||||||
@ -19,9 +19,9 @@ ASRelativeDimension ASRelativeDimensionMake(ASRelativeDimensionType type, CGFloa
|
|||||||
{
|
{
|
||||||
if (type == ASRelativeDimensionTypePoints) {
|
if (type == ASRelativeDimensionTypePoints) {
|
||||||
ASDisplayNodeCAssertPositiveReal(@"Points", value);
|
ASDisplayNodeCAssertPositiveReal(@"Points", value);
|
||||||
} else if (type == ASRelativeDimensionTypePercent) {
|
} else if (type == ASRelativeDimensionTypeFraction) {
|
||||||
// TODO: Enable this assertion for 2.0. Check that there is no use case for using a larger value, e.g. to layout for a clipsToBounds = NO element.
|
// TODO: Enable this assertion for 2.0. Check that there is no use case for using a larger value, e.g. to layout for a clipsToBounds = NO element.
|
||||||
// ASDisplayNodeCAssert( 0 <= value && value <= 1.0, @"ASRelativeDimension percent value (%f) must be between 0 and 1.", value);
|
// ASDisplayNodeCAssert( 0 <= value && value <= 1.0, @"ASRelativeDimension fraction value (%f) must be between 0 and 1.", value);
|
||||||
}
|
}
|
||||||
ASRelativeDimension dimension; dimension.type = type; dimension.value = value; return dimension;
|
ASRelativeDimension dimension; dimension.type = type; dimension.value = value; return dimension;
|
||||||
}
|
}
|
||||||
@ -32,10 +32,10 @@ ASRelativeDimension ASRelativeDimensionMakeWithPoints(CGFloat points)
|
|||||||
return ASRelativeDimensionMake(ASRelativeDimensionTypePoints, points);
|
return ASRelativeDimensionMake(ASRelativeDimensionTypePoints, points);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASRelativeDimension ASRelativeDimensionMakeWithPercent(CGFloat percent)
|
ASRelativeDimension ASRelativeDimensionMakeWithFraction(CGFloat fraction)
|
||||||
{
|
{
|
||||||
// ASDisplayNodeCAssert( 0 <= percent && percent <= 1.0, @"ASRelativeDimension percent value (%f) must be between 0 and 1.", percent);
|
// ASDisplayNodeCAssert( 0 <= fraction && fraction <= 1.0, @"ASRelativeDimension fraction value (%f) must be between 0 and 1.", fraction);
|
||||||
return ASRelativeDimensionMake(ASRelativeDimensionTypePercent, percent);
|
return ASRelativeDimensionMake(ASRelativeDimensionTypeFraction, fraction);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASRelativeDimension ASRelativeDimensionCopy(ASRelativeDimension aDimension)
|
ASRelativeDimension ASRelativeDimensionCopy(ASRelativeDimension aDimension)
|
||||||
@ -53,7 +53,7 @@ NSString *NSStringFromASRelativeDimension(ASRelativeDimension dimension)
|
|||||||
switch (dimension.type) {
|
switch (dimension.type) {
|
||||||
case ASRelativeDimensionTypePoints:
|
case ASRelativeDimensionTypePoints:
|
||||||
return [NSString stringWithFormat:@"%.0fpt", dimension.value];
|
return [NSString stringWithFormat:@"%.0fpt", dimension.value];
|
||||||
case ASRelativeDimensionTypePercent:
|
case ASRelativeDimensionTypeFraction:
|
||||||
return [NSString stringWithFormat:@"%.0f%%", dimension.value * 100.0];
|
return [NSString stringWithFormat:@"%.0f%%", dimension.value * 100.0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ CGFloat ASRelativeDimensionResolve(ASRelativeDimension dimension, CGFloat parent
|
|||||||
switch (dimension.type) {
|
switch (dimension.type) {
|
||||||
case ASRelativeDimensionTypePoints:
|
case ASRelativeDimensionTypePoints:
|
||||||
return dimension.value;
|
return dimension.value;
|
||||||
case ASRelativeDimensionTypePercent:
|
case ASRelativeDimensionTypeFraction:
|
||||||
return dimension.value * parent;
|
return dimension.value * parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
/**
|
/**
|
||||||
A layout spec that wraps another layoutable child, applying insets around it.
|
A layout spec that wraps another layoutable child, applying insets around it.
|
||||||
|
|
||||||
If the child has a size specified as a percentage, the percentage is resolved against this spec's parent
|
If the child has a size specified as a fraction, the fraction is resolved against this spec's parent
|
||||||
size **after** applying insets.
|
size **after** applying insets.
|
||||||
|
|
||||||
@example ASOuterLayoutSpec contains an ASInsetLayoutSpec with an ASInnerLayoutSpec. Suppose that:
|
@example ASOuterLayoutSpec contains an ASInsetLayoutSpec with an ASInnerLayoutSpec. Suppose that:
|
||||||
|
|||||||
@ -40,11 +40,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
* only require a single child.
|
* only require a single child.
|
||||||
*
|
*
|
||||||
* For layout specs that require a known number of children (ASBackgroundLayoutSpec, for example)
|
* For layout specs that require a known number of children (ASBackgroundLayoutSpec, for example)
|
||||||
* a subclass should use this method to set the "primary" child. This is actually the same as calling
|
* a subclass should use this method to set the "primary" child. It can then use setChild:forIdentifier:
|
||||||
* setChild:forIdentifier:0. All other children should be set by defining convenience methods
|
* to set any other required children. Ideally a subclass would hide this from the user, and use the
|
||||||
* that call setChild:forIdentifier behind the scenes.
|
* setChild:forIdentifier: internally. For example, ASBackgroundLayoutSpec exposes a backgroundChild
|
||||||
|
* property that behind the scenes is calling setChild:forIdentifier:.
|
||||||
*/
|
*/
|
||||||
- (void)setChild:(id<ASLayoutable>)child;
|
@property (nullable, strong, nonatomic) id<ASLayoutable> child;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a child with the given identifier to this layout spec.
|
* Adds a child with the given identifier to this layout spec.
|
||||||
@ -76,21 +77,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
* For good measure, in these layout specs it probably makes sense to define
|
* For good measure, in these layout specs it probably makes sense to define
|
||||||
* setChild: and setChild:forIdentifier: methods to do something appropriate or to assert.
|
* setChild: and setChild:forIdentifier: methods to do something appropriate or to assert.
|
||||||
*/
|
*/
|
||||||
- (void)setChildren:(NSArray<id<ASLayoutable>> *)children;
|
@property (nullable, strong, nonatomic) NSArray<id<ASLayoutable>> *children;
|
||||||
|
|
||||||
/**
|
|
||||||
* Get child methods
|
|
||||||
*
|
|
||||||
* There is a corresponding "getChild" method for the above "setChild" methods. If a subclass
|
|
||||||
* has extra layoutable children, it is recommended to make a corresponding get method for that
|
|
||||||
* child. For example, the ASBackgroundLayoutSpec responds to backgroundChild.
|
|
||||||
*
|
|
||||||
* If a get method is called on a spec that doesn't make sense, then the standard is to assert.
|
|
||||||
* For example, calling children on an ASInsetLayoutSpec will assert.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Returns the child added to this layout spec using the default identifier. */
|
|
||||||
- (nullable id<ASLayoutable>)child;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the child added to this layout spec using the given index.
|
* Returns the child added to this layout spec using the given index.
|
||||||
@ -99,11 +86,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (nullable id<ASLayoutable>)childForIndex:(NSUInteger)index;
|
- (nullable id<ASLayoutable>)childForIndex:(NSUInteger)index;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all children added to this layout spec.
|
|
||||||
*/
|
|
||||||
- (nullable NSArray<id<ASLayoutable>> *)children;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface ASLayoutSpec (Debugging) <ASLayoutableAsciiArtProtocol>
|
@interface ASLayoutSpec (Debugging) <ASLayoutableAsciiArtProtocol>
|
||||||
|
|||||||
@ -117,7 +117,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
#pragma mark - ASStaticLayoutable
|
#pragma mark - ASStaticLayoutable
|
||||||
/**
|
/**
|
||||||
If specified, the child's size is restricted according to this size. Percentages are resolved relative to the static layout spec.
|
If specified, the child's size is restricted according to this size. Fractions are resolved relative to the static layout spec.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) ASRelativeSizeRange sizeRange;
|
@property (nonatomic, assign) ASRelativeSizeRange sizeRange;
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#import "ASRatioLayoutSpec.h"
|
#import "ASRatioLayoutSpec.h"
|
||||||
|
|
||||||
#import <algorithm>
|
#import <algorithm>
|
||||||
|
#import <tgmath.h>
|
||||||
#import <vector>
|
#import <vector>
|
||||||
|
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
@ -64,7 +65,7 @@
|
|||||||
|
|
||||||
// Choose the size closest to the desired ratio.
|
// Choose the size closest to the desired ratio.
|
||||||
const auto &bestSize = std::max_element(sizeOptions.begin(), sizeOptions.end(), [&](const CGSize &a, const CGSize &b){
|
const auto &bestSize = std::max_element(sizeOptions.begin(), sizeOptions.end(), [&](const CGSize &a, const CGSize &b){
|
||||||
return fabs((a.height / a.width) - _ratio) > fabs((b.height / b.width) - _ratio);
|
return std::fabs((a.height / a.width) - _ratio) > std::fabs((b.height / b.width) - _ratio);
|
||||||
});
|
});
|
||||||
|
|
||||||
// If there is no max size in *either* dimension, we can't apply the ratio, so just pass our size range through.
|
// If there is no max size in *either* dimension, we can't apply the ratio, so just pass our size range through.
|
||||||
|
|||||||
@ -39,11 +39,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
extern ASRelativeSize ASRelativeSizeMake(ASRelativeDimension width, ASRelativeDimension height);
|
extern ASRelativeSize ASRelativeSizeMake(ASRelativeDimension width, ASRelativeDimension height);
|
||||||
|
|
||||||
/** Convenience constructor to provide size in Points. */
|
/** Convenience constructor to provide size in points. */
|
||||||
extern ASRelativeSize ASRelativeSizeMakeWithCGSize(CGSize size);
|
extern ASRelativeSize ASRelativeSizeMakeWithCGSize(CGSize size);
|
||||||
|
|
||||||
/** Convenience constructor to provide size in Percentage. */
|
/** Convenience constructor to provide size as a fraction. */
|
||||||
extern ASRelativeSize ASRelativeSizeMakeWithPercent(CGFloat percent);
|
extern ASRelativeSize ASRelativeSizeMakeWithFraction(CGFloat fraction);
|
||||||
|
|
||||||
/** Resolve this relative size relative to a parent size. */
|
/** Resolve this relative size relative to a parent size. */
|
||||||
extern CGSize ASRelativeSizeResolveSize(ASRelativeSize relativeSize, CGSize parentSize);
|
extern CGSize ASRelativeSizeResolveSize(ASRelativeSize relativeSize, CGSize parentSize);
|
||||||
@ -61,7 +61,7 @@ extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelati
|
|||||||
|
|
||||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactCGSize(CGSize exact);
|
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactCGSize(CGSize exact);
|
||||||
|
|
||||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactPercent(CGFloat percent);
|
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactFraction(CGFloat fraction);
|
||||||
|
|
||||||
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimension exactWidth,
|
extern ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimension exactWidth,
|
||||||
ASRelativeDimension exactHeight);
|
ASRelativeDimension exactHeight);
|
||||||
|
|||||||
@ -25,10 +25,10 @@ ASRelativeSize ASRelativeSizeMakeWithCGSize(CGSize size)
|
|||||||
ASRelativeDimensionMakeWithPoints(size.height));
|
ASRelativeDimensionMakeWithPoints(size.height));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASRelativeSize ASRelativeSizeMakeWithPercent(CGFloat percent)
|
ASRelativeSize ASRelativeSizeMakeWithFraction(CGFloat fraction)
|
||||||
{
|
{
|
||||||
return ASRelativeSizeMake(ASRelativeDimensionMakeWithPercent(percent),
|
return ASRelativeSizeMake(ASRelativeDimensionMakeWithFraction(fraction),
|
||||||
ASRelativeDimensionMakeWithPercent(percent));
|
ASRelativeDimensionMakeWithFraction(fraction));
|
||||||
}
|
}
|
||||||
|
|
||||||
CGSize ASRelativeSizeResolveSize(ASRelativeSize relativeSize, CGSize parentSize)
|
CGSize ASRelativeSizeResolveSize(ASRelativeSize relativeSize, CGSize parentSize)
|
||||||
@ -67,9 +67,9 @@ ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactCGSize(CGSize exact)
|
|||||||
return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMakeWithCGSize(exact));
|
return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMakeWithCGSize(exact));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactPercent(CGFloat percent)
|
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactFraction(CGFloat fraction)
|
||||||
{
|
{
|
||||||
return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMakeWithPercent(percent));
|
return ASRelativeSizeRangeMakeWithExactRelativeSize(ASRelativeSizeMakeWithFraction(fraction));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimension exactWidth,
|
ASRelativeSizeRange ASRelativeSizeRangeMakeWithExactRelativeDimensions(ASRelativeDimension exactWidth,
|
||||||
|
|||||||
@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@protocol ASStaticLayoutable
|
@protocol ASStaticLayoutable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If specified, the child's size is restricted according to this size. Percentages are resolved relative to the static layout spec.
|
If specified, the child's size is restricted according to this size. Fractions are resolved relative to the static layout spec.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) ASRelativeSizeRange sizeRange;
|
@property (nonatomic, assign) ASRelativeSizeRange sizeRange;
|
||||||
|
|
||||||
|
|||||||
@ -95,7 +95,7 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCellNode *> *nodes, NS
|
|||||||
* The data source is locked at this point and accessing it is safe. Use this method to set up any nodes or
|
* The data source is locked at this point and accessing it is safe. Use this method to set up any nodes or
|
||||||
* data stores before entering into editing the backing store on a background thread.
|
* data stores before entering into editing the backing store on a background thread.
|
||||||
*/
|
*/
|
||||||
- (void)prepareForReloadData;
|
- (void)prepareForReloadDataWithSectionCount:(NSInteger)newSectionCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the subclass that the data controller is about to reload its data entirely
|
* Notifies the subclass that the data controller is about to reload its data entirely
|
||||||
@ -104,7 +104,7 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCellNode *> *nodes, NS
|
|||||||
* concrete implementation. This is a great place to perform new node creation like supplementary views
|
* concrete implementation. This is a great place to perform new node creation like supplementary views
|
||||||
* or header/footer nodes.
|
* or header/footer nodes.
|
||||||
*/
|
*/
|
||||||
- (void)willReloadData;
|
- (void)willReloadDataWithSectionCount:(NSInteger)newSectionCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies the subclass to perform setup before sections are inserted in the data controller
|
* Notifies the subclass to perform setup before sections are inserted in the data controller
|
||||||
|
|||||||
@ -344,7 +344,7 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo
|
|||||||
// The node is loaded but we're not on main.
|
// The node is loaded but we're not on main.
|
||||||
// We will call [self __setNeedsLayout] when we apply
|
// We will call [self __setNeedsLayout] when we apply
|
||||||
// the pending state. We need to call it on main if the node is loaded
|
// the pending state. We need to call it on main if the node is loaded
|
||||||
// to support implicit hierarchy management.
|
// to support automatic subnode management.
|
||||||
[ASDisplayNodeGetPendingState(self) setNeedsLayout];
|
[ASDisplayNodeGetPendingState(self) setNeedsLayout];
|
||||||
} else {
|
} else {
|
||||||
// The node is not loaded and we're not on main.
|
// The node is not loaded and we're not on main.
|
||||||
|
|||||||
@ -21,8 +21,6 @@
|
|||||||
#import "ASLayoutTransition.h"
|
#import "ASLayoutTransition.h"
|
||||||
#import "ASEnvironment.h"
|
#import "ASEnvironment.h"
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
@protocol _ASDisplayLayerDelegate;
|
@protocol _ASDisplayLayerDelegate;
|
||||||
@class _ASDisplayLayer;
|
@class _ASDisplayLayer;
|
||||||
@class _ASPendingState;
|
@class _ASPendingState;
|
||||||
@ -85,10 +83,10 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
|
|||||||
|
|
||||||
// Prevent calling setNeedsDisplay on a layer that backs a UIImageView. Usually calling setNeedsDisplay on a CALayer
|
// Prevent calling setNeedsDisplay on a layer that backs a UIImageView. Usually calling setNeedsDisplay on a CALayer
|
||||||
// triggers a recreation of the contents of layer unfortunately calling it on a CALayer that backs a UIImageView
|
// triggers a recreation of the contents of layer unfortunately calling it on a CALayer that backs a UIImageView
|
||||||
// it goes trough the normal flow to assign the contents to a layer via the CALayerDelegate methods. Unfortunately
|
// it goes through the normal flow to assign the contents to a layer via the CALayerDelegate methods. Unfortunately
|
||||||
// UIImageView does not do recreate the layer contents the usual way, it actually does not implement some of the
|
// UIImageView does not do recreate the layer contents the usual way, it actually does not implement some of the
|
||||||
// methods at all instead it throws away the contents of the layer and nothing will show up.
|
// methods at all instead it throws away the contents of the layer and nothing will show up.
|
||||||
unsigned canCallNeedsDisplayOfLayer:1;
|
unsigned canCallSetNeedsDisplayOfLayer:1;
|
||||||
|
|
||||||
// whether custom drawing is enabled
|
// whether custom drawing is enabled
|
||||||
unsigned implementsInstanceDrawRect:1;
|
unsigned implementsInstanceDrawRect:1;
|
||||||
@ -124,7 +122,10 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
|
|||||||
|
|
||||||
// Main thread only
|
// Main thread only
|
||||||
_ASTransitionContext *_pendingLayoutTransitionContext;
|
_ASTransitionContext *_pendingLayoutTransitionContext;
|
||||||
BOOL _usesImplicitHierarchyManagement;
|
BOOL _automaticallyManagesSubnodes;
|
||||||
|
NSTimeInterval _defaultLayoutTransitionDuration;
|
||||||
|
NSTimeInterval _defaultLayoutTransitionDelay;
|
||||||
|
UIViewAnimationOptions _defaultLayoutTransitionOptions;
|
||||||
|
|
||||||
int32_t _pendingTransitionID;
|
int32_t _pendingTransitionID;
|
||||||
ASLayoutTransition *_pendingLayoutTransition;
|
ASLayoutTransition *_pendingLayoutTransition;
|
||||||
|
|||||||
@ -20,7 +20,7 @@ ASDISPLAYNODE_EXTERN_C_BEGIN
|
|||||||
@param sourceImageSize The size of the encoded image.
|
@param sourceImageSize The size of the encoded image.
|
||||||
@param boundsSize The bounds in which the image will be displayed.
|
@param boundsSize The bounds in which the image will be displayed.
|
||||||
@param contentMode The mode that defines how image will be scaled and cropped to fit. Supported values are UIViewContentModeScaleToAspectFill and UIViewContentModeScaleToAspectFit.
|
@param contentMode The mode that defines how image will be scaled and cropped to fit. Supported values are UIViewContentModeScaleToAspectFill and UIViewContentModeScaleToAspectFit.
|
||||||
@param cropRect A rectangle that is to be featured by the cropped image. The rectangle is specified as a "unit rectangle," using percentages of the source image's width and height, e.g. CGRectMake(0.5, 0, 0.5, 1.0) will feature the full right half a photo. If the cropRect is empty, the contentMode will be used to determine the drawRect's size, and only the cropRect's origin will be used for positioning.
|
@param cropRect A rectangle that is to be featured by the cropped image. The rectangle is specified as a "unit rectangle," using fractions of the source image's width and height, e.g. CGRectMake(0.5, 0, 0.5, 1.0) will feature the full right half a photo. If the cropRect is empty, the contentMode will be used to determine the drawRect's size, and only the cropRect's origin will be used for positioning.
|
||||||
@param forceUpscaling A boolean that indicates you would *not* like the backing size to be downscaled if the image is smaller than the destination size. Setting this to YES will result in higher memory usage when images are smaller than their destination.
|
@param forceUpscaling A boolean that indicates you would *not* like the backing size to be downscaled if the image is smaller than the destination size. Setting this to YES will result in higher memory usage when images are smaller than their destination.
|
||||||
@discussion If the image is smaller than the size and UIViewContentModeScaleToAspectFill is specified, we suggest the input size so it will be efficiently upscaled on the GPU by the displaying layer at composite time.
|
@discussion If the image is smaller than the size and UIViewContentModeScaleToAspectFill is specified, we suggest the input size so it will be efficiently upscaled on the GPU by the displaying layer at composite time.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "ASImageNode+CGExtras.h"
|
#import "ASImageNode+CGExtras.h"
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
// TODO rewrite these to be closer to the intended use -- take UIViewContentMode as param, CGRect destinationBounds, CGSize sourceSize.
|
// TODO rewrite these to be closer to the intended use -- take UIViewContentMode as param, CGRect destinationBounds, CGSize sourceSize.
|
||||||
static CGSize _ASSizeFillWithAspectRatio(CGFloat aspectRatio, CGSize constraints);
|
static CGSize _ASSizeFillWithAspectRatio(CGFloat aspectRatio, CGSize constraints);
|
||||||
@ -20,7 +21,7 @@ static CGSize _ASSizeFillWithAspectRatio(CGFloat sizeToScaleAspectRatio, CGSize
|
|||||||
if (sizeToScaleAspectRatio > destinationAspectRatio) {
|
if (sizeToScaleAspectRatio > destinationAspectRatio) {
|
||||||
return CGSizeMake(destinationSize.height * sizeToScaleAspectRatio, destinationSize.height);
|
return CGSizeMake(destinationSize.height * sizeToScaleAspectRatio, destinationSize.height);
|
||||||
} else {
|
} else {
|
||||||
return CGSizeMake(destinationSize.width, roundf(destinationSize.width / sizeToScaleAspectRatio));
|
return CGSizeMake(destinationSize.width, round(destinationSize.width / sizeToScaleAspectRatio));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ void ASCroppedImageBackingSizeAndDrawRectInBounds(CGSize sourceImageSize,
|
|||||||
|
|
||||||
// Often, an image is too low resolution to completely fill the width and height provided.
|
// Often, an image is too low resolution to completely fill the width and height provided.
|
||||||
// Per the API contract as commented in the header, we will adjust input parameters (destinationWidth, destinationHeight) to ensure that the image is not upscaled on the CPU.
|
// Per the API contract as commented in the header, we will adjust input parameters (destinationWidth, destinationHeight) to ensure that the image is not upscaled on the CPU.
|
||||||
CGFloat boundsAspectRatio = (float)destinationWidth / (float)destinationHeight;
|
CGFloat boundsAspectRatio = (CGFloat)destinationWidth / (CGFloat)destinationHeight;
|
||||||
|
|
||||||
CGSize scaledSizeForImage = sourceImageSize;
|
CGSize scaledSizeForImage = sourceImageSize;
|
||||||
BOOL cropToRectDimensions = !CGRectIsEmpty(cropRect);
|
BOOL cropToRectDimensions = !CGRectIsEmpty(cropRect);
|
||||||
@ -66,8 +67,8 @@ void ASCroppedImageBackingSizeAndDrawRectInBounds(CGSize sourceImageSize,
|
|||||||
// If fitting the desired aspect ratio to the image size actually results in a larger buffer, use the input values.
|
// If fitting the desired aspect ratio to the image size actually results in a larger buffer, use the input values.
|
||||||
// However, if there is a pixel savings (e.g. we would have to upscale the image), overwrite the function arguments.
|
// However, if there is a pixel savings (e.g. we would have to upscale the image), overwrite the function arguments.
|
||||||
if (forceUpscaling == NO && (scaledSizeForImage.width * scaledSizeForImage.height) < (destinationWidth * destinationHeight)) {
|
if (forceUpscaling == NO && (scaledSizeForImage.width * scaledSizeForImage.height) < (destinationWidth * destinationHeight)) {
|
||||||
destinationWidth = (size_t)roundf(scaledSizeForImage.width);
|
destinationWidth = (size_t)round(scaledSizeForImage.width);
|
||||||
destinationHeight = (size_t)roundf(scaledSizeForImage.height);
|
destinationHeight = (size_t)round(scaledSizeForImage.height);
|
||||||
if (destinationWidth == 0 || destinationHeight == 0) {
|
if (destinationWidth == 0 || destinationHeight == 0) {
|
||||||
*outBackingSize = CGSizeZero;
|
*outBackingSize = CGSizeZero;
|
||||||
*outDrawRect = CGRectZero;
|
*outDrawRect = CGRectZero;
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#import "ASLayout.h"
|
#import "ASLayout.h"
|
||||||
|
|
||||||
#import <queue>
|
#import <queue>
|
||||||
|
#import <memory>
|
||||||
|
|
||||||
#import "NSArray+Diffing.h"
|
#import "NSArray+Diffing.h"
|
||||||
#import "ASEqualityHelpers.h"
|
#import "ASEqualityHelpers.h"
|
||||||
@ -47,7 +48,8 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@implementation ASLayoutTransition {
|
@implementation ASLayoutTransition {
|
||||||
ASDN::RecursiveMutex __instanceLock__;
|
std::shared_ptr<ASDN::RecursiveMutex> __instanceLock__;
|
||||||
|
|
||||||
BOOL _calculatedSubnodeOperations;
|
BOOL _calculatedSubnodeOperations;
|
||||||
NSArray<ASDisplayNode *> *_insertedSubnodes;
|
NSArray<ASDisplayNode *> *_insertedSubnodes;
|
||||||
NSArray<ASDisplayNode *> *_removedSubnodes;
|
NSArray<ASDisplayNode *> *_removedSubnodes;
|
||||||
@ -61,6 +63,8 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
|
__instanceLock__ = std::make_shared<ASDN::RecursiveMutex>();
|
||||||
|
|
||||||
_node = node;
|
_node = node;
|
||||||
_pendingLayout = pendingLayout;
|
_pendingLayout = pendingLayout;
|
||||||
_previousLayout = previousLayout;
|
_previousLayout = previousLayout;
|
||||||
@ -70,7 +74,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (BOOL)isSynchronous
|
- (BOOL)isSynchronous
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
return !ASLayoutCanTransitionAsynchronous(_pendingLayout);
|
return !ASLayoutCanTransitionAsynchronous(_pendingLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +86,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (void)applySubnodeInsertions
|
- (void)applySubnodeInsertions
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
[self calculateSubnodeOperationsIfNeeded];
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
|
|
||||||
NSUInteger i = 0;
|
NSUInteger i = 0;
|
||||||
@ -95,7 +99,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (void)applySubnodeRemovals
|
- (void)applySubnodeRemovals
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
[self calculateSubnodeOperationsIfNeeded];
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
for (ASDisplayNode *subnode in _removedSubnodes) {
|
for (ASDisplayNode *subnode in _removedSubnodes) {
|
||||||
[subnode removeFromSupernode];
|
[subnode removeFromSupernode];
|
||||||
@ -104,7 +108,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (void)calculateSubnodeOperationsIfNeeded
|
- (void)calculateSubnodeOperationsIfNeeded
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
if (_calculatedSubnodeOperations) {
|
if (_calculatedSubnodeOperations) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -134,27 +138,27 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
return _node.subnodes;
|
return _node.subnodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
- (NSArray<ASDisplayNode *> *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
[self calculateSubnodeOperationsIfNeeded];
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
return _insertedSubnodes;
|
return _insertedSubnodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray<ASDisplayNode *> *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
- (NSArray<ASDisplayNode *> *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
[self calculateSubnodeOperationsIfNeeded];
|
[self calculateSubnodeOperationsIfNeeded];
|
||||||
return _removedSubnodes;
|
return _removedSubnodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key
|
- (ASLayout *)transitionContext:(_ASTransitionContext *)context layoutForKey:(NSString *)key
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
||||||
return _previousLayout;
|
return _previousLayout;
|
||||||
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
||||||
@ -166,7 +170,7 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
|||||||
|
|
||||||
- (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key
|
- (ASSizeRange)transitionContext:(_ASTransitionContext *)context constrainedSizeForKey:(NSString *)key
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
if ([key isEqualToString:ASTransitionContextFromLayoutKey]) {
|
||||||
return _previousLayout.constrainedSizeRange;
|
return _previousLayout.constrainedSizeRange;
|
||||||
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
} else if ([key isEqualToString:ASTransitionContextToLayoutKey]) {
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#import "ASStackPositionedLayout.h"
|
#import "ASStackPositionedLayout.h"
|
||||||
|
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
#import "ASLayoutSpecUtilities.h"
|
#import "ASLayoutSpecUtilities.h"
|
||||||
|
|
||||||
@ -105,16 +107,16 @@ ASStackPositionedLayout ASStackPositionedLayout::compute(const ASStackUnposition
|
|||||||
case ASStackLayoutJustifyContentStart:
|
case ASStackLayoutJustifyContentStart:
|
||||||
return stackedLayout(style, 0, unpositionedLayout, constrainedSize);
|
return stackedLayout(style, 0, unpositionedLayout, constrainedSize);
|
||||||
case ASStackLayoutJustifyContentCenter:
|
case ASStackLayoutJustifyContentCenter:
|
||||||
return stackedLayout(style, floorf(violation / 2), unpositionedLayout, constrainedSize);
|
return stackedLayout(style, std::floor(violation / 2), unpositionedLayout, constrainedSize);
|
||||||
case ASStackLayoutJustifyContentEnd:
|
case ASStackLayoutJustifyContentEnd:
|
||||||
return stackedLayout(style, violation, unpositionedLayout, constrainedSize);
|
return stackedLayout(style, violation, unpositionedLayout, constrainedSize);
|
||||||
case ASStackLayoutJustifyContentSpaceBetween: {
|
case ASStackLayoutJustifyContentSpaceBetween: {
|
||||||
const auto numOfSpacings = numOfItems - 1;
|
const auto numOfSpacings = numOfItems - 1;
|
||||||
return stackedLayout(style, 0, floorf(violation / numOfSpacings), fmodf(violation, numOfSpacings), unpositionedLayout, constrainedSize);
|
return stackedLayout(style, 0, std::floor(violation / numOfSpacings), std::fmod(violation, numOfSpacings), unpositionedLayout, constrainedSize);
|
||||||
}
|
}
|
||||||
case ASStackLayoutJustifyContentSpaceAround: {
|
case ASStackLayoutJustifyContentSpaceAround: {
|
||||||
// Spacing between items are twice the spacing on the edges
|
// Spacing between items are twice the spacing on the edges
|
||||||
CGFloat spacingUnit = floorf(violation / (numOfItems * 2));
|
CGFloat spacingUnit = std::floor(violation / (numOfItems * 2));
|
||||||
return stackedLayout(style, spacingUnit, spacingUnit * 2, 0, unpositionedLayout, constrainedSize);
|
return stackedLayout(style, spacingUnit, spacingUnit * 2, 0, unpositionedLayout, constrainedSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#import "ASStackUnpositionedLayout.h"
|
#import "ASStackUnpositionedLayout.h"
|
||||||
|
|
||||||
|
#import <tgmath.h>
|
||||||
#import <numeric>
|
#import <numeric>
|
||||||
|
|
||||||
#import "ASLayoutSpecUtilities.h"
|
#import "ASLayoutSpecUtilities.h"
|
||||||
@ -87,7 +88,7 @@ static void stretchChildrenAlongCrossDimension(std::vector<ASStackUnpositionedIt
|
|||||||
// restretch all stretchable children along the cross axis using the new min. set their max size to childCrossMax,
|
// restretch all stretchable children along the cross axis using the new min. set their max size to childCrossMax,
|
||||||
// not crossMax, so that if any of them would choose a larger size just because the min size increased (weird!)
|
// not crossMax, so that if any of them would choose a larger size just because the min size increased (weird!)
|
||||||
// they are forced to choose the same width as all the other children.
|
// they are forced to choose the same width as all the other children.
|
||||||
if (alignItems == ASStackLayoutAlignItemsStretch && fabs(cross - childCrossMax) > 0.01) {
|
if (alignItems == ASStackLayoutAlignItemsStretch && std::fabs(cross - childCrossMax) > 0.01) {
|
||||||
l.layout = crossChildLayout(child, style, stack, stack, childCrossMax, childCrossMax);
|
l.layout = crossChildLayout(child, style, stack, stack, childCrossMax, childCrossMax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +183,7 @@ static const CGFloat kViolationEpsilon = 0.01;
|
|||||||
*/
|
*/
|
||||||
static std::function<BOOL(const ASStackUnpositionedItem &)> isFlexibleInViolationDirection(const CGFloat violation)
|
static std::function<BOOL(const ASStackUnpositionedItem &)> isFlexibleInViolationDirection(const CGFloat violation)
|
||||||
{
|
{
|
||||||
if (fabs(violation) < kViolationEpsilon) {
|
if (std::fabs(violation) < kViolationEpsilon) {
|
||||||
return [](const ASStackUnpositionedItem &l) { return NO; };
|
return [](const ASStackUnpositionedItem &l) { return NO; };
|
||||||
} else if (violation > 0) {
|
} else if (violation > 0) {
|
||||||
return [](const ASStackUnpositionedItem &l) { return l.child.flexGrow; };
|
return [](const ASStackUnpositionedItem &l) { return l.child.flexGrow; };
|
||||||
@ -263,7 +264,7 @@ static void flexChildrenAlongStackDimension(std::vector<ASStackUnpositionedItem>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Each flexible child along the direction of the violation is expanded or contracted equally
|
// Each flexible child along the direction of the violation is expanded or contracted equally
|
||||||
const CGFloat violationPerFlexChild = floorf(violation / flexibleChildren);
|
const CGFloat violationPerFlexChild = std::floor(violation / flexibleChildren);
|
||||||
// If the floor operation above left a remainder we may have a remainder after deducting the adjustments from all the
|
// If the floor operation above left a remainder we may have a remainder after deducting the adjustments from all the
|
||||||
// contributions of the flexible children.
|
// contributions of the flexible children.
|
||||||
const CGFloat violationRemainder = violation - (violationPerFlexChild * flexibleChildren);
|
const CGFloat violationRemainder = violation - (violationPerFlexChild * flexibleChildren);
|
||||||
|
|||||||
@ -32,8 +32,8 @@ extern void ASDisplayNodeSetupLayerContentsWithResizableImage(CALayer *layer, UI
|
|||||||
UIEdgeInsets insets = [image capInsets];
|
UIEdgeInsets insets = [image capInsets];
|
||||||
|
|
||||||
// These are lifted from what UIImageView does by experimentation. Without these exact values, the stretching is slightly off.
|
// These are lifted from what UIImageView does by experimentation. Without these exact values, the stretching is slightly off.
|
||||||
const float halfPixelFudge = 0.49f;
|
const CGFloat halfPixelFudge = 0.49f;
|
||||||
const float otherPixelFudge = 0.02f;
|
const CGFloat otherPixelFudge = 0.02f;
|
||||||
// Convert to unit coordinates for the contentsCenter property.
|
// Convert to unit coordinates for the contentsCenter property.
|
||||||
CGRect contentsCenter = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
|
CGRect contentsCenter = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
|
||||||
if (insets.left > 0 || insets.right > 0) {
|
if (insets.left > 0 || insets.right > 0) {
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
#import "NSIndexSet+ASHelpers.h"
|
#import "NSIndexSet+ASHelpers.h"
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASDisplayNode+Beta.h"
|
#import "ASDisplayNode+Beta.h"
|
||||||
|
|
||||||
#import <unordered_map>
|
#import <unordered_map>
|
||||||
|
|
||||||
#define ASFailUpdateValidation(...)\
|
#define ASFailUpdateValidation(...)\
|
||||||
|
|||||||
@ -10,13 +10,14 @@
|
|||||||
|
|
||||||
#import "ASTextKitContext.h"
|
#import "ASTextKitContext.h"
|
||||||
#import "ASLayoutManager.h"
|
#import "ASLayoutManager.h"
|
||||||
|
#import "ASThread.h"
|
||||||
|
|
||||||
#import <mutex>
|
#include <memory>
|
||||||
|
|
||||||
@implementation ASTextKitContext
|
@implementation ASTextKitContext
|
||||||
{
|
{
|
||||||
// All TextKit operations (even non-mutative ones) must be executed serially.
|
// All TextKit operations (even non-mutative ones) must be executed serially.
|
||||||
std::mutex _textKitMutex;
|
std::shared_ptr<ASDN::Mutex> __instanceLock__;
|
||||||
|
|
||||||
NSLayoutManager *_layoutManager;
|
NSLayoutManager *_layoutManager;
|
||||||
NSTextStorage *_textStorage;
|
NSTextStorage *_textStorage;
|
||||||
@ -35,8 +36,11 @@
|
|||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
// Concurrently initialising TextKit components crashes (rdar://18448377) so we use a global lock.
|
// Concurrently initialising TextKit components crashes (rdar://18448377) so we use a global lock.
|
||||||
static std::mutex __static_mutex;
|
static ASDN::Mutex __staticMutex;
|
||||||
std::lock_guard<std::mutex> l(__static_mutex);
|
ASDN::MutexLocker l(__staticMutex);
|
||||||
|
|
||||||
|
__instanceLock__ = std::make_shared<ASDN::Mutex>();
|
||||||
|
|
||||||
// Create the TextKit component stack with our default configuration.
|
// Create the TextKit component stack with our default configuration.
|
||||||
if (textStorageCreationBlock) {
|
if (textStorageCreationBlock) {
|
||||||
_textStorage = textStorageCreationBlock(attributedString);
|
_textStorage = textStorageCreationBlock(attributedString);
|
||||||
@ -60,13 +64,13 @@
|
|||||||
|
|
||||||
- (CGSize)constrainedSize
|
- (CGSize)constrainedSize
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(_textKitMutex);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
return _textContainer.size;
|
return _textContainer.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setConstrainedSize:(CGSize)constrainedSize
|
- (void)setConstrainedSize:(CGSize)constrainedSize
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(_textKitMutex);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
_textContainer.size = constrainedSize;
|
_textContainer.size = constrainedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +78,7 @@
|
|||||||
NSTextStorage *,
|
NSTextStorage *,
|
||||||
NSTextContainer *))block
|
NSTextContainer *))block
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(_textKitMutex);
|
ASDN::MutexSharedLocker l(__instanceLock__);
|
||||||
if (block) {
|
if (block) {
|
||||||
block(_layoutManager, _textStorage, _textContainer);
|
block(_layoutManager, _textStorage, _textContainer);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,12 +8,15 @@
|
|||||||
// of patent rights can be found in the PATENTS file in the same directory.
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "ASTextKitContext.h"
|
|
||||||
#import "ASTextKitFontSizeAdjuster.h"
|
|
||||||
#import "ASLayoutManager.h"
|
|
||||||
|
|
||||||
|
#import "ASTextKitFontSizeAdjuster.h"
|
||||||
|
|
||||||
|
#import <tgmath.h>
|
||||||
#import <mutex>
|
#import <mutex>
|
||||||
|
|
||||||
|
#import "ASTextKitContext.h"
|
||||||
|
#import "ASLayoutManager.h"
|
||||||
|
|
||||||
//#define LOG(...) NSLog(__VA_ARGS__)
|
//#define LOG(...) NSLog(__VA_ARGS__)
|
||||||
#define LOG(...)
|
#define LOG(...)
|
||||||
|
|
||||||
@ -48,7 +51,7 @@
|
|||||||
[attrString enumerateAttributesInRange:NSMakeRange(0, attrString.length) options:0 usingBlock:^(NSDictionary<NSString *,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
|
[attrString enumerateAttributesInRange:NSMakeRange(0, attrString.length) options:0 usingBlock:^(NSDictionary<NSString *,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
|
||||||
if (attrs[NSFontAttributeName] != nil) {
|
if (attrs[NSFontAttributeName] != nil) {
|
||||||
UIFont *font = attrs[NSFontAttributeName];
|
UIFont *font = attrs[NSFontAttributeName];
|
||||||
font = [font fontWithSize:roundf(font.pointSize * scaleFactor)];
|
font = [font fontWithSize:std::round(font.pointSize * scaleFactor)];
|
||||||
[attrString removeAttribute:NSFontAttributeName range:range];
|
[attrString removeAttribute:NSFontAttributeName range:range];
|
||||||
[attrString addAttribute:NSFontAttributeName value:font range:range];
|
[attrString addAttribute:NSFontAttributeName value:font range:range];
|
||||||
}
|
}
|
||||||
@ -166,7 +169,7 @@
|
|||||||
// adjust here so we start at the proper place in our scale array if we have too many lines
|
// adjust here so we start at the proper place in our scale array if we have too many lines
|
||||||
scaleIndex++;
|
scaleIndex++;
|
||||||
|
|
||||||
if (ceilf(longestWordSize.width * [scaleFactor floatValue]) <= _constrainedSize.width) {
|
if (std::ceil(longestWordSize.width * [scaleFactor floatValue]) <= _constrainedSize.width) {
|
||||||
// we fit! we are done
|
// we fit! we are done
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#import "ASTextKitRenderer+Positioning.h"
|
#import "ASTextKitRenderer+Positioning.h"
|
||||||
|
|
||||||
#import <CoreText/CoreText.h>
|
#import <CoreText/CoreText.h>
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
|
|
||||||
@ -163,7 +164,7 @@ static const CGFloat ASTextKitRendererTextCapHeightPadding = 1.3;
|
|||||||
|
|
||||||
[self enumerateTextIndexesAtPosition:position usingBlock:^(NSUInteger characterIndex, CGRect glyphBoundingRect, BOOL *stop) {
|
[self enumerateTextIndexesAtPosition:position usingBlock:^(NSUInteger characterIndex, CGRect glyphBoundingRect, BOOL *stop) {
|
||||||
CGPoint glyphLocation = CGPointMake(CGRectGetMidX(glyphBoundingRect), CGRectGetMidY(glyphBoundingRect));
|
CGPoint glyphLocation = CGPointMake(CGRectGetMidX(glyphBoundingRect), CGRectGetMidY(glyphBoundingRect));
|
||||||
CGFloat currentDistance = sqrtf(powf(position.x - glyphLocation.x, 2.f) + powf(position.y - glyphLocation.y, 2.f));
|
CGFloat currentDistance = std::sqrt(std::pow(position.x - glyphLocation.x, 2.f) + std::pow(position.y - glyphLocation.y, 2.f));
|
||||||
if (currentDistance < minimumGlyphDistance) {
|
if (currentDistance < minimumGlyphDistance) {
|
||||||
minimumGlyphDistance = currentDistance;
|
minimumGlyphDistance = currentDistance;
|
||||||
minimumGlyphCharacterIndex = characterIndex;
|
minimumGlyphCharacterIndex = characterIndex;
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#import "ASTextKitShadower.h"
|
#import "ASTextKitShadower.h"
|
||||||
|
|
||||||
|
#import <tgmath.h>
|
||||||
|
|
||||||
static inline CGSize _insetSize(CGSize size, UIEdgeInsets insets)
|
static inline CGSize _insetSize(CGSize size, UIEdgeInsets insets)
|
||||||
{
|
{
|
||||||
return UIEdgeInsetsInsetRect({.size = size}, insets).size;
|
return UIEdgeInsetsInsetRect({.size = size}, insets).size;
|
||||||
@ -87,11 +89,11 @@ static inline UIEdgeInsets _invertInsets(UIEdgeInsets insets)
|
|||||||
|
|
||||||
// min values are expected to be negative for most typical shadowOffset and
|
// min values are expected to be negative for most typical shadowOffset and
|
||||||
// blurRadius settings:
|
// blurRadius settings:
|
||||||
shadowPadding.top = fminf(0.0f, _shadowOffset.height - _shadowRadius);
|
shadowPadding.top = std::fmin(0.0f, _shadowOffset.height - _shadowRadius);
|
||||||
shadowPadding.left = fminf(0.0f, _shadowOffset.width - _shadowRadius);
|
shadowPadding.left = std::fmin(0.0f, _shadowOffset.width - _shadowRadius);
|
||||||
|
|
||||||
shadowPadding.bottom = fminf(0.0f, -_shadowOffset.height - _shadowRadius);
|
shadowPadding.bottom = std::fmin(0.0f, -_shadowOffset.height - _shadowRadius);
|
||||||
shadowPadding.right = fminf(0.0f, -_shadowOffset.width - _shadowRadius);
|
shadowPadding.right = std::fmin(0.0f, -_shadowOffset.width - _shadowRadius);
|
||||||
|
|
||||||
_calculatedShadowPadding = shadowPadding;
|
_calculatedShadowPadding = shadowPadding;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "_ASTransitionContext.h"
|
#import "_ASTransitionContext.h"
|
||||||
|
#import "ASDisplayNode.h"
|
||||||
#import "ASLayout.h"
|
#import "ASLayout.h"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,7 @@
|
|||||||
}];
|
}];
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
[self waitForExpectationsWithTimeout:3 handler:nil];
|
[self waitForExpectationsWithTimeout:30 handler:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -294,34 +294,6 @@
|
|||||||
collectionView.asyncDelegate = nil;
|
collectionView.asyncDelegate = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - #collectionView:numberOfSectionsForSupplementaryNodeOfKind:
|
|
||||||
|
|
||||||
- (void)testThatItRespondsWithTheDefaultNumberOfSections
|
|
||||||
{
|
|
||||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
|
||||||
NSUInteger sections = [inspector collectionView:collectionView numberOfSectionsForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
|
||||||
XCTAssert(sections == 1, @"should return 1 by default");
|
|
||||||
|
|
||||||
collectionView.asyncDataSource = nil;
|
|
||||||
collectionView.asyncDelegate = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)testThatItProvidesTheNumberOfSectionsInTheDataSource
|
|
||||||
{
|
|
||||||
InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
|
|
||||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
|
||||||
collectionView.asyncDataSource = dataSource;
|
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
|
||||||
NSUInteger sections = [inspector collectionView:collectionView numberOfSectionsForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
|
||||||
XCTAssert(sections == 2, @"should return 2");
|
|
||||||
|
|
||||||
collectionView.asyncDataSource = nil;
|
|
||||||
collectionView.asyncDelegate = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - #collectionView:supplementaryNodesOfKind:inSection:
|
#pragma mark - #collectionView:supplementaryNodesOfKind:inSection:
|
||||||
|
|
||||||
- (void)testThatItReturnsOneWhenAValidSizeIsImplementedOnTheDelegate
|
- (void)testThatItReturnsOneWhenAValidSizeIsImplementedOnTheDelegate
|
||||||
|
|||||||
@ -47,28 +47,13 @@
|
|||||||
|
|
||||||
@implementation ASDisplayNodeImplicitHierarchyTests
|
@implementation ASDisplayNodeImplicitHierarchyTests
|
||||||
|
|
||||||
- (void)setUp {
|
|
||||||
[super setUp];
|
|
||||||
[ASDisplayNode setUsesImplicitHierarchyManagement:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tearDown {
|
|
||||||
[ASDisplayNode setUsesImplicitHierarchyManagement:NO];
|
|
||||||
[super tearDown];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)testFeatureFlag
|
- (void)testFeatureFlag
|
||||||
{
|
{
|
||||||
XCTAssert([ASDisplayNode usesImplicitHierarchyManagement]);
|
|
||||||
ASDisplayNode *node = [[ASDisplayNode alloc] init];
|
ASDisplayNode *node = [[ASDisplayNode alloc] init];
|
||||||
XCTAssert(node.usesImplicitHierarchyManagement);
|
XCTAssertFalse(node.automaticallyManagesSubnodes);
|
||||||
|
|
||||||
[ASDisplayNode setUsesImplicitHierarchyManagement:NO];
|
node.automaticallyManagesSubnodes = YES;
|
||||||
XCTAssertFalse([ASDisplayNode usesImplicitHierarchyManagement]);
|
XCTAssertTrue(node.automaticallyManagesSubnodes);
|
||||||
XCTAssertFalse(node.usesImplicitHierarchyManagement);
|
|
||||||
|
|
||||||
node.usesImplicitHierarchyManagement = YES;
|
|
||||||
XCTAssert(node.usesImplicitHierarchyManagement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testInitialNodeInsertionWithOrdering
|
- (void)testInitialNodeInsertionWithOrdering
|
||||||
@ -80,6 +65,7 @@
|
|||||||
ASDisplayNode *node5 = [[ASDisplayNode alloc] init];
|
ASDisplayNode *node5 = [[ASDisplayNode alloc] init];
|
||||||
|
|
||||||
ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
|
ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
|
||||||
|
node.automaticallyManagesSubnodes = YES;
|
||||||
node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
|
node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
|
||||||
ASStaticLayoutSpec *staticLayout = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[node4]];
|
ASStaticLayoutSpec *staticLayout = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[node4]];
|
||||||
|
|
||||||
@ -106,6 +92,7 @@
|
|||||||
ASDisplayNode *node3 = [[ASDisplayNode alloc] init];
|
ASDisplayNode *node3 = [[ASDisplayNode alloc] init];
|
||||||
|
|
||||||
ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
|
ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
|
||||||
|
node.automaticallyManagesSubnodes = YES;
|
||||||
node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize){
|
node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize){
|
||||||
ASSpecTestDisplayNode *strongNode = (ASSpecTestDisplayNode *)weakNode;
|
ASSpecTestDisplayNode *strongNode = (ASSpecTestDisplayNode *)weakNode;
|
||||||
if ([strongNode.layoutState isEqualToNumber:@1]) {
|
if ([strongNode.layoutState isEqualToNumber:@1]) {
|
||||||
@ -136,6 +123,7 @@
|
|||||||
ASDisplayNode *node2 = [[ASDisplayNode alloc] init];
|
ASDisplayNode *node2 = [[ASDisplayNode alloc] init];
|
||||||
|
|
||||||
ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
|
ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
|
||||||
|
node.automaticallyManagesSubnodes = YES;
|
||||||
node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
|
node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
|
||||||
ASSpecTestDisplayNode *strongNode = (ASSpecTestDisplayNode *)weakNode;
|
ASSpecTestDisplayNode *strongNode = (ASSpecTestDisplayNode *)weakNode;
|
||||||
if ([strongNode.layoutState isEqualToNumber:@1]) {
|
if ([strongNode.layoutState isEqualToNumber:@1]) {
|
||||||
@ -179,6 +167,7 @@
|
|||||||
ASDisplayNode *node2 = [[ASDisplayNode alloc] init];
|
ASDisplayNode *node2 = [[ASDisplayNode alloc] init];
|
||||||
|
|
||||||
ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
|
ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
|
||||||
|
node.automaticallyManagesSubnodes = YES;
|
||||||
|
|
||||||
node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
|
node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
|
||||||
ASSpecTestDisplayNode *strongNode = (ASSpecTestDisplayNode *)weakNode;
|
ASSpecTestDisplayNode *strongNode = (ASSpecTestDisplayNode *)weakNode;
|
||||||
@ -190,6 +179,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Intentionally trigger view creation
|
// Intentionally trigger view creation
|
||||||
|
[node view];
|
||||||
|
[node1 view];
|
||||||
[node2 view];
|
[node2 view];
|
||||||
|
|
||||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Fix IHM layout transition also if one node is already loaded"];
|
XCTestExpectation *expectation = [self expectationWithDescription:@"Fix IHM layout transition also if one node is already loaded"];
|
||||||
@ -199,7 +190,7 @@
|
|||||||
|
|
||||||
node.layoutState = @2;
|
node.layoutState = @2;
|
||||||
[node invalidateCalculatedLayout];
|
[node invalidateCalculatedLayout];
|
||||||
[node transitionLayoutWithAnimation:YES shouldMeasureAsync:YES measurementCompletion:^{
|
[node transitionLayoutAnimated:YES measurementCompletion:^{
|
||||||
// Push this to the next runloop to let async insertion / removing of nodes finished before checking
|
// Push this to the next runloop to let async insertion / removing of nodes finished before checking
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
XCTAssertEqual(node.subnodes[0], node2);
|
XCTAssertEqual(node.subnodes[0], node2);
|
||||||
|
|||||||
36
AsyncDisplayKitTests/ASDisplayNodeSnapshotTests.m
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// ASDisplayNodeSnapshotTests.m
|
||||||
|
// AsyncDisplayKit
|
||||||
|
//
|
||||||
|
// Created by Adlai Holler on 8/16/16.
|
||||||
|
// Copyright © 2016 Facebook. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "ASSnapshotTestCase.h"
|
||||||
|
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||||
|
|
||||||
|
@interface ASDisplayNodeSnapshotTests : ASSnapshotTestCase
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ASDisplayNodeSnapshotTests
|
||||||
|
|
||||||
|
- (void)testBasicHierarchySnapshotTesting
|
||||||
|
{
|
||||||
|
ASDisplayNode *node = [[ASDisplayNode alloc] init];
|
||||||
|
node.backgroundColor = [UIColor blueColor];
|
||||||
|
|
||||||
|
ASTextNode *subnode = [[ASTextNode alloc] init];
|
||||||
|
subnode.backgroundColor = [UIColor whiteColor];
|
||||||
|
|
||||||
|
subnode.attributedText = [[NSAttributedString alloc] initWithString:@"Hello"];
|
||||||
|
node.automaticallyManagesSubnodes = YES;
|
||||||
|
node.layoutSpecBlock = ^(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
|
||||||
|
return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(5, 5, 5, 5) child:subnode];
|
||||||
|
};
|
||||||
|
[node measure:CGSizeMake(100, 100)];
|
||||||
|
|
||||||
|
ASSnapshotVerifyNode(node, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@ -29,7 +29,7 @@
|
|||||||
// trivial test case to ensure ASSnapshotTestCase works
|
// trivial test case to ensure ASSnapshotTestCase works
|
||||||
ASImageNode *imageNode = [[ASImageNode alloc] init];
|
ASImageNode *imageNode = [[ASImageNode alloc] init];
|
||||||
imageNode.image = [self testImage];
|
imageNode.image = [self testImage];
|
||||||
imageNode.frame = CGRectMake(0, 0, 100, 100);
|
[imageNode measure:CGSizeMake(100, 100)];
|
||||||
|
|
||||||
ASSnapshotVerifyNode(imageNode, nil);
|
ASSnapshotVerifyNode(imageNode, nil);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
#import "ASLayout.h"
|
#import "ASLayout.h"
|
||||||
|
|
||||||
@interface ASTestNode : ASDisplayNode
|
@interface ASTestNode : ASDisplayNode
|
||||||
- (void)setLayoutSpecUnderTest:(ASLayoutSpec *)layoutSpecUnderTest sizeRange:(ASSizeRange)sizeRange;
|
@property (strong, nonatomic, nullable) ASLayoutSpec *layoutSpecUnderTest;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ASLayoutSpecSnapshotTestCase
|
@implementation ASLayoutSpecSnapshotTestCase
|
||||||
@ -37,18 +37,15 @@
|
|||||||
[node addSubnode:subnode];
|
[node addSubnode:subnode];
|
||||||
}
|
}
|
||||||
|
|
||||||
[node setLayoutSpecUnderTest:layoutSpec sizeRange:sizeRange];
|
node.layoutSpecUnderTest = layoutSpec;
|
||||||
|
|
||||||
|
[node measureWithSizeRange:sizeRange];
|
||||||
ASSnapshotVerifyNode(node, identifier);
|
ASSnapshotVerifyNode(node, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ASTestNode
|
@implementation ASTestNode
|
||||||
{
|
|
||||||
ASLayout *_layoutUnderTest;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
@ -57,22 +54,9 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setLayoutSpecUnderTest:(ASLayoutSpec *)layoutSpecUnderTest sizeRange:(ASSizeRange)sizeRange
|
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
|
||||||
{
|
{
|
||||||
ASLayout *layout = [layoutSpecUnderTest measureWithSizeRange:sizeRange];
|
return _layoutSpecUnderTest;
|
||||||
layout.position = CGPointZero;
|
|
||||||
layout = [ASLayout layoutWithLayoutableObject:self
|
|
||||||
constrainedSizeRange:sizeRange
|
|
||||||
size:layout.size
|
|
||||||
sublayouts:@[layout]];
|
|
||||||
_layoutUnderTest = [layout filteredNodeLayoutTree];
|
|
||||||
self.frame = CGRectMake(0, 0, _layoutUnderTest.size.width, _layoutUnderTest.size.height);
|
|
||||||
[self measure:_layoutUnderTest.size];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
|
|
||||||
{
|
|
||||||
return _layoutUnderTest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#import <FBSnapshotTestCase/FBSnapshotTestCase.h>
|
#import <FBSnapshotTestCase/FBSnapshotTestCase.h>
|
||||||
|
|
||||||
#import <AsyncDisplayKit/ASDisplayNode.h>
|
@class ASDisplayNode;
|
||||||
|
|
||||||
#define ASSnapshotVerifyNode(node__, identifier__) \
|
#define ASSnapshotVerifyNode(node__, identifier__) \
|
||||||
{ \
|
{ \
|
||||||
|
|||||||
28
AsyncDisplayKitTests/ASSnapshotTestCase.m
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// ASSnapshotTestCase.m
|
||||||
|
// 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 "ASSnapshotTestCase.h"
|
||||||
|
#import "ASDisplayNode+Beta.h"
|
||||||
|
#import "ASDisplayNodeExtras.h"
|
||||||
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
|
|
||||||
|
@implementation ASSnapshotTestCase
|
||||||
|
|
||||||
|
+ (void)hackilySynchronouslyRecursivelyRenderNode:(ASDisplayNode *)node
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssertNotNil(node.calculatedLayout, @"Node %@ must be measured before it is rendered.", node);
|
||||||
|
node.bounds = (CGRect) { .size = node.calculatedSize };
|
||||||
|
ASDisplayNodePerformBlockOnEveryNode(nil, node, ^(ASDisplayNode * _Nonnull node) {
|
||||||
|
[node.layer setNeedsDisplay];
|
||||||
|
});
|
||||||
|
[node recursivelyEnsureDisplaySynchronously:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@ -1,57 +0,0 @@
|
|||||||
//
|
|
||||||
// ASSnapshotTestCase.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 "ASSnapshotTestCase.h"
|
|
||||||
#import "ASDisplayNode+FrameworkPrivate.h"
|
|
||||||
#import "ASDisplayNodeInternal.h"
|
|
||||||
|
|
||||||
@implementation ASSnapshotTestCase
|
|
||||||
|
|
||||||
+ (void)_layoutAndDisplayNode:(ASDisplayNode *)node
|
|
||||||
{
|
|
||||||
if (![node __shouldLoadViewOrLayer]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CALayer *layer = node.layer;
|
|
||||||
|
|
||||||
[layer setNeedsLayout];
|
|
||||||
[layer layoutIfNeeded];
|
|
||||||
|
|
||||||
[layer setNeedsDisplay];
|
|
||||||
[layer displayIfNeeded];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)_recursivelyLayoutAndDisplayNode:(ASDisplayNode *)node
|
|
||||||
{
|
|
||||||
for (ASDisplayNode *subnode in node.subnodes) {
|
|
||||||
[self _recursivelyLayoutAndDisplayNode:subnode];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self _layoutAndDisplayNode:node];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)_recursivelySetDisplaysAsynchronously:(BOOL)flag forNode:(ASDisplayNode *)node
|
|
||||||
{
|
|
||||||
node.displaysAsynchronously = flag;
|
|
||||||
|
|
||||||
for (ASDisplayNode *subnode in node.subnodes) {
|
|
||||||
[self _recursivelySetDisplaysAsynchronously:flag forNode:subnode];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)hackilySynchronouslyRecursivelyRenderNode:(ASDisplayNode *)node
|
|
||||||
{
|
|
||||||
// TODO: Reconfigure this to be able to use [node recursivelyEnsureDisplay];
|
|
||||||
[self _recursivelySetDisplaysAsynchronously:NO forNode:node];
|
|
||||||
[self _recursivelyLayoutAndDisplayNode:node];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -330,7 +330,7 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
|
|||||||
subnode2.staticSize = {50, 50};
|
subnode2.staticSize = {50, 50};
|
||||||
|
|
||||||
ASRatioLayoutSpec *child1 = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.5 child:subnode1];
|
ASRatioLayoutSpec *child1 = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.5 child:subnode1];
|
||||||
child1.flexBasis = ASRelativeDimensionMakeWithPercent(1);
|
child1.flexBasis = ASRelativeDimensionMakeWithFraction(1);
|
||||||
child1.flexGrow = YES;
|
child1.flexGrow = YES;
|
||||||
child1.flexShrink = YES;
|
child1.flexShrink = YES;
|
||||||
|
|
||||||
@ -508,7 +508,7 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
|
|||||||
[self testStackLayoutSpecWithStyle:style sizeRange:kOverflowSize subnodes:subnodes identifier:@"overflow"];
|
[self testStackLayoutSpecWithStyle:style sizeRange:kOverflowSize subnodes:subnodes identifier:@"overflow"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testPercentageFlexBasisResolvesAgainstParentSize
|
- (void)testFractionalFlexBasisResolvesAgainstParentSize
|
||||||
{
|
{
|
||||||
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
ASStackLayoutSpecStyle style = {.direction = ASStackLayoutDirectionHorizontal};
|
||||||
|
|
||||||
@ -520,7 +520,7 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
|
|||||||
|
|
||||||
// This should override the intrinsic size of 50pts and instead compute to 50% = 100pts.
|
// This should override the intrinsic size of 50pts and instead compute to 50% = 100pts.
|
||||||
// The result should be that the red box is twice as wide as the blue and gree boxes after flexing.
|
// The result should be that the red box is twice as wide as the blue and gree boxes after flexing.
|
||||||
((ASStaticSizeDisplayNode *)subnodes[0]).flexBasis = ASRelativeDimensionMakeWithPercent(0.5);
|
((ASStaticSizeDisplayNode *)subnodes[0]).flexBasis = ASRelativeDimensionMakeWithFraction(0.5);
|
||||||
|
|
||||||
static ASSizeRange kSize = {{200, 0}, {200, INFINITY}};
|
static ASSizeRange kSize = {{200, 0}, {200, INFINITY}};
|
||||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||||
|
|||||||
56
AsyncDisplayKitTests/ASTextNodeSnapshotTests.m
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// ASTextNodeSnapshotTests.m
|
||||||
|
// AsyncDisplayKit
|
||||||
|
//
|
||||||
|
// Created by Garrett Moon on 8/12/16.
|
||||||
|
// 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 "ASSnapshotTestCase.h"
|
||||||
|
|
||||||
|
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||||
|
|
||||||
|
@interface ASTextNodeSnapshotTests : ASSnapshotTestCase
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ASTextNodeSnapshotTests
|
||||||
|
|
||||||
|
- (void)testTextContainerInset
|
||||||
|
{
|
||||||
|
// trivial test case to ensure ASSnapshotTestCase works
|
||||||
|
ASTextNode *textNode = [[ASTextNode alloc] init];
|
||||||
|
textNode.attributedText = [[NSAttributedString alloc] initWithString:@"judar"
|
||||||
|
attributes:@{NSFontAttributeName : [UIFont italicSystemFontOfSize:24]}];
|
||||||
|
[textNode measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX))];
|
||||||
|
textNode.textContainerInset = UIEdgeInsetsMake(0, 2, 0, 2);
|
||||||
|
|
||||||
|
ASSnapshotVerifyNode(textNode, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testTextContainerInsetHighlight
|
||||||
|
{
|
||||||
|
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
|
backgroundView.layer.as_allowsHighlightDrawing = YES;
|
||||||
|
|
||||||
|
ASTextNode *textNode = [[ASTextNode alloc] init];
|
||||||
|
textNode.attributedText = [[NSAttributedString alloc] initWithString:@"yolo"
|
||||||
|
attributes:@{ NSFontAttributeName : [UIFont systemFontOfSize:30] }];
|
||||||
|
|
||||||
|
[textNode measureWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX))];
|
||||||
|
textNode.frame = CGRectMake(50, 50, textNode.calculatedSize.width, textNode.calculatedSize.height);
|
||||||
|
textNode.textContainerInset = UIEdgeInsetsMake(5, 10, 10, 5);
|
||||||
|
|
||||||
|
[backgroundView addSubview:textNode.view];
|
||||||
|
backgroundView.frame = UIEdgeInsetsInsetRect(textNode.bounds, UIEdgeInsetsMake(-50, -50, -50, -50));
|
||||||
|
|
||||||
|
textNode.highlightRange = NSMakeRange(0, textNode.attributedText.length);
|
||||||
|
|
||||||
|
[ASSnapshotTestCase hackilySynchronouslyRecursivelyRenderNode:textNode];
|
||||||
|
FBSnapshotVerifyLayer(backgroundView.layer, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
70
AsyncDisplayKitTests/ASUICollectionViewTests.m
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
//
|
||||||
|
// ASUICollectionViewTests.m
|
||||||
|
// AsyncDisplayKit
|
||||||
|
//
|
||||||
|
// Created by Adlai Holler on 8/18/16.
|
||||||
|
// Copyright © 2016 Facebook. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <XCTest/XCTest.h>
|
||||||
|
#import <OCMock/OCMock.h>
|
||||||
|
|
||||||
|
@interface ASUICollectionViewTests : XCTestCase
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ASUICollectionViewTests
|
||||||
|
|
||||||
|
/// Test normal item-affiliated supplementary node
|
||||||
|
- (void)testNormalTwoIndexSupplementaryElement
|
||||||
|
{
|
||||||
|
[self _testSupplementaryNodeAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:1] sectionCount:2 expectException:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If your supp is indexPathForItem:inSection:, the section index must be in bounds
|
||||||
|
- (void)testThatSupplementariesWithItemIndexesMustBeWithinNormalSections
|
||||||
|
{
|
||||||
|
[self _testSupplementaryNodeAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:3] sectionCount:2 expectException:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If your supp is indexPathWithIndex:, that's OK even if that section is out of bounds!
|
||||||
|
- (void)testThatSupplementariesWithOneIndexAreOKOutOfSectionBounds
|
||||||
|
{
|
||||||
|
[self _testSupplementaryNodeAtIndexPath:[NSIndexPath indexPathWithIndex:3] sectionCount:2 expectException:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_testSupplementaryNodeAtIndexPath:(NSIndexPath *)indexPath sectionCount:(NSInteger)sectionCount expectException:(BOOL)shouldFail
|
||||||
|
{
|
||||||
|
UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:@"SuppKind" withIndexPath:indexPath];
|
||||||
|
attr.frame = CGRectMake(0, 0, 20, 20);
|
||||||
|
UICollectionViewLayout *layout = [[UICollectionViewLayout alloc] init];
|
||||||
|
id layoutMock = [OCMockObject partialMockForObject:layout];
|
||||||
|
|
||||||
|
[[[[layoutMock expect] ignoringNonObjectArgs] andReturn:@[ attr ]] layoutAttributesForElementsInRect:CGRectZero];
|
||||||
|
UICollectionView *cv = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) collectionViewLayout:layoutMock];
|
||||||
|
[cv registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:@"SuppKind" withReuseIdentifier:@"ReuseID"];
|
||||||
|
|
||||||
|
id dataSource = [OCMockObject niceMockForProtocol:@protocol(UICollectionViewDataSource)];
|
||||||
|
__block id view = nil;
|
||||||
|
[[[dataSource expect] andDo:^(NSInvocation *invocation) {
|
||||||
|
NSIndexPath *indexPath = nil;
|
||||||
|
[invocation getArgument:&indexPath atIndex:4];
|
||||||
|
view = [cv dequeueReusableSupplementaryViewOfKind:@"SuppKind" withReuseIdentifier:@"ReuseID" forIndexPath:indexPath];
|
||||||
|
[invocation setReturnValue:&view];
|
||||||
|
}] collectionView:cv viewForSupplementaryElementOfKind:@"SuppKind" atIndexPath:indexPath];
|
||||||
|
[[[dataSource expect] andReturnValue:[NSNumber numberWithInteger:sectionCount]] numberOfSectionsInCollectionView:cv];
|
||||||
|
|
||||||
|
cv.dataSource = dataSource;
|
||||||
|
if (shouldFail) {
|
||||||
|
XCTAssertThrowsSpecificNamed([cv layoutIfNeeded], NSException, NSInternalInconsistencyException);
|
||||||
|
} else {
|
||||||
|
[cv layoutIfNeeded];
|
||||||
|
XCTAssertEqualObjects(attr, [cv layoutAttributesForSupplementaryElementOfKind:@"SuppKind" atIndexPath:indexPath]);
|
||||||
|
XCTAssertEqual(view, [cv supplementaryViewForElementKind:@"SuppKind" atIndexPath:indexPath]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[dataSource verify];
|
||||||
|
[layoutMock verify];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
BIN
examples/ASDKLayoutTransition/Default-568h@2x.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
examples/ASDKLayoutTransition/Default-667h@2x.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
examples/ASDKLayoutTransition/Default-736h@3x.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
5
examples/ASDKLayoutTransition/Podfile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
source 'https://github.com/CocoaPods/Specs.git'
|
||||||
|
platform :ios, '7.0'
|
||||||
|
target 'Sample' do
|
||||||
|
pod 'AsyncDisplayKit', :path => '../..'
|
||||||
|
end
|
||||||
368
examples/ASDKLayoutTransition/Sample.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 46;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
0585428019D4DBE100606EA6 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0585427F19D4DBE100606EA6 /* Default-568h@2x.png */; };
|
||||||
|
05E2128719D4DB510098F589 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128619D4DB510098F589 /* main.m */; };
|
||||||
|
05E2128A19D4DB510098F589 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128919D4DB510098F589 /* AppDelegate.m */; };
|
||||||
|
05E2128D19D4DB510098F589 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128C19D4DB510098F589 /* ViewController.m */; };
|
||||||
|
6C2C82AC19EE274300767484 /* Default-667h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C2C82AA19EE274300767484 /* Default-667h@2x.png */; };
|
||||||
|
6C2C82AD19EE274300767484 /* Default-736h@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C2C82AB19EE274300767484 /* Default-736h@3x.png */; };
|
||||||
|
DFE855DDBC731242D3515B58 /* libPods-Sample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C284F7E957985CA251284B05 /* libPods-Sample.a */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
0585427F19D4DBE100606EA6 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "../Default-568h@2x.png"; sourceTree = "<group>"; };
|
||||||
|
05E2128119D4DB510098F589 /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
05E2128519D4DB510098F589 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
05E2128619D4DB510098F589 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
|
05E2128819D4DB510098F589 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||||
|
05E2128919D4DB510098F589 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||||
|
05E2128B19D4DB510098F589 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
|
||||||
|
05E2128C19D4DB510098F589 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
|
||||||
|
1C47DEC3F9D2BD9AD5F5CD67 /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
6C2C82AA19EE274300767484 /* Default-667h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-667h@2x.png"; sourceTree = SOURCE_ROOT; };
|
||||||
|
6C2C82AB19EE274300767484 /* Default-736h@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-736h@3x.png"; sourceTree = SOURCE_ROOT; };
|
||||||
|
79ED4D85CC60068C341CFD77 /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
C284F7E957985CA251284B05 /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
05E2127E19D4DB510098F589 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
DFE855DDBC731242D3515B58 /* libPods-Sample.a in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
05E2127819D4DB510098F589 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
05E2128319D4DB510098F589 /* Sample */,
|
||||||
|
05E2128219D4DB510098F589 /* Products */,
|
||||||
|
1A943BF0259746F18D6E423F /* Frameworks */,
|
||||||
|
1AE410B73DA5C3BD087ACDD7 /* Pods */,
|
||||||
|
);
|
||||||
|
indentWidth = 2;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
tabWidth = 2;
|
||||||
|
usesTabs = 0;
|
||||||
|
};
|
||||||
|
05E2128219D4DB510098F589 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
05E2128119D4DB510098F589 /* Sample.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
05E2128319D4DB510098F589 /* Sample */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
05E2128819D4DB510098F589 /* AppDelegate.h */,
|
||||||
|
05E2128919D4DB510098F589 /* AppDelegate.m */,
|
||||||
|
05E2128B19D4DB510098F589 /* ViewController.h */,
|
||||||
|
05E2128C19D4DB510098F589 /* ViewController.m */,
|
||||||
|
05E2128419D4DB510098F589 /* Supporting Files */,
|
||||||
|
);
|
||||||
|
path = Sample;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
05E2128419D4DB510098F589 /* Supporting Files */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0585427F19D4DBE100606EA6 /* Default-568h@2x.png */,
|
||||||
|
6C2C82AA19EE274300767484 /* Default-667h@2x.png */,
|
||||||
|
6C2C82AB19EE274300767484 /* Default-736h@3x.png */,
|
||||||
|
05E2128519D4DB510098F589 /* Info.plist */,
|
||||||
|
05E2128619D4DB510098F589 /* main.m */,
|
||||||
|
);
|
||||||
|
name = "Supporting Files";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
1A943BF0259746F18D6E423F /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
C284F7E957985CA251284B05 /* libPods-Sample.a */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
1AE410B73DA5C3BD087ACDD7 /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
79ED4D85CC60068C341CFD77 /* Pods-Sample.debug.xcconfig */,
|
||||||
|
1C47DEC3F9D2BD9AD5F5CD67 /* Pods-Sample.release.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
05E2128019D4DB510098F589 /* Sample */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 05E212A419D4DB510098F589 /* Build configuration list for PBXNativeTarget "Sample" */;
|
||||||
|
buildPhases = (
|
||||||
|
E080B80F89C34A25B3488E26 /* [CP] Check Pods Manifest.lock */,
|
||||||
|
05E2127D19D4DB510098F589 /* Sources */,
|
||||||
|
05E2127E19D4DB510098F589 /* Frameworks */,
|
||||||
|
05E2127F19D4DB510098F589 /* Resources */,
|
||||||
|
F012A6F39E0149F18F564F50 /* [CP] Copy Pods Resources */,
|
||||||
|
6E05308BEF86AD80AEB4EEE7 /* [CP] Embed Pods Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = Sample;
|
||||||
|
productName = Sample;
|
||||||
|
productReference = 05E2128119D4DB510098F589 /* Sample.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
05E2127919D4DB510098F589 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 0710;
|
||||||
|
ORGANIZATIONNAME = Facebook;
|
||||||
|
TargetAttributes = {
|
||||||
|
05E2128019D4DB510098F589 = {
|
||||||
|
CreatedOnToolsVersion = 6.0.1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 05E2127C19D4DB510098F589 /* Build configuration list for PBXProject "Sample" */;
|
||||||
|
compatibilityVersion = "Xcode 3.2";
|
||||||
|
developmentRegion = English;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 05E2127819D4DB510098F589;
|
||||||
|
productRefGroup = 05E2128219D4DB510098F589 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
05E2128019D4DB510098F589 /* Sample */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
05E2127F19D4DB510098F589 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
0585428019D4DBE100606EA6 /* Default-568h@2x.png in Resources */,
|
||||||
|
6C2C82AC19EE274300767484 /* Default-667h@2x.png in Resources */,
|
||||||
|
6C2C82AD19EE274300767484 /* Default-736h@3x.png in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
6E05308BEF86AD80AEB4EEE7 /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
E080B80F89C34A25B3488E26 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
F012A6F39E0149F18F564F50 /* [CP] Copy Pods Resources */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "[CP] Copy Pods Resources";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
05E2127D19D4DB510098F589 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
05E2128D19D4DB510098F589 /* ViewController.m in Sources */,
|
||||||
|
05E2128A19D4DB510098F589 /* AppDelegate.m in Sources */,
|
||||||
|
05E2128719D4DB510098F589 /* main.m in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
05E212A219D4DB510098F589 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
05E212A319D4DB510098F589 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = YES;
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
05E212A519D4DB510098F589 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 79ED4D85CC60068C341CFD77 /* Pods-Sample.debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
INFOPLIST_FILE = Sample/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
05E212A619D4DB510098F589 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 1C47DEC3F9D2BD9AD5F5CD67 /* Pods-Sample.release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
INFOPLIST_FILE = Sample/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
05E2127C19D4DB510098F589 /* Build configuration list for PBXProject "Sample" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
05E212A219D4DB510098F589 /* Debug */,
|
||||||
|
05E212A319D4DB510098F589 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
05E212A419D4DB510098F589 /* Build configuration list for PBXNativeTarget "Sample" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
05E212A519D4DB510098F589 /* Debug */,
|
||||||
|
05E212A619D4DB510098F589 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 05E2127919D4DB510098F589 /* Project object */;
|
||||||
|
}
|
||||||
7
examples/ASDKLayoutTransition/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:Sample.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "0710"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "05E2128019D4DB510098F589"
|
||||||
|
BuildableName = "Sample.app"
|
||||||
|
BlueprintName = "Sample"
|
||||||
|
ReferencedContainer = "container:Sample.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "05E2128019D4DB510098F589"
|
||||||
|
BuildableName = "Sample.app"
|
||||||
|
BlueprintName = "Sample"
|
||||||
|
ReferencedContainer = "container:Sample.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "05E2128019D4DB510098F589"
|
||||||
|
BuildableName = "Sample.app"
|
||||||
|
BlueprintName = "Sample"
|
||||||
|
ReferencedContainer = "container:Sample.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "05E2128019D4DB510098F589"
|
||||||
|
BuildableName = "Sample.app"
|
||||||
|
BlueprintName = "Sample"
|
||||||
|
ReferencedContainer = "container:Sample.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||