diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 631fc6d0..24a82c91 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -250,6 +250,7 @@ 509E68661B3AEDD7009B9150 /* CGRect+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E201B376416007741D0 /* CGRect+ASConvenience.m */; }; 636EA1A41C7FF4EC00EE152F /* NSArray+Diffing.m in Sources */ = {isa = PBXBuildFile; fileRef = DBC452DA1C5BF64600B16017 /* NSArray+Diffing.m */; }; 636EA1A51C7FF4EF00EE152F /* ASDefaultPlayButton.m in Sources */ = {isa = PBXBuildFile; fileRef = AEB7B0191C5962EA00662EF4 /* ASDefaultPlayButton.m */; }; + 680346941CE4052A0009FEB4 /* ASNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68355B311CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */; }; 68355B341CB579B9001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */; }; 68355B3A1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m */; }; @@ -272,6 +273,17 @@ 68EE0DBE1C1B4ED300BA1B99 /* ASMainSerialQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */; }; 68EE0DBF1C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; 68EE0DC01C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; + 68FC85DE1CE29AB700EDD713 /* ASNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68FC85DF1CE29AB700EDD713 /* ASNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85DD1CE29AB700EDD713 /* ASNavigationController.m */; }; + 68FC85E21CE29B7E00EDD713 /* ASTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68FC85E31CE29B7E00EDD713 /* ASTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68FC85E41CE29B7E00EDD713 /* ASTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E11CE29B7E00EDD713 /* ASTabBarController.m */; }; + 68FC85E51CE29B7E00EDD713 /* ASTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E11CE29B7E00EDD713 /* ASTabBarController.m */; }; + 68FC85E61CE29B9400EDD713 /* ASNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85DD1CE29AB700EDD713 /* ASNavigationController.m */; }; + 68FC85E91CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68FC85EA1CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68FC85EB1CE29C7D00EDD713 /* ASVisibilityProtocols.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */; }; + 68FC85EC1CE29C7D00EDD713 /* ASVisibilityProtocols.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */; }; 698548631CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; 698548641CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; 698C8B611CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -787,6 +799,12 @@ 68B8A4E01CBDB958007E4543 /* ASWeakProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASWeakProxy.m; sourceTree = ""; }; 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMainSerialQueue.h; sourceTree = ""; }; 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMainSerialQueue.mm; sourceTree = ""; }; + 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASNavigationController.h; sourceTree = ""; }; + 68FC85DD1CE29AB700EDD713 /* ASNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASNavigationController.m; sourceTree = ""; }; + 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTabBarController.h; sourceTree = ""; }; + 68FC85E11CE29B7E00EDD713 /* ASTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTabBarController.m; sourceTree = ""; }; + 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASVisibilityProtocols.h; sourceTree = ""; }; + 68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASVisibilityProtocols.m; sourceTree = ""; }; 698548611CA9E025008A345F /* ASEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEnvironment.h; sourceTree = ""; }; 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutableExtensibility.h; path = AsyncDisplayKit/Layout/ASLayoutableExtensibility.h; sourceTree = ""; }; 69CB62A91CB8165900024920 /* _ASDisplayViewAccessiblity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASDisplayViewAccessiblity.h; sourceTree = ""; }; @@ -1075,6 +1093,8 @@ 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */, 0516FA3E1A1563D200B4EBED /* ASMultiplexImageNode.h */, 0516FA3F1A1563D200B4EBED /* ASMultiplexImageNode.mm */, + 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */, + 68FC85DD1CE29AB700EDD713 /* ASNavigationController.m */, 055B9FA61A1C154B00035D6D /* ASNetworkImageNode.h */, 055B9FA71A1C154B00035D6D /* ASNetworkImageNode.mm */, 25E327541C16819500A2170C /* ASPagerNode.h */, @@ -1083,6 +1103,8 @@ A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.m */, D785F6601A74327E00291744 /* ASScrollNode.h */, D785F6611A74327E00291744 /* ASScrollNode.m */, + 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */, + 68FC85E11CE29B7E00EDD713 /* ASTabBarController.m */, B0F880581BEAEC7500D17647 /* ASTableNode.h */, 9CFFC6C11CCAC768006A6476 /* ASTableNode.mm */, 055F1A3219ABD3E3004DAFF1 /* ASTableView.h */, @@ -1098,6 +1120,8 @@ 764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */, 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */, DB55C2651C641AE4004EDCF5 /* ASContextTransitioning.h */, + 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */, + 68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */, 92074A5E1CC8B9DD00918F75 /* tvOS */, 058D09E1195D050800B7D73C /* Details */, 058D0A01195D050800B7D73C /* Private */, @@ -1493,6 +1517,7 @@ 058D0A82195D060300B7D73C /* ASAssert.h in Headers */, 0516FA3C1A15563400B4EBED /* ASAvailability.h in Headers */, AEB7B01A1C5962EA00662EF4 /* ASDefaultPlayButton.h in Headers */, + 68FC85E21CE29B7E00EDD713 /* ASTabBarController.h in Headers */, ACF6ED1A1B17843500DA7C62 /* ASBackgroundLayoutSpec.h in Headers */, 058D0A83195D060300B7D73C /* ASBaseDefines.h in Headers */, 054963491A1EA066000F8E56 /* ASBasicImageDownloader.h in Headers */, @@ -1508,6 +1533,7 @@ AC3C4A511A1139C100143C57 /* ASCollectionView.h in Headers */, AEEC47E11C20C2DD00EC1693 /* ASVideoNode.h in Headers */, DE8BEAC11C2DF3FC00D57C12 /* ASDelegateProxy.h in Headers */, + 68FC85DE1CE29AB700EDD713 /* ASNavigationController.h in Headers */, 205F0E1D1B373A2C007741D0 /* ASCollectionViewLayoutController.h in Headers */, AC3C4A541A113EEC00143C57 /* ASCollectionViewProtocols.h in Headers */, 058D0A49195D05CB00B7D73C /* ASControlNode+Subclasses.h in Headers */, @@ -1533,6 +1559,7 @@ 0587F9BD1A7309ED00AFF0BA /* ASEditableTextNode.h in Headers */, DE6EA3221C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */, 1950C4491A3BB5C1005C8279 /* ASEqualityHelpers.h in Headers */, + 68FC85E91CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */, 257754A81BEE44CD00737CA5 /* ASTextKitContext.h in Headers */, DB55C2611C6408D6004EDCF5 /* _ASTransitionContext.h in Headers */, 464052221A3F83C40061C0BA /* ASFlowLayoutController.h in Headers */, @@ -1667,6 +1694,7 @@ CC3B20841C3F76D600798563 /* ASPendingStateController.h in Headers */, 92074A621CC8BA1900918F75 /* ASImageNode+tvOS.h in Headers */, B35061F71B010EFD0018CF92 /* ASCollectionViewProtocols.h in Headers */, + 68FC85E31CE29B7E00EDD713 /* ASTabBarController.h in Headers */, DE6EA3231C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */, 9C70F20F1CDBE9FF007D6C76 /* ASLayoutManager.h in Headers */, B35061FA1B010EFD0018CF92 /* ASControlNode+Subclasses.h in Headers */, @@ -1674,6 +1702,7 @@ B35062171B010EFD0018CF92 /* ASDataController.h in Headers */, B35062191B010EFD0018CF92 /* ASDealloc2MainObject.h in Headers */, 34EFC75B1B701BAF00AD841F /* ASDimension.h in Headers */, + 68FC85EA1CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */, A37320101C571B740011FC94 /* ASTextNode+Beta.h in Headers */, DBABFAFC1C6A8D2F0039EA4A /* _ASTransitionContext.h in Headers */, 9C70F2061CDA4F0C007D6C76 /* ASTraitCollection.h in Headers */, @@ -1685,6 +1714,7 @@ B35062521B010EFD0018CF92 /* ASDisplayNodeInternal.h in Headers */, B35062001B010EFD0018CF92 /* ASEditableTextNode.h in Headers */, B350625B1B010F070018CF92 /* ASEqualityHelpers.h in Headers */, + 680346941CE4052A0009FEB4 /* ASNavigationController.h in Headers */, B350621B1B010EFD0018CF92 /* ASFlowLayoutController.h in Headers */, B350621D1B010EFD0018CF92 /* ASHighlightOverlayLayer.h in Headers */, C78F7E2B1BF7809800CDEAFC /* ASTableNode.h in Headers */, @@ -1975,6 +2005,7 @@ files = ( 058D0A22195D050800B7D73C /* _ASAsyncTransaction.mm in Sources */, E55D86321CA8A14000A0C26F /* ASLayoutable.mm in Sources */, + 68FC85E41CE29B7E00EDD713 /* ASTabBarController.m in Sources */, 058D0A23195D050800B7D73C /* _ASAsyncTransactionContainer.m in Sources */, 058D0A24195D050800B7D73C /* _ASAsyncTransactionGroup.m in Sources */, 68355B3A1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m in Sources */, @@ -2004,6 +2035,7 @@ AC3C4A521A1139C100143C57 /* ASCollectionView.mm in Sources */, 9CFFC6C21CCAC768006A6476 /* ASTableNode.mm in Sources */, 205F0E1E1B373A2C007741D0 /* ASCollectionViewLayoutController.mm in Sources */, + 68FC85EB1CE29C7D00EDD713 /* ASVisibilityProtocols.m in Sources */, 058D0A13195D050800B7D73C /* ASControlNode.mm in Sources */, 464052211A3F83C40061C0BA /* ASDataController.mm in Sources */, B30BF6531C5964B0004FCD53 /* ASLayoutManager.m in Sources */, @@ -2028,6 +2060,7 @@ 430E7C911B4C23F100697A4C /* ASIndexPath.m in Sources */, ACF6ED231B17843500DA7C62 /* ASInsetLayoutSpec.mm in Sources */, ACF6ED4C1B17847A00DA7C62 /* ASInternalHelpers.mm in Sources */, + 68FC85DF1CE29AB700EDD713 /* ASNavigationController.m in Sources */, ACF6ED251B17843500DA7C62 /* ASLayout.mm in Sources */, DB55C2631C6408D6004EDCF5 /* _ASTransitionContext.m in Sources */, 92074A631CC8BA1900918F75 /* ASImageNode+tvOS.m in Sources */, @@ -2161,6 +2194,7 @@ 34EFC7641B701CC600AD841F /* ASCenterLayoutSpec.mm in Sources */, 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */, E55D86331CA8A14000A0C26F /* ASLayoutable.mm in Sources */, + 68FC85EC1CE29C7D00EDD713 /* ASVisibilityProtocols.m in Sources */, 68B8A4E41CBDB958007E4543 /* ASWeakProxy.m in Sources */, 9C70F20A1CDBE949007D6C76 /* ASTableNode.mm in Sources */, 69CB62AE1CB8165900024920 /* _ASDisplayViewAccessiblity.mm in Sources */, @@ -2209,6 +2243,7 @@ 044285101BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm in Sources */, B35062271B010EFD0018CF92 /* ASRangeController.mm in Sources */, 0442850A1BAA63FE00D16268 /* ASBatchFetching.m in Sources */, + 68FC85E61CE29B9400EDD713 /* ASNavigationController.m in Sources */, 34EFC76F1B701CF700AD841F /* ASRatioLayoutSpec.mm in Sources */, 254C6B8B1BF94F8A003EC431 /* ASTextKitShadower.mm in Sources */, 34EFC7661B701CD200AD841F /* ASRelativeSize.mm in Sources */, @@ -2223,6 +2258,7 @@ 9C70F2051CDA4F06007D6C76 /* ASTraitCollection.m in Sources */, 34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */, DE84918E1C8FFF9F003D89E9 /* ASRunLoopQueue.mm in Sources */, + 68FC85E51CE29B7E00EDD713 /* ASTabBarController.m in Sources */, AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */, 34EFC7741B701D0A00AD841F /* ASStaticLayoutSpec.mm in Sources */, 92074A6A1CC8BADA00918F75 /* ASControlNode+tvOS.m in Sources */, diff --git a/AsyncDisplayKit/ASNavigationController.h b/AsyncDisplayKit/ASNavigationController.h new file mode 100644 index 00000000..c849f708 --- /dev/null +++ b/AsyncDisplayKit/ASNavigationController.h @@ -0,0 +1,15 @@ +// +// ASNavigationController.h +// Pods +// +// Created by Garrett Moon on 4/27/16. +// +// + +#import + +#import "ASVisibilityProtocols.h" + +@interface ASNavigationController : UINavigationController + +@end diff --git a/AsyncDisplayKit/ASNavigationController.m b/AsyncDisplayKit/ASNavigationController.m new file mode 100644 index 00000000..a246aa33 --- /dev/null +++ b/AsyncDisplayKit/ASNavigationController.m @@ -0,0 +1,93 @@ +// +// ASNavigationController.m +// Pods +// +// Created by Garrett Moon on 4/27/16. +// +// + +#import "ASNavigationController.h" + +@implementation ASNavigationController +{ + BOOL _parentManagesVisibilityDepth; + NSInteger _visibilityDepth; +} + +ASVisibilityDidMoveToParentViewController; + +ASVisibilityViewWillAppear; + +ASVisibilityViewDidDisappearImplementation; + +ASVisibilitySetVisibilityDepth; + +ASVisibilityDepthImplementation; + +- (void)visibilityDepthDidChange +{ + for (UIViewController *viewController in self.viewControllers) { + if ([viewController conformsToProtocol:@protocol(ASVisibilityDepth)]) { + [(id )viewController visibilityDepthDidChange]; + } + } +} + +- (NSInteger)visibilityDepthOfChildViewController:(UIViewController *)childViewController +{ + NSUInteger viewControllerIndex = [self.viewControllers indexOfObject:childViewController]; + NSAssert(viewControllerIndex != NSNotFound, @"childViewController is not in the navigation stack."); + + if (viewControllerIndex == self.viewControllers.count - 1) { + //view controller is at the top, just return our own visibility depth. + return [self visibilityDepth]; + } else if (viewControllerIndex == 0) { + //view controller is the root view controller. Can be accessed by holding the back button. + return [self visibilityDepth] + 1; + } + + return [self visibilityDepth] + self.viewControllers.count - 1 - viewControllerIndex; +} + +#pragma mark - UIKit overrides + +- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated +{ + NSArray *viewControllers = [super popToViewController:viewController animated:animated]; + [self visibilityDepthDidChange]; + return viewControllers; +} + +- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated +{ + NSArray *viewControllers = [super popToRootViewControllerAnimated:animated]; + [self visibilityDepthDidChange]; + return viewControllers; +} + +- (void)setViewControllers:(NSArray *)viewControllers +{ + [super setViewControllers:viewControllers]; + [self visibilityDepthDidChange]; +} + +- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated +{ + [super setViewControllers:viewControllers animated:animated]; + [self visibilityDepthDidChange]; +} + +- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated +{ + [super pushViewController:viewController animated:animated]; + [self visibilityDepthDidChange]; +} + +- (UIViewController *)popViewControllerAnimated:(BOOL)animated +{ + UIViewController *viewController = [super popViewControllerAnimated:animated]; + [self visibilityDepthDidChange]; + return viewController; +} + +@end diff --git a/AsyncDisplayKit/ASTabBarController.h b/AsyncDisplayKit/ASTabBarController.h new file mode 100644 index 00000000..6c633a8a --- /dev/null +++ b/AsyncDisplayKit/ASTabBarController.h @@ -0,0 +1,15 @@ +// +// ASTabBarController.h +// AsyncDisplayKit +// +// Created by Garrett Moon on 5/10/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import + +#import "ASVisibilityProtocols.h" + +@interface ASTabBarController : UITabBarController + +@end diff --git a/AsyncDisplayKit/ASTabBarController.m b/AsyncDisplayKit/ASTabBarController.m new file mode 100644 index 00000000..28150f09 --- /dev/null +++ b/AsyncDisplayKit/ASTabBarController.m @@ -0,0 +1,70 @@ +// +// ASTabBarController.m +// AsyncDisplayKit +// +// Created by Garrett Moon on 5/10/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "ASTabBarController.h" + +@implementation ASTabBarController +{ + BOOL _parentManagesVisibilityDepth; + NSInteger _visibilityDepth; +} + +ASVisibilityDidMoveToParentViewController; + +ASVisibilityViewWillAppear; + +ASVisibilityViewDidDisappearImplementation; + +ASVisibilitySetVisibilityDepth; + +ASVisibilityDepthImplementation; + +- (void)visibilityDepthDidChange +{ + for (UIViewController *viewController in self.viewControllers) { + if ([viewController conformsToProtocol:@protocol(ASVisibilityDepth)]) { + [(id )viewController visibilityDepthDidChange]; + } + } +} + +- (NSInteger)visibilityDepthOfChildViewController:(UIViewController *)childViewController +{ + if (self.selectedViewController == childViewController) { + return [self visibilityDepth]; + } + return [self visibilityDepth] + 1; +} + +#pragma mark - UIKit overrides + +- (void)setViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers +{ + [super setViewControllers:viewControllers]; + [self visibilityDepthDidChange]; +} + +- (void)setViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers animated:(BOOL)animated +{ + [super setViewControllers:viewControllers animated:animated]; + [self visibilityDepthDidChange]; +} + +- (void)setSelectedIndex:(NSUInteger)selectedIndex +{ + [super setSelectedIndex:selectedIndex]; + [self visibilityDepthDidChange]; +} + +- (void)setSelectedViewController:(__kindof UIViewController *)selectedViewController +{ + [super setSelectedViewController:selectedViewController]; + [self visibilityDepthDidChange]; +} + +@end diff --git a/AsyncDisplayKit/ASViewController.h b/AsyncDisplayKit/ASViewController.h index 4102ee80..71a7e4a7 100644 --- a/AsyncDisplayKit/ASViewController.h +++ b/AsyncDisplayKit/ASViewController.h @@ -8,6 +8,7 @@ #import #import +#import @class ASTraitCollection; @@ -16,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitCollectionBlock)(UITraitCollection *traitCollection); typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(CGSize windowSize); -@interface ASViewController<__covariant DisplayNodeType : ASDisplayNode *> : UIViewController +@interface ASViewController<__covariant DisplayNodeType : ASDisplayNode *> : UIViewController - (instancetype)initWithNode:(DisplayNodeType)node NS_DESIGNATED_INITIALIZER; diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index af76607c..7cb031a1 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -9,17 +9,18 @@ #import "ASViewController.h" #import "ASAssert.h" #import "ASDimension.h" -#import "ASDisplayNodeInternal.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+Beta.h" -#import "ASTraitCollection.h" -#import "ASEnvironmentInternal.h" #import "ASRangeControllerUpdateRangeProtocol+Beta.h" +#define AS_LOG_VISIBILITY_CHANGES 0 + @implementation ASViewController { BOOL _ensureDisplayed; BOOL _automaticallyAdjustRangeModeBasedOnViewEvents; + BOOL _parentManagesVisibilityDepth; + NSInteger _visibilityDepth; } - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil @@ -45,21 +46,10 @@ _node = node; _automaticallyAdjustRangeModeBasedOnViewEvents = NO; - + return self; } -- (void)dealloc -{ - if (_traitColectionContext != nil) { - // The setter will iterate through the VC's subnodes and replace the traitCollectionContext in their ASEnvironmentTraitCollection with nil. - // Since the VC holds the only strong reference to this context and we are in the process of destroying - // the VC, all the references in the subnodes will be unsafe unless we nil them out. More than likely all the subnodes will be dealloc'ed - // as part of the VC being dealloc'ed, but this is just to make extra sure. - self.traitColectionContext = nil; - } -} - - (void)loadView { ASDisplayNodeAssertTrue(!_node.layerBacked); @@ -95,21 +85,54 @@ [super viewDidLayoutSubviews]; } +ASVisibilityDidMoveToParentViewController; + - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; _ensureDisplayed = YES; [_node measureWithSizeRange:[self nodeConstrainedSize]]; [_node recursivelyFetchData]; - - [self updateCurrentRangeModeWithModeIfPossible:ASLayoutRangeModeFull]; + + if (_parentManagesVisibilityDepth == NO) { + [self setVisibilityDepth:0]; + } } -- (void)viewDidDisappear:(BOOL)animated +ASVisibilitySetVisibilityDepth; + +ASVisibilityViewDidDisappearImplementation; + +ASVisibilityDepthImplementation; + +- (void)visibilityDepthDidChange { - [super viewDidDisappear:animated]; - - [self updateCurrentRangeModeWithModeIfPossible:ASLayoutRangeModeMinimum]; + ASLayoutRangeMode rangeMode = ASLayoutRangeModeForVisibilityDepth(self.visibilityDepth); +#if AS_LOG_VISIBILITY_CHANGES + NSString *rangeModeString; + switch (rangeMode) { + case ASLayoutRangeModeMinimum: + rangeModeString = @"Minimum"; + break; + + case ASLayoutRangeModeFull: + rangeModeString = @"Full"; + break; + + case ASLayoutRangeModeVisibleOnly: + rangeModeString = @"Visible Only"; + break; + + case ASLayoutRangeModeLowMemory: + rangeModeString = @"Low Memory"; + break; + + default: + break; + } + NSLog(@"Updating visibility of:%@ to: %@ (visibility depth: %d)", self, rangeModeString, self.visibilityDepth); +#endif + [self updateCurrentRangeModeWithModeIfPossible:rangeMode]; } #pragma mark - Automatic range mode @@ -127,7 +150,9 @@ - (void)updateCurrentRangeModeWithModeIfPossible:(ASLayoutRangeMode)rangeMode { if (!_automaticallyAdjustRangeModeBasedOnViewEvents) { return; } - if (![_node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)]) { return; } + if (![_node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)]) { + return; + } id updateRangeNode = (id)_node; [updateRangeNode updateCurrentRangeWithMode:rangeMode]; @@ -146,80 +171,4 @@ return _node.interfaceState; } -#pragma mark - ASEnvironmentTraitCollection - -- (void)setTraitColectionContext:(id)traitColectionContext -{ - if (_traitColectionContext != traitColectionContext) { - // propagate first so that nodes aren't hanging around with a dealloc'ed pointer - ASEnvironmentTraitCollectionUpdateDisplayContext(self.node, traitColectionContext); - - _traitColectionContext = traitColectionContext; - } -} - -- (ASEnvironmentTraitCollection)displayTraitsForTraitCollection:(UITraitCollection *)traitCollection -{ - if (self.overrideDisplayTraitsWithTraitCollection) { - ASTraitCollection *asyncTraitCollection = self.overrideDisplayTraitsWithTraitCollection(traitCollection); - self.traitColectionContext = asyncTraitCollection.traitCollectionContext; - return [asyncTraitCollection environmentTraitCollection]; - } - - ASEnvironmentTraitCollection asyncTraitCollection = ASEnvironmentTraitCollectionFromUITraitCollection(traitCollection); - asyncTraitCollection.displayContext = self.traitColectionContext; - return asyncTraitCollection; -} - -- (ASEnvironmentTraitCollection)displayTraitsForWindowSize:(CGSize)windowSize -{ - if (self.overrideDisplayTraitsWithWindowSize) { - ASTraitCollection *traitCollection = self.overrideDisplayTraitsWithWindowSize(windowSize); - self.traitColectionContext = traitCollection.traitCollectionContext; - return [traitCollection environmentTraitCollection]; - } - return self.node.environmentTraitCollection; -} - -- (void)progagateNewDisplayTraits:(ASEnvironmentTraitCollection)traitCollection -{ - ASEnvironmentState environmentState = self.node.environmentState; - ASEnvironmentTraitCollection oldTraitCollection = environmentState.traitCollection; - - if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(traitCollection, oldTraitCollection) == NO) { - environmentState.traitCollection = traitCollection; - self.node.environmentState = environmentState; - [self.node setNeedsLayout]; - - NSArray> *children = [self.node children]; - for (id child in children) { - ASEnvironmentStatePropagateDown(child, environmentState.traitCollection); - } - } -} - -- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection -{ - [super traitCollectionDidChange:previousTraitCollection]; - - ASEnvironmentTraitCollection traitCollection = [self displayTraitsForTraitCollection:self.traitCollection]; - [self progagateNewDisplayTraits:traitCollection]; -} - -- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id)coordinator -{ - [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; - - ASEnvironmentTraitCollection traitCollection = [self displayTraitsForTraitCollection:newCollection]; - [self progagateNewDisplayTraits:traitCollection]; -} - -- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator -{ - [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; - - ASEnvironmentTraitCollection traitCollection = [self displayTraitsForWindowSize:size]; - [self progagateNewDisplayTraits:traitCollection]; -} - @end diff --git a/AsyncDisplayKit/ASVisibilityProtocols.h b/AsyncDisplayKit/ASVisibilityProtocols.h new file mode 100644 index 00000000..c077d8ff --- /dev/null +++ b/AsyncDisplayKit/ASVisibilityProtocols.h @@ -0,0 +1,103 @@ +// +// ASVisibilityProtocols.h +// Pods +// +// Created by Garrett Moon on 4/27/16. +// +// + +#import "ASLayoutRangeType.h" + +#import "ASBaseDefines.h" + +@class UIViewController; + +ASDISPLAYNODE_EXTERN_C_BEGIN + +extern ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth); + +ASDISPLAYNODE_EXTERN_C_END + +@protocol ASVisibilityDepth + +/** + * @abstract Represents the number of user actions necessary to reach the view controller. An increased visibility + * depth indicates a higher number of user interactions for the view controller to be visible again. For example, + * an onscreen navigation controller's top view controller should have a visibility depth of 0. The view controller + * one from the top should have a visibility deptch of 1 as should the root view controller in the stack (because + * the user can hold the back button to pop to the root view controller). + * + * Visibility depth is used to automatically adjust ranges on range controllers (and thus free up memory) and can + * be used to reduce memory usage of other items as well. + */ +- (NSInteger)visibilityDepth; + + +- (void)visibilityDepthDidChange; + +@end + +/** + * @abstract Container view controllers should adopt this protocol to indicate that they will manage their child's + * visibilityDepth. For example, ASNavigationController adopts this protocol and manages its childrens visibility + * depth. + * + * If you adopt this protocol, you *must* also emit visibilityDepthDidChange messages to child view controllers. + * + * @param childViewController Expected to return the visibility depth of the child view controller. + */ +@protocol ASManagesChildVisibilityDepth + +- (NSInteger)visibilityDepthOfChildViewController:(UIViewController *)childViewController; + +@end + +#define ASVisibilitySetVisibilityDepth \ +- (void)setVisibilityDepth:(NSUInteger)visibilityDepth \ +{ \ + if (_visibilityDepth == visibilityDepth) { \ + return; \ + } \ + _visibilityDepth = visibilityDepth; \ + [self visibilityDepthDidChange]; \ +} + +#define ASVisibilityDepthImplementation \ +- (NSInteger)visibilityDepth \ +{ \ + if (self.parentViewController && _parentManagesVisibilityDepth == NO) { \ + _parentManagesVisibilityDepth = [self.parentViewController conformsToProtocol:@protocol(ASManagesChildVisibilityDepth)]; \ + } \ + \ + if (_parentManagesVisibilityDepth) { \ + return [(id )self.parentViewController visibilityDepthOfChildViewController:self]; \ + } \ + return _visibilityDepth; \ +} + +#define ASVisibilityViewDidDisappearImplementation \ +- (void)viewDidDisappear:(BOOL)animated \ +{ \ + [super viewDidDisappear:animated]; \ + \ + if (_parentManagesVisibilityDepth == NO) { \ + [self setVisibilityDepth:1]; \ + } \ +} + +#define ASVisibilityViewWillAppear \ +- (void)viewWillAppear:(BOOL)animated \ +{ \ + [super viewWillAppear:animated]; \ + \ + if (_parentManagesVisibilityDepth == NO) { \ + [self setVisibilityDepth:0]; \ + } \ +} + +#define ASVisibilityDidMoveToParentViewController \ +- (void)didMoveToParentViewController:(UIViewController *)parent \ +{ \ + [super didMoveToParentViewController:parent]; \ + [self visibilityDepthDidChange]; \ +} diff --git a/AsyncDisplayKit/ASVisibilityProtocols.m b/AsyncDisplayKit/ASVisibilityProtocols.m new file mode 100644 index 00000000..a739fd01 --- /dev/null +++ b/AsyncDisplayKit/ASVisibilityProtocols.m @@ -0,0 +1,23 @@ +// +// ASVisibilityProtocols.m +// Pods +// +// Created by Garrett Moon on 4/28/16. +// +// + +#import + +#import "ASVisibilityProtocols.h" + +ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth) +{ + if (visibilityDepth == 0) { + return ASLayoutRangeModeFull; + } else if (visibilityDepth == 1) { + return ASLayoutRangeModeMinimum; + } else if (visibilityDepth == 2) { + return ASLayoutRangeModeVisibleOnly; + } + return ASLayoutRangeModeLowMemory; +} \ No newline at end of file diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index 42a3baa5..7de390bb 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -34,6 +34,8 @@ #import #import +#import +#import #import #import @@ -78,6 +80,7 @@ #import #import #import +#import #import