mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-02-09 09:12:06 +08:00
Ported TabBarIOS to OSS and unified implementation
This commit is contained in:
@@ -3,9 +3,9 @@
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "Layout.h"
|
||||
#import "RCTPointerEvents.h"
|
||||
#import "RCTAnimationType.h"
|
||||
#import "../Layout/Layout.h"
|
||||
#import "../Views/RCTAnimationType.h"
|
||||
#import "../Views/RCTPointerEvents.h"
|
||||
|
||||
/**
|
||||
* This class provides a collection of conversion functions for mapping
|
||||
@@ -47,7 +47,6 @@
|
||||
+ (UIColor *)UIColor:(id)json;
|
||||
+ (CGColorRef)CGColor:(id)json;
|
||||
|
||||
+ (CAKeyframeAnimation *)GIF:(id)json;
|
||||
+ (UIImage *)UIImage:(id)json;
|
||||
+ (CGImageRef)CGImage:(id)json;
|
||||
|
||||
@@ -68,6 +67,10 @@
|
||||
|
||||
@end
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will attempt to set a property using a json value by first
|
||||
* inferring the correct type from all available information, and then
|
||||
@@ -82,3 +85,7 @@ BOOL RCTSetProperty(id target, NSString *keypath, id json);
|
||||
* be set, it will do nothing and return NO.
|
||||
*/
|
||||
BOOL RCTCopyProperty(id target, id source, NSString *keypath);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
|
||||
#import <objc/message.h>
|
||||
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
|
||||
#import "RCTLog.h"
|
||||
|
||||
CGFloat const RCTDefaultFontSize = 14;
|
||||
@@ -431,88 +428,11 @@ RCT_STRUCT_CONVERTER(CGAffineTransform, (@[@"a", @"b", @"c", @"d", @"tx", @"ty"]
|
||||
return [self UIColor:json].CGColor;
|
||||
}
|
||||
|
||||
+ (CAKeyframeAnimation *)GIF:(id)json
|
||||
{
|
||||
CGImageSourceRef imageSource = NULL;
|
||||
if ([json isKindOfClass:[NSString class]]) {
|
||||
NSString *path = json;
|
||||
if (path.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSURL *fileURL = [path isAbsolutePath] ? [NSURL fileURLWithPath:path] : [[NSBundle mainBundle] URLForResource:path withExtension:nil];
|
||||
imageSource = CGImageSourceCreateWithURL((CFURLRef)fileURL, NULL);
|
||||
} else if ([json isKindOfClass:[NSData class]]) {
|
||||
NSData *data = json;
|
||||
if (data.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
imageSource = CGImageSourceCreateWithData((CFDataRef)data, NULL);
|
||||
} else {
|
||||
RCTLogMustFix(@"Expected NSString or NSData for GIF, received %@: %@", [json class], json);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!UTTypeConformsTo(CGImageSourceGetType(imageSource), kUTTypeGIF)) {
|
||||
CFRelease(imageSource);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(imageSource, NULL);
|
||||
NSUInteger loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
|
||||
|
||||
size_t imageCount = CGImageSourceGetCount(imageSource);
|
||||
NSTimeInterval duration = 0;
|
||||
NSMutableArray *delays = [NSMutableArray arrayWithCapacity:imageCount];
|
||||
NSMutableArray *images = [NSMutableArray arrayWithCapacity:imageCount];
|
||||
for (size_t i = 0; i < imageCount; i++) {
|
||||
CGImageRef image = CGImageSourceCreateImageAtIndex(imageSource, i, NULL);
|
||||
NSDictionary *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource, i, NULL);
|
||||
NSDictionary *frameGIFProperties = frameProperties[(id)kCGImagePropertyGIFDictionary];
|
||||
|
||||
const NSTimeInterval kDelayTimeIntervalDefault = 0.1;
|
||||
NSNumber *delayTime = frameGIFProperties[(id)kCGImagePropertyGIFUnclampedDelayTime] ?: frameGIFProperties[(id)kCGImagePropertyGIFDelayTime];
|
||||
if (delayTime == nil) {
|
||||
if (i == 0) {
|
||||
delayTime = @(kDelayTimeIntervalDefault);
|
||||
} else {
|
||||
delayTime = delays[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
const NSTimeInterval kDelayTimeIntervalMinimum = 0.02;
|
||||
if (delayTime.floatValue < (float)kDelayTimeIntervalMinimum - FLT_EPSILON) {
|
||||
delayTime = @(kDelayTimeIntervalDefault);
|
||||
}
|
||||
|
||||
duration += delayTime.doubleValue;
|
||||
delays[i] = delayTime;
|
||||
images[i] = (__bridge_transfer id)image;
|
||||
}
|
||||
|
||||
CFRelease(imageSource);
|
||||
|
||||
NSMutableArray *keyTimes = [NSMutableArray arrayWithCapacity:delays.count];
|
||||
NSTimeInterval runningDuration = 0;
|
||||
for (NSNumber *delayNumber in delays) {
|
||||
[keyTimes addObject:@(runningDuration / duration)];
|
||||
runningDuration += delayNumber.doubleValue;
|
||||
}
|
||||
|
||||
[keyTimes addObject:@1.0];
|
||||
|
||||
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
|
||||
animation.calculationMode = kCAAnimationDiscrete;
|
||||
animation.repeatCount = loopCount == 0 ? HUGE_VALF : loopCount;
|
||||
animation.keyTimes = keyTimes;
|
||||
animation.values = images;
|
||||
animation.duration = duration;
|
||||
return animation;
|
||||
}
|
||||
|
||||
+ (UIImage *)UIImage:(id)json
|
||||
{
|
||||
// TODO: we might as well cache the result of these checks (and possibly the
|
||||
// image itself) so as to reduce overhead on subsequent checks of the same input
|
||||
|
||||
if (![json isKindOfClass:[NSString class]]) {
|
||||
RCTLogError(@"Expected NSString for UIImage, received %@: %@", [json class], json);
|
||||
return nil;
|
||||
@@ -532,9 +452,8 @@ RCT_STRUCT_CONVERTER(CGAffineTransform, (@[@"a", @"b", @"c", @"d", @"tx", @"ty"]
|
||||
image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:path ofType:nil]];
|
||||
}
|
||||
}
|
||||
if (!image) {
|
||||
RCTLogWarn(@"No image was found at path %@", json);
|
||||
}
|
||||
// NOTE: we don't warn about nil images because there are legitimate
|
||||
// case where we find out if a string is an image by using this method
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
@@ -1109,8 +1109,8 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView
|
||||
// Bubble dispatched events
|
||||
@"topTap": @{
|
||||
@"phasedRegistrationNames": @{
|
||||
@"bubbled": @"notActuallyTapDontUseMe",
|
||||
@"captured": @"notActuallyTapCaptureDontUseMe"
|
||||
@"bubbled": @"onPress",
|
||||
@"captured": @"onPressCapture"
|
||||
}
|
||||
},
|
||||
@"topVisibleCellsChange": @{
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1302F0FD1A78550100EBEF02 /* RCTStaticImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1302F0FA1A78550100EBEF02 /* RCTStaticImage.m */; };
|
||||
1302F0FE1A78550100EBEF02 /* RCTStaticImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1302F0FC1A78550100EBEF02 /* RCTStaticImageManager.m */; };
|
||||
134FCB361A6D42D900051CC8 /* RCTSparseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */; };
|
||||
134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */; };
|
||||
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */; };
|
||||
13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */; };
|
||||
137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E01AA5CF210034F82E /* RCTTabBar.m */; };
|
||||
137327E81AA5CF210034F82E /* RCTTabBarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E21AA5CF210034F82E /* RCTTabBarItem.m */; };
|
||||
137327E91AA5CF210034F82E /* RCTTabBarItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */; };
|
||||
137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E61AA5CF210034F82E /* RCTTabBarManager.m */; };
|
||||
13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; };
|
||||
13B07FEF1A69327A00A75B9A /* RCTAlertManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FE81A69327A00A75B9A /* RCTAlertManager.m */; };
|
||||
13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FEA1A69327A00A75B9A /* RCTExceptionsManager.m */; };
|
||||
@@ -60,21 +62,27 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1302F0F91A78550100EBEF02 /* RCTStaticImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStaticImage.h; sourceTree = "<group>"; };
|
||||
1302F0FA1A78550100EBEF02 /* RCTStaticImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStaticImage.m; sourceTree = "<group>"; };
|
||||
1302F0FB1A78550100EBEF02 /* RCTStaticImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStaticImageManager.h; sourceTree = "<group>"; };
|
||||
1302F0FC1A78550100EBEF02 /* RCTStaticImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStaticImageManager.m; sourceTree = "<group>"; };
|
||||
13442BF21AA90E0B0037E5B0 /* RCTAnimationType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationType.h; sourceTree = "<group>"; };
|
||||
13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPointerEvents.h; sourceTree = "<group>"; };
|
||||
13442BF41AA90E0B0037E5B0 /* RCTViewControllerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTViewControllerProtocol.h; sourceTree = "<group>"; };
|
||||
134FCB391A6E7F0800051CC8 /* RCTContextExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTContextExecutor.h; sourceTree = "<group>"; };
|
||||
134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTContextExecutor.m; sourceTree = "<group>"; };
|
||||
134FCB3B1A6E7F0800051CC8 /* RCTWebViewExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewExecutor.h; sourceTree = "<group>"; };
|
||||
134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebViewExecutor.m; sourceTree = "<group>"; };
|
||||
13723B4E1A82FD3C00F88898 /* RCTStatusBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStatusBarManager.h; sourceTree = "<group>"; };
|
||||
13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStatusBarManager.m; sourceTree = "<group>"; };
|
||||
137327DF1AA5CF210034F82E /* RCTTabBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBar.h; sourceTree = "<group>"; };
|
||||
137327E01AA5CF210034F82E /* RCTTabBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBar.m; sourceTree = "<group>"; };
|
||||
137327E11AA5CF210034F82E /* RCTTabBarItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBarItem.h; sourceTree = "<group>"; };
|
||||
137327E21AA5CF210034F82E /* RCTTabBarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarItem.m; sourceTree = "<group>"; };
|
||||
137327E31AA5CF210034F82E /* RCTTabBarItemManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBarItemManager.h; sourceTree = "<group>"; };
|
||||
137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarItemManager.m; sourceTree = "<group>"; };
|
||||
137327E51AA5CF210034F82E /* RCTTabBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBarManager.h; sourceTree = "<group>"; };
|
||||
137327E61AA5CF210034F82E /* RCTTabBarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarManager.m; sourceTree = "<group>"; };
|
||||
13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyCommands.h; sourceTree = "<group>"; };
|
||||
13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTKeyCommands.m; sourceTree = "<group>"; };
|
||||
13B07FC71A68125100A75B9A /* Layout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Layout.c; sourceTree = "<group>"; };
|
||||
13B07FC81A68125100A75B9A /* Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Layout.h; sourceTree = "<group>"; };
|
||||
13B07FCD1A683B5F00A75B9A /* RCTScrollableProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTScrollableProtocol.h; sourceTree = "<group>"; };
|
||||
13B07FE71A69327A00A75B9A /* RCTAlertManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAlertManager.h; sourceTree = "<group>"; };
|
||||
13B07FE81A69327A00A75B9A /* RCTAlertManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAlertManager.m; sourceTree = "<group>"; };
|
||||
13B07FE91A69327A00A75B9A /* RCTExceptionsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTExceptionsManager.h; sourceTree = "<group>"; };
|
||||
@@ -101,7 +109,9 @@
|
||||
13B080191A69489C00A75B9A /* RCTUIActivityIndicatorViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIActivityIndicatorViewManager.m; sourceTree = "<group>"; };
|
||||
13B080231A694A8400A75B9A /* RCTWrapperViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWrapperViewController.h; sourceTree = "<group>"; };
|
||||
13B080241A694A8400A75B9A /* RCTWrapperViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWrapperViewController.m; sourceTree = "<group>"; };
|
||||
13DB9D681A8CC58200429C20 /* RCTAnimationType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationType.h; sourceTree = "<group>"; };
|
||||
13C325261AA63B6A0048765F /* RCTAutoInsetsProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAutoInsetsProtocol.h; sourceTree = "<group>"; };
|
||||
13C325271AA63B6A0048765F /* RCTScrollableProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTScrollableProtocol.h; sourceTree = "<group>"; };
|
||||
13C325281AA63B6A0048765F /* RCTViewNodeProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTViewNodeProtocol.h; sourceTree = "<group>"; };
|
||||
13E067481A70F434002CDEE1 /* RCTUIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUIManager.h; sourceTree = "<group>"; };
|
||||
13E067491A70F434002CDEE1 /* RCTUIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIManager.m; sourceTree = "<group>"; };
|
||||
13E0674B1A70F44B002CDEE1 /* RCTShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTShadowView.h; sourceTree = "<group>"; };
|
||||
@@ -112,7 +122,6 @@
|
||||
13E067501A70F44B002CDEE1 /* RCTView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTView.m; sourceTree = "<group>"; };
|
||||
13E067531A70F44B002CDEE1 /* UIView+ReactKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+ReactKit.h"; sourceTree = "<group>"; };
|
||||
13E067541A70F44B002CDEE1 /* UIView+ReactKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+ReactKit.m"; sourceTree = "<group>"; };
|
||||
13ED13891A80C9D40050A8F9 /* RCTPointerEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPointerEvents.h; sourceTree = "<group>"; };
|
||||
13EFFCCF1A98E6FE002607DC /* RCTJSMethodRegistrar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSMethodRegistrar.h; sourceTree = "<group>"; };
|
||||
5F5F0D971A9E456B001279FA /* RCTLocationObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTLocationObserver.h; sourceTree = "<group>"; };
|
||||
5F5F0D981A9E456B001279FA /* RCTLocationObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTLocationObserver.m; sourceTree = "<group>"; };
|
||||
@@ -135,8 +144,6 @@
|
||||
83CBBA591A601E9000E9B192 /* RCTRedBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRedBox.m; sourceTree = "<group>"; };
|
||||
83CBBA5E1A601EAA00E9B192 /* RCTBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBridge.h; sourceTree = "<group>"; };
|
||||
83CBBA5F1A601EAA00E9B192 /* RCTBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBridge.m; sourceTree = "<group>"; };
|
||||
83CBBA611A601EB200E9B192 /* RCTAutoInsetsProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTAutoInsetsProtocol.h; sourceTree = "<group>"; };
|
||||
83CBBA621A601EB800E9B192 /* RCTViewNodeProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTViewNodeProtocol.h; sourceTree = "<group>"; };
|
||||
83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptExecutor.h; sourceTree = "<group>"; };
|
||||
83CBBA651A601EF300E9B192 /* RCTEventDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTEventDispatcher.h; sourceTree = "<group>"; };
|
||||
83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventDispatcher.m; sourceTree = "<group>"; };
|
||||
@@ -199,6 +206,12 @@
|
||||
13B07FF31A6947C200A75B9A /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13442BF21AA90E0B0037E5B0 /* RCTAnimationType.h */,
|
||||
13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */,
|
||||
13442BF41AA90E0B0037E5B0 /* RCTViewControllerProtocol.h */,
|
||||
13C325261AA63B6A0048765F /* RCTAutoInsetsProtocol.h */,
|
||||
13C325271AA63B6A0048765F /* RCTScrollableProtocol.h */,
|
||||
13C325281AA63B6A0048765F /* RCTViewNodeProtocol.h */,
|
||||
13B0800C1A69489C00A75B9A /* RCTNavigator.h */,
|
||||
13B0800D1A69489C00A75B9A /* RCTNavigator.m */,
|
||||
13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */,
|
||||
@@ -213,10 +226,6 @@
|
||||
13B07FF91A6947C200A75B9A /* RCTScrollViewManager.m */,
|
||||
13E0674B1A70F44B002CDEE1 /* RCTShadowView.h */,
|
||||
13E0674C1A70F44B002CDEE1 /* RCTShadowView.m */,
|
||||
1302F0F91A78550100EBEF02 /* RCTStaticImage.h */,
|
||||
1302F0FA1A78550100EBEF02 /* RCTStaticImage.m */,
|
||||
1302F0FB1A78550100EBEF02 /* RCTStaticImageManager.h */,
|
||||
1302F0FC1A78550100EBEF02 /* RCTStaticImageManager.m */,
|
||||
13B080141A69489C00A75B9A /* RCTTextField.h */,
|
||||
13B080151A69489C00A75B9A /* RCTTextField.m */,
|
||||
13B080161A69489C00A75B9A /* RCTTextFieldManager.h */,
|
||||
@@ -229,6 +238,14 @@
|
||||
13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */,
|
||||
13B080231A694A8400A75B9A /* RCTWrapperViewController.h */,
|
||||
13B080241A694A8400A75B9A /* RCTWrapperViewController.m */,
|
||||
137327DF1AA5CF210034F82E /* RCTTabBar.h */,
|
||||
137327E01AA5CF210034F82E /* RCTTabBar.m */,
|
||||
137327E11AA5CF210034F82E /* RCTTabBarItem.h */,
|
||||
137327E21AA5CF210034F82E /* RCTTabBarItem.m */,
|
||||
137327E31AA5CF210034F82E /* RCTTabBarItemManager.h */,
|
||||
137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */,
|
||||
137327E51AA5CF210034F82E /* RCTTabBarManager.h */,
|
||||
137327E61AA5CF210034F82E /* RCTTabBarManager.m */,
|
||||
13E067531A70F44B002CDEE1 /* UIView+ReactKit.h */,
|
||||
13E067541A70F44B002CDEE1 /* UIView+ReactKit.m */,
|
||||
);
|
||||
@@ -266,10 +283,8 @@
|
||||
83CBBA491A601E3B00E9B192 /* Base */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13DB9D681A8CC58200429C20 /* RCTAnimationType.h */,
|
||||
83CBBA4A1A601E3B00E9B192 /* RCTAssert.h */,
|
||||
83CBBA4B1A601E3B00E9B192 /* RCTAssert.m */,
|
||||
83CBBA611A601EB200E9B192 /* RCTAutoInsetsProtocol.h */,
|
||||
83CBBA5E1A601EAA00E9B192 /* RCTBridge.h */,
|
||||
83CBBA5F1A601EAA00E9B192 /* RCTBridge.m */,
|
||||
830213F31A654E0800B993E6 /* RCTBridgeModule.h */,
|
||||
@@ -286,19 +301,16 @@
|
||||
13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */,
|
||||
83CBBA4D1A601E3B00E9B192 /* RCTLog.h */,
|
||||
83CBBA4E1A601E3B00E9B192 /* RCTLog.m */,
|
||||
13ED13891A80C9D40050A8F9 /* RCTPointerEvents.h */,
|
||||
83CBBA581A601E9000E9B192 /* RCTRedBox.h */,
|
||||
83CBBA591A601E9000E9B192 /* RCTRedBox.m */,
|
||||
830A229C1A66C68A008503DA /* RCTRootView.h */,
|
||||
830A229D1A66C68A008503DA /* RCTRootView.m */,
|
||||
13B07FCD1A683B5F00A75B9A /* RCTScrollableProtocol.h */,
|
||||
83BEE46C1A6D19BC00B5863B /* RCTSparseArray.h */,
|
||||
83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */,
|
||||
83CBBA961A6020BB00E9B192 /* RCTTouchHandler.h */,
|
||||
83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */,
|
||||
83CBBA4F1A601E3B00E9B192 /* RCTUtils.h */,
|
||||
83CBBA501A601E3B00E9B192 /* RCTUtils.m */,
|
||||
83CBBA621A601EB800E9B192 /* RCTViewNodeProtocol.h */,
|
||||
);
|
||||
path = Base;
|
||||
sourceTree = "<group>";
|
||||
@@ -383,7 +395,6 @@
|
||||
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */,
|
||||
5F5F0D991A9E456B001279FA /* RCTLocationObserver.m in Sources */,
|
||||
830A229E1A66C68A008503DA /* RCTRootView.m in Sources */,
|
||||
1302F0FD1A78550100EBEF02 /* RCTStaticImage.m in Sources */,
|
||||
13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */,
|
||||
83CBBA5A1A601E9000E9B192 /* RCTRedBox.m in Sources */,
|
||||
83CBBA511A601E3B00E9B192 /* RCTAssert.m in Sources */,
|
||||
@@ -391,6 +402,7 @@
|
||||
13B080201A69489C00A75B9A /* RCTUIActivityIndicatorViewManager.m in Sources */,
|
||||
13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */,
|
||||
13B080061A6947C200A75B9A /* RCTScrollViewManager.m in Sources */,
|
||||
137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */,
|
||||
13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */,
|
||||
13B080051A6947C200A75B9A /* RCTScrollView.m in Sources */,
|
||||
13B07FF21A69327A00A75B9A /* RCTTiming.m in Sources */,
|
||||
@@ -401,18 +413,20 @@
|
||||
83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */,
|
||||
13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */,
|
||||
13E067571A70F44B002CDEE1 /* RCTView.m in Sources */,
|
||||
137327E91AA5CF210034F82E /* RCTTabBarItemManager.m in Sources */,
|
||||
134FCB361A6D42D900051CC8 /* RCTSparseArray.m in Sources */,
|
||||
13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */,
|
||||
83CBBA531A601E3B00E9B192 /* RCTUtils.m in Sources */,
|
||||
83CBBA601A601EAA00E9B192 /* RCTBridge.m in Sources */,
|
||||
137327E81AA5CF210034F82E /* RCTTabBarItem.m in Sources */,
|
||||
13E067551A70F44B002CDEE1 /* RCTShadowView.m in Sources */,
|
||||
13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */,
|
||||
830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */,
|
||||
137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */,
|
||||
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */,
|
||||
13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
|
||||
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */,
|
||||
13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */,
|
||||
1302F0FE1A78550100EBEF02 /* RCTStaticImageManager.m in Sources */,
|
||||
13B0801B1A69489C00A75B9A /* RCTNavigatorManager.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
@@ -41,7 +41,6 @@ NSInteger kNeverProgressed = -10000;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
* In general, `RCTNavigator` examines `_currentViews` (which are React child
|
||||
* views), and compares them to `_navigationController.viewControllers` (which
|
||||
@@ -138,7 +137,6 @@ NSInteger kNeverProgressed = -10000;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoked when either a navigation item has been popped off, or when a
|
||||
* swipe-back gesture has began. The swipe-back gesture doesn't respect the
|
||||
@@ -184,7 +182,6 @@ NSInteger kNeverProgressed = -10000;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface RCTNavigator() <RCTWrapperViewControllerNavigationListener, UINavigationControllerDelegate>
|
||||
{
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
@@ -204,7 +201,7 @@ NSInteger kNeverProgressed = -10000;
|
||||
*
|
||||
* - The run loop retains the displayLink.
|
||||
* - `displayLink` retains its target.
|
||||
* - We use `reactWillDestroy` to remove the `RCTNavigator`'s reference to the
|
||||
* - We use `invalidate` to remove the `RCTNavigator`'s reference to the
|
||||
* `displayLink` and remove the `displayLink` from the run loop.
|
||||
*
|
||||
*
|
||||
@@ -212,7 +209,7 @@ NSInteger kNeverProgressed = -10000;
|
||||
* --------------
|
||||
*
|
||||
* - Even though we could implement the `displayLink` cleanup without the
|
||||
* `reactWillDestroy` hook by adding and removing it from the run loop at the
|
||||
* `invalidate` hook by adding and removing it from the run loop at the
|
||||
* right times (begin/end animation), we need to account for the possibility
|
||||
* that the view itself is destroyed mid-interaction. So we always keep it
|
||||
* added to the run loop, but start/stop it with interactions/animations. We
|
||||
@@ -343,7 +340,7 @@ NSInteger kNeverProgressed = -10000;
|
||||
NSUInteger indexOfFrom = [_currentViews indexOfObject:fromController.navItem];
|
||||
NSUInteger indexOfTo = [_currentViews indexOfObject:toController.navItem];
|
||||
CGFloat destination = indexOfFrom < indexOfTo ? 1.0 : -1.0;
|
||||
_dummyView.frame = (CGRect){destination};
|
||||
_dummyView.frame = (CGRect){{destination}};
|
||||
_currentlyTransitioningFrom = indexOfFrom;
|
||||
_currentlyTransitioningTo = indexOfTo;
|
||||
if (indexOfFrom != indexOfTo) {
|
||||
@@ -450,24 +447,10 @@ NSInteger kNeverProgressed = -10000;
|
||||
return self.superview ? self.superview : self.reactNavSuperviewLink;
|
||||
}
|
||||
|
||||
- (void)addControllerToClosestParent:(UIViewController *)controller
|
||||
{
|
||||
if (!controller.parentViewController) {
|
||||
id responder = [self.superview nextResponder];
|
||||
while (responder && ![responder isKindOfClass:[UIViewController class]]) {
|
||||
responder = [responder nextResponder];
|
||||
}
|
||||
if (responder) {
|
||||
[responder addChildViewController:controller];
|
||||
[controller didMoveToParentViewController:responder];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reactBridgeDidFinishTransaction
|
||||
{
|
||||
// we can't hook up the VC hierarchy in 'init' because the subviews aren't hooked up yet,
|
||||
// so we do it on demand here
|
||||
// we can't hook up the VC hierarchy in 'init' because the subviews aren't
|
||||
// hooked up yet, so we do it on demand here
|
||||
[self addControllerToClosestParent:_navigationController];
|
||||
|
||||
NSInteger viewControllerCount = _navigationController.viewControllers.count;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#import "RCTNavigatorManager.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTNavigator.h"
|
||||
#import "RCTShadowView.h"
|
||||
#import "RCTSparseArray.h"
|
||||
#import "RCTUIManager.h"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTNavigator alloc] initWithEventDispatcher:self.eventDispatcher];
|
||||
return [[RCTNavigator alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(requestedTopOfStack)
|
||||
@@ -34,16 +34,12 @@ RCT_EXPORT_VIEW_PROPERTY(requestedTopOfStack)
|
||||
RCT_EXPORT();
|
||||
|
||||
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
||||
if (reactTag) {
|
||||
RCTNavigator *navigator = viewRegistry[reactTag];
|
||||
if ([navigator isKindOfClass:[RCTNavigator class]]) {
|
||||
BOOL wasAcquired = [navigator requestSchedulingJavaScriptNavigation];
|
||||
callback(@[@(wasAcquired)]);
|
||||
} else {
|
||||
RCTLogError(@"Cannot set lock: %@ (tag #%@) is not an RCTNavigator", navigator, reactTag);
|
||||
}
|
||||
RCTNavigator *navigator = viewRegistry[reactTag];
|
||||
if ([navigator isKindOfClass:[RCTNavigator class]]) {
|
||||
BOOL wasAcquired = [navigator requestSchedulingJavaScriptNavigation];
|
||||
callback(@[@(wasAcquired)]);
|
||||
} else {
|
||||
RCTLogError(@"Tag not specified for requestSchedulingJavaScriptNavigation");
|
||||
RCTLogError(@"Cannot set lock: %@ (tag #%@) is not an RCTNavigator", navigator, reactTag);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#import "RCTScrollViewManager.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTScrollView.h"
|
||||
|
||||
@@ -9,7 +10,7 @@
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTScrollView alloc] initWithEventDispatcher:self.eventDispatcher];
|
||||
return [[RCTScrollView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(alwaysBounceHorizontal)
|
||||
|
||||
@@ -325,6 +325,11 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
|
||||
return _reactSubviews;
|
||||
}
|
||||
|
||||
- (RCTShadowView *)reactSuperview
|
||||
{
|
||||
return _superview;
|
||||
}
|
||||
|
||||
- (NSNumber *)reactTagAtPoint:(CGPoint)point
|
||||
{
|
||||
for (RCTShadowView *shadowView in _reactSubviews) {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface RCTStaticImage : UIImageView
|
||||
|
||||
@property (nonatomic, assign) UIEdgeInsets capInsets;
|
||||
@property (nonatomic, assign) UIImageRenderingMode renderingMode;
|
||||
|
||||
@end
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTStaticImage.h"
|
||||
|
||||
@implementation RCTStaticImage
|
||||
|
||||
- (void)_updateImage
|
||||
{
|
||||
UIImage *image = self.image;
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply rendering mode
|
||||
if (_renderingMode != image.renderingMode) {
|
||||
image = [image imageWithRenderingMode:_renderingMode];
|
||||
}
|
||||
|
||||
// Applying capInsets of 0 will switch the "resizingMode" of the image to "tile" which is undesired
|
||||
if (!UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, _capInsets)) {
|
||||
image = [image resizableImageWithCapInsets:_capInsets resizingMode:UIImageResizingModeStretch];
|
||||
}
|
||||
|
||||
// Apply trilinear filtering to smooth out mis-sized images
|
||||
self.layer.minificationFilter = kCAFilterTrilinear;
|
||||
self.layer.magnificationFilter = kCAFilterTrilinear;
|
||||
|
||||
super.image = image;
|
||||
}
|
||||
|
||||
- (void)setImage:(UIImage *)image
|
||||
{
|
||||
if (image != super.image) {
|
||||
super.image = image;
|
||||
[self _updateImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCapInsets:(UIEdgeInsets)capInsets
|
||||
{
|
||||
if (!UIEdgeInsetsEqualToEdgeInsets(_capInsets, capInsets)) {
|
||||
_capInsets = capInsets;
|
||||
[self _updateImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setRenderingMode:(UIImageRenderingMode)renderingMode
|
||||
{
|
||||
if (_renderingMode != renderingMode) {
|
||||
_renderingMode = renderingMode;
|
||||
[self _updateImage];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTStaticImageManager.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTStaticImage.h"
|
||||
#import "RCTConvert.h"
|
||||
|
||||
@implementation RCTStaticImageManager
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTStaticImage alloc] init];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(capInsets)
|
||||
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode)
|
||||
RCT_CUSTOM_VIEW_PROPERTY(src, RCTStaticImage *)
|
||||
{
|
||||
if (json) {
|
||||
if ([[[json description] pathExtension] caseInsensitiveCompare:@"gif"] == NSOrderedSame) {
|
||||
[view.layer addAnimation:[RCTConvert GIF:json] forKey:@"contents"];
|
||||
} else {
|
||||
view.image = [RCTConvert UIImage:json];
|
||||
}
|
||||
} else {
|
||||
view.image = defaultView.image;
|
||||
}
|
||||
}
|
||||
RCT_CUSTOM_VIEW_PROPERTY(tintColor, RCTStaticImage *)
|
||||
{
|
||||
if (json) {
|
||||
view.renderingMode = UIImageRenderingModeAlwaysTemplate;
|
||||
view.tintColor = [RCTConvert UIColor:json];
|
||||
} else {
|
||||
view.renderingMode = defaultView.renderingMode;
|
||||
view.tintColor = defaultView.tintColor;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
11
ReactKit/Views/RCTTabBar.h
Normal file
11
ReactKit/Views/RCTTabBar.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RCTEventDispatcher;
|
||||
|
||||
@interface RCTTabBar : UIView
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
139
ReactKit/Views/RCTTabBar.m
Normal file
139
ReactKit/Views/RCTTabBar.m
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTTabBar.h"
|
||||
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTTabBarItem.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "RCTView.h"
|
||||
#import "RCTViewControllerProtocol.h"
|
||||
#import "RCTWrapperViewController.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@interface RKCustomTabBarController : UITabBarController <RCTViewControllerProtocol>
|
||||
|
||||
@end
|
||||
|
||||
@implementation RKCustomTabBarController
|
||||
|
||||
@synthesize currentTopLayoutGuide = _currentTopLayoutGuide;
|
||||
@synthesize currentBottomLayoutGuide = _currentBottomLayoutGuide;
|
||||
|
||||
- (void)viewWillLayoutSubviews
|
||||
{
|
||||
[super viewWillLayoutSubviews];
|
||||
_currentTopLayoutGuide = self.topLayoutGuide;
|
||||
_currentBottomLayoutGuide = self.bottomLayoutGuide;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTTabBar() <UITabBarControllerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTTabBar
|
||||
{
|
||||
BOOL _tabsChanged;
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
UITabBarController *_tabController;
|
||||
NSMutableArray *_tabViews;
|
||||
}
|
||||
|
||||
- (id)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if ((self = [super initWithFrame:CGRectZero])) {
|
||||
_eventDispatcher = eventDispatcher;
|
||||
_tabViews = [[NSMutableArray alloc] init];
|
||||
_tabController = [[RKCustomTabBarController alloc] init];
|
||||
_tabController.delegate = self;
|
||||
[self addSubview:_tabController.view];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIViewController *)backingViewController
|
||||
{
|
||||
return _tabController;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_tabController.delegate = nil;
|
||||
}
|
||||
|
||||
- (NSArray *)reactSubviews
|
||||
{
|
||||
return _tabViews;
|
||||
}
|
||||
|
||||
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
|
||||
{
|
||||
if (![view isKindOfClass:[RCTTabBarItem class]]) {
|
||||
RCTLogError(@"subview should be of type RCTTabBarItem");
|
||||
return;
|
||||
}
|
||||
[_tabViews insertObject:view atIndex:atIndex];
|
||||
_tabsChanged = YES;
|
||||
}
|
||||
|
||||
- (void)removeReactSubview:(UIView *)subview
|
||||
{
|
||||
if (_tabViews.count == 0) {
|
||||
RCTLogError(@"should have at least one view to remove a subview");
|
||||
return;
|
||||
}
|
||||
[_tabViews removeObject:subview];
|
||||
_tabsChanged = YES;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
_tabController.view.frame = self.bounds;
|
||||
}
|
||||
|
||||
- (void)reactBridgeDidFinishTransaction
|
||||
{
|
||||
// we can't hook up the VC hierarchy in 'init' because the subviews aren't
|
||||
// hooked up yet, so we do it on demand here whenever a transaction has finished
|
||||
[self addControllerToClosestParent:_tabController];
|
||||
//[RCTView addViewController:_tabController toBackingViewControllerForView:self];
|
||||
|
||||
if (_tabsChanged) {
|
||||
|
||||
NSMutableArray *viewControllers = [NSMutableArray array];
|
||||
for (RCTTabBarItem *tab in [self reactSubviews]) {
|
||||
UIViewController *controller = tab.backingViewController;
|
||||
if (!controller) {
|
||||
controller = [[RCTWrapperViewController alloc] initWithContentView:tab
|
||||
eventDispatcher:_eventDispatcher];
|
||||
}
|
||||
[viewControllers addObject:controller];
|
||||
}
|
||||
|
||||
_tabController.viewControllers = viewControllers;
|
||||
_tabsChanged = NO;
|
||||
}
|
||||
|
||||
[[self reactSubviews] enumerateObjectsUsingBlock:^(RCTTabBarItem *tab, NSUInteger index, BOOL *stop) {
|
||||
UIViewController *controller = _tabController.viewControllers[index];
|
||||
controller.tabBarItem = tab.barItem;
|
||||
if (tab.selected) {
|
||||
_tabController.selectedViewController = controller;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - UITabBarControllerDelegate
|
||||
|
||||
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
|
||||
{
|
||||
NSUInteger index = [tabBarController.viewControllers indexOfObject:viewController];
|
||||
RCTTabBarItem *tab = [self reactSubviews][index];
|
||||
[_eventDispatcher sendInputEventWithName:@"topTap" body:@{@"target": tab.reactTag}];
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
11
ReactKit/Views/RCTTabBarItem.h
Normal file
11
ReactKit/Views/RCTTabBarItem.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface RCTTabBarItem : UIView
|
||||
|
||||
@property (nonatomic, copy) NSString *icon;
|
||||
@property (nonatomic, assign, getter=isSelected) BOOL selected;
|
||||
@property (nonatomic, readonly) UITabBarItem *barItem;
|
||||
|
||||
@end
|
||||
83
ReactKit/Views/RCTTabBarItem.m
Normal file
83
ReactKit/Views/RCTTabBarItem.m
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTTabBarItem.h"
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTLog.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@implementation RCTTabBarItem
|
||||
|
||||
@synthesize barItem = _barItem;
|
||||
|
||||
- (UITabBarItem *)barItem
|
||||
{
|
||||
if (!_barItem) {
|
||||
_barItem = [[UITabBarItem alloc] init];
|
||||
}
|
||||
return _barItem;
|
||||
}
|
||||
|
||||
- (void)setIcon:(NSString *)icon
|
||||
{
|
||||
static NSDictionary *systemIcons;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
systemIcons = @{
|
||||
@"more": @(UITabBarSystemItemMore),
|
||||
@"favorites": @(UITabBarSystemItemFavorites),
|
||||
@"featured": @(UITabBarSystemItemFeatured),
|
||||
@"topRated": @(UITabBarSystemItemTopRated),
|
||||
@"recents": @(UITabBarSystemItemRecents),
|
||||
@"contacts": @(UITabBarSystemItemContacts),
|
||||
@"history": @(UITabBarSystemItemHistory),
|
||||
@"bookmarks": @(UITabBarSystemItemBookmarks),
|
||||
@"search": @(UITabBarSystemItemSearch),
|
||||
@"downloads": @(UITabBarSystemItemDownloads),
|
||||
@"mostRecent": @(UITabBarSystemItemMostRecent),
|
||||
@"mostViewed": @(UITabBarSystemItemMostViewed),
|
||||
};
|
||||
});
|
||||
|
||||
// Update icon
|
||||
BOOL wasSystemIcon = (systemIcons[_icon] != nil);
|
||||
_icon = [icon copy];
|
||||
|
||||
// Check if string matches any custom images first
|
||||
UIImage *image = [RCTConvert UIImage:_icon];
|
||||
UITabBarItem *oldItem = _barItem;
|
||||
if (image) {
|
||||
|
||||
// Recreate barItem if previous item was a system icon
|
||||
if (wasSystemIcon) {
|
||||
_barItem = nil;
|
||||
self.barItem.image = image;
|
||||
} else {
|
||||
self.barItem.image = image;
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Not a custom image, may be a system item?
|
||||
NSNumber *systemIcon = systemIcons[icon];
|
||||
if (!systemIcon) {
|
||||
RCTLogError(@"The tab bar icon '%@' did not match any known image or system icon", icon);
|
||||
return;
|
||||
}
|
||||
_barItem = [[UITabBarItem alloc] initWithTabBarSystemItem:[systemIcon integerValue] tag:oldItem.tag];
|
||||
}
|
||||
|
||||
// Reapply previous properties
|
||||
_barItem.title = oldItem.title;
|
||||
_barItem.imageInsets = oldItem.imageInsets;
|
||||
_barItem.selectedImage = oldItem.selectedImage;
|
||||
_barItem.badgeValue = oldItem.badgeValue;
|
||||
}
|
||||
|
||||
- (UIViewController *)backingViewController
|
||||
{
|
||||
return self.superview.backingViewController;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
#import "RCTViewManager.h"
|
||||
|
||||
@interface RCTStaticImageManager : RCTViewManager
|
||||
@interface RCTTabBarItemManager : RCTViewManager
|
||||
|
||||
@end
|
||||
25
ReactKit/Views/RCTTabBarItemManager.m
Normal file
25
ReactKit/Views/RCTTabBarItemManager.m
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTTabBarItemManager.h"
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTTabBarItem.h"
|
||||
|
||||
@implementation RCTTabBarItemManager
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTTabBarItem alloc] init];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(selected);
|
||||
RCT_EXPORT_VIEW_PROPERTY(icon);
|
||||
RCT_REMAP_VIEW_PROPERTY(selectedIcon, barItem.selectedImage);
|
||||
RCT_REMAP_VIEW_PROPERTY(badgeValue, barItem.badgeValue);
|
||||
RCT_CUSTOM_VIEW_PROPERTY(title, RCTTabBarItem *)
|
||||
{
|
||||
view.barItem.title = json ? [RCTConvert NSString:json] : defaultView.barItem.title;
|
||||
view.barItem.imageInsets = [view.barItem.title length] ? UIEdgeInsetsZero : (UIEdgeInsets){6, 0, -6, 0};
|
||||
}
|
||||
|
||||
@end
|
||||
7
ReactKit/Views/RCTTabBarManager.h
Normal file
7
ReactKit/Views/RCTTabBarManager.h
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTViewManager.h"
|
||||
|
||||
@interface RCTTabBarManager : RCTViewManager
|
||||
|
||||
@end
|
||||
17
ReactKit/Views/RCTTabBarManager.m
Normal file
17
ReactKit/Views/RCTTabBarManager.m
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTTabBarManager.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTTabBar.h"
|
||||
|
||||
@implementation RCTTabBarManager
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTTabBar alloc] initWithEventDispatcher:_bridge.eventDispatcher];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTTextField alloc] initWithEventDispatcher:self.eventDispatcher];
|
||||
return [[RCTTextField alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(caretHidden)
|
||||
|
||||
@@ -10,14 +10,18 @@
|
||||
|
||||
@interface RCTView : UIView
|
||||
|
||||
/**
|
||||
* Used to control how touch events are processed.
|
||||
*/
|
||||
@property (nonatomic, assign) RCTPointerEvents pointerEvents;
|
||||
|
||||
+ (void)autoAdjustInsetsForView:(UIView<RCTAutoInsetsProtocol> *)parentView
|
||||
withScrollView:(UIScrollView *)scrollView
|
||||
updateOffset:(BOOL)updateOffset;
|
||||
|
||||
+ (UIViewController *)backingViewControllerForView:(UIView *)view;
|
||||
|
||||
/**
|
||||
* Find the first view controller whose view, or any subview is the specified view.
|
||||
*/
|
||||
+ (UIEdgeInsets)contentInsetsForView:(UIView *)curView;
|
||||
|
||||
@end
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#import "RCTAutoInsetsProtocol.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTLog.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
||||
{
|
||||
@@ -23,15 +24,6 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
||||
|
||||
@implementation RCTView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
_pointerEvents = RCTPointerEventsUnspecified;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)accessibilityLabel
|
||||
{
|
||||
if (super.accessibilityLabel) {
|
||||
@@ -108,19 +100,10 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
||||
}
|
||||
}
|
||||
|
||||
+ (UIViewController *)backingViewControllerForView:(UIView *)view
|
||||
{
|
||||
id responder = [view nextResponder];
|
||||
if ([responder isKindOfClass:[UIViewController class]]) {
|
||||
return responder;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (UIEdgeInsets)contentInsetsForView:(UIView *)view
|
||||
{
|
||||
while (view) {
|
||||
UIViewController *controller = [self backingViewControllerForView:view];
|
||||
UIViewController *controller = view.backingViewController;
|
||||
if (controller) {
|
||||
return (UIEdgeInsets){
|
||||
controller.topLayoutGuide.length, 0,
|
||||
|
||||
13
ReactKit/Views/RCTViewControllerProtocol.h
Normal file
13
ReactKit/Views/RCTViewControllerProtocol.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
/**
|
||||
* A simple protocol that any React-managed ViewControllers should implement.
|
||||
* We need all of our ViewControllers to cache layoutGuide changes so any View
|
||||
* in our View hierarchy can access accurate layoutGuide info at any time.
|
||||
*/
|
||||
@protocol RCTViewControllerProtocol <NSObject>
|
||||
|
||||
@property (nonatomic, readonly, strong) id<UILayoutSupport> currentTopLayoutGuide;
|
||||
@property (nonatomic, readonly, strong) id<UILayoutSupport> currentBottomLayoutGuide;
|
||||
|
||||
@end
|
||||
@@ -23,14 +23,6 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, RCTSparseArray *v
|
||||
*/
|
||||
@property (nonatomic, strong) RCTBridge *bridge;
|
||||
|
||||
/**
|
||||
* The event dispatcher is used to send events back to the JavaScript application.
|
||||
* It can either be used directly by the module, or passed on to instantiated
|
||||
* view subclasses so that they can handle their own events.
|
||||
*/
|
||||
// TODO: remove this, as it can be accessed directly from bridge
|
||||
@property (nonatomic, readonly) RCTEventDispatcher *eventDispatcher;
|
||||
|
||||
/**
|
||||
* The module name exposed to React JS. If omitted, this will be inferred
|
||||
* automatically by using the view module's class name. It is better to not
|
||||
|
||||
@@ -14,11 +14,6 @@
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
- (RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
return _bridge.eventDispatcher;
|
||||
}
|
||||
|
||||
+ (NSString *)moduleName
|
||||
{
|
||||
// Default implementation, works in most cases
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
- (void)insertReactSubview:(id<RCTViewNodeProtocol>)subview atIndex:(NSInteger)atIndex;
|
||||
- (void)removeReactSubview:(id<RCTViewNodeProtocol>)subview;
|
||||
- (NSMutableArray *)reactSubviews;
|
||||
- (id<RCTViewNodeProtocol>)reactSuperview;
|
||||
- (NSNumber *)reactTagAtPoint:(CGPoint)point;
|
||||
|
||||
// View is an RCTRootView
|
||||
@@ -26,3 +27,9 @@
|
||||
- (void)reactBridgeDidFinishTransaction;
|
||||
|
||||
@end
|
||||
|
||||
// TODO: this is kinda dumb - let's come up with a
|
||||
// better way of identifying root react views please!
|
||||
static inline BOOL RCTIsReactRootView(NSNumber *reactTag) {
|
||||
return reactTag.integerValue % 10 == 1;
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTViewControllerProtocol.h"
|
||||
|
||||
@class RCTEventDispatcher;
|
||||
@class RCTNavItem;
|
||||
@class RCTWrapperViewController;
|
||||
@@ -13,7 +15,7 @@ didMoveToNavigationController:(UINavigationController *)navigationController;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTWrapperViewController : UIViewController
|
||||
@interface RCTWrapperViewController : UIViewController <RCTViewControllerProtocol>
|
||||
|
||||
- (instancetype)initWithContentView:(UIView *)contentView
|
||||
eventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
||||
@@ -21,7 +23,7 @@ didMoveToNavigationController:(UINavigationController *)navigationController;
|
||||
- (instancetype)initWithNavItem:(RCTNavItem *)navItem
|
||||
eventDispatcher:(RCTEventDispatcher *)eventDispatcher;
|
||||
|
||||
@property (nonatomic, readwrite, weak) id<RCTWrapperViewControllerNavigationListener> navigationListener;
|
||||
@property (nonatomic, strong, readwrite) RCTNavItem *navItem;
|
||||
@property (nonatomic, weak) id<RCTWrapperViewControllerNavigationListener> navigationListener;
|
||||
@property (nonatomic, strong) RCTNavItem *navItem;
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,22 +2,30 @@
|
||||
|
||||
#import "RCTWrapperViewController.h"
|
||||
|
||||
#import <UIKit/UIScrollView.h>
|
||||
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTNavItem.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "RCTViewControllerProtocol.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@implementation RCTWrapperViewController
|
||||
{
|
||||
UIView *_wrapperView;
|
||||
UIView *_contentView;
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
CGFloat _previousTopLayout;
|
||||
CGFloat _previousBottomLayout;
|
||||
}
|
||||
|
||||
- (instancetype)initWithContentView:(UIView *)contentView eventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
@synthesize currentTopLayoutGuide = _currentTopLayoutGuide;
|
||||
@synthesize currentBottomLayoutGuide = _currentBottomLayoutGuide;
|
||||
|
||||
- (instancetype)initWithContentView:(UIView *)contentView
|
||||
eventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if ((self = [super initWithNibName:nil bundle:nil])) {
|
||||
if (self = [super initWithNibName:nil bundle:nil]) {
|
||||
_contentView = contentView;
|
||||
_eventDispatcher = eventDispatcher;
|
||||
self.automaticallyAdjustsScrollViewInsets = NO;
|
||||
@@ -25,80 +33,91 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNavItem:(RCTNavItem *)navItem eventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
- (instancetype)initWithNavItem:(RCTNavItem *)navItem
|
||||
eventDispatcher:(RCTEventDispatcher *)eventDispatcher
|
||||
{
|
||||
if ((self = [self initWithContentView:navItem eventDispatcher:eventDispatcher])) {
|
||||
if (self = [self initWithContentView:navItem eventDispatcher:eventDispatcher]) {
|
||||
_navItem = navItem;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews
|
||||
{
|
||||
[super viewWillLayoutSubviews];
|
||||
|
||||
_currentTopLayoutGuide = self.topLayoutGuide;
|
||||
_currentBottomLayoutGuide = self.bottomLayoutGuide;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
[self.navigationController setNavigationBarHidden:!_navItem animated:animated];
|
||||
if (!_navItem) {
|
||||
return;
|
||||
}
|
||||
// TODO: find a way to make this less-tightly coupled to navigation controller
|
||||
if ([self.parentViewController isKindOfClass:[UINavigationController class]])
|
||||
{
|
||||
|
||||
self.navigationItem.title = _navItem.title;
|
||||
|
||||
[self _configureNavBarStyle];
|
||||
|
||||
if (_navItem.rightButtonTitle.length > 0) {
|
||||
self.navigationItem.rightBarButtonItem =
|
||||
[[UIBarButtonItem alloc] initWithTitle:_navItem.rightButtonTitle
|
||||
style:UIBarButtonItemStyleDone
|
||||
target:self
|
||||
action:@selector(rightButtonTapped)];
|
||||
}
|
||||
|
||||
if (_navItem.backButtonTitle.length > 0) {
|
||||
self.navigationItem.backBarButtonItem =
|
||||
[[UIBarButtonItem alloc] initWithTitle:_navItem.backButtonTitle
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:nil
|
||||
action:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_configureNavBarStyle
|
||||
{
|
||||
UINavigationBar *bar = self.navigationController.navigationBar;
|
||||
if (_navItem.barTintColor) {
|
||||
bar.barTintColor = _navItem.barTintColor;
|
||||
}
|
||||
if (_navItem.tintColor) {
|
||||
BOOL canSetTintColor = _navItem.barTintColor == nil;
|
||||
if (canSetTintColor) {
|
||||
bar.tintColor = _navItem.tintColor;
|
||||
[self.navigationController setNavigationBarHidden:!_navItem animated:animated];
|
||||
if (!_navItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.navigationItem.title = _navItem.title;
|
||||
|
||||
UINavigationBar *bar = self.navigationController.navigationBar;
|
||||
if (_navItem.barTintColor) {
|
||||
bar.barTintColor = _navItem.barTintColor;
|
||||
}
|
||||
if (_navItem.tintColor) {
|
||||
BOOL canSetTintColor = _navItem.barTintColor == nil;
|
||||
if (canSetTintColor) {
|
||||
bar.tintColor = _navItem.tintColor;
|
||||
}
|
||||
}
|
||||
if (_navItem.titleTextColor) {
|
||||
[bar setTitleTextAttributes:@{NSForegroundColorAttributeName : _navItem.titleTextColor}];
|
||||
}
|
||||
|
||||
if (_navItem.rightButtonTitle.length > 0) {
|
||||
self.navigationItem.rightBarButtonItem =
|
||||
[[UIBarButtonItem alloc] initWithTitle:_navItem.rightButtonTitle
|
||||
style:UIBarButtonItemStyleDone
|
||||
target:self
|
||||
action:@selector(handleNavRightButtonTapped)];
|
||||
}
|
||||
|
||||
if (_navItem.backButtonTitle.length > 0) {
|
||||
self.navigationItem.backBarButtonItem =
|
||||
[[UIBarButtonItem alloc] initWithTitle:_navItem.backButtonTitle
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:nil
|
||||
action:nil];
|
||||
}
|
||||
}
|
||||
if (_navItem.titleTextColor) {
|
||||
[bar setTitleTextAttributes:@{NSForegroundColorAttributeName : _navItem.titleTextColor}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
// Add a wrapper so that UIViewControllerWrapperView (managed by the
|
||||
// add a wrapper so that UIViewControllerWrapperView (managed by the
|
||||
// UINavigationController) doesn't end up resetting the frames for
|
||||
// `contentView` which is a react-managed view.
|
||||
self.view = [[UIView alloc] init];
|
||||
[self.view addSubview:_contentView];
|
||||
//`contentView` which is a react-managed view.
|
||||
_wrapperView = [[UIView alloc] initWithFrame:_contentView.bounds];
|
||||
[_wrapperView addSubview:_contentView];
|
||||
self.view = _wrapperView;
|
||||
}
|
||||
|
||||
- (void)rightButtonTapped
|
||||
- (void)handleNavRightButtonTapped
|
||||
{
|
||||
[_eventDispatcher sendInputEventWithName:@"topNavRightButtonTap" body:@{@"target":_navItem.reactTag}];
|
||||
[_eventDispatcher sendInputEventWithName:@"topNavRightButtonTap"
|
||||
body:@{@"target":_navItem.reactTag}];
|
||||
}
|
||||
|
||||
- (void)didMoveToParentViewController:(UIViewController *)parent
|
||||
{
|
||||
// There's no clear setter for navigation controllers, but did move to parent view controller
|
||||
// provides the desired effect. This is called after a pop finishes, be it a swipe to go back
|
||||
// or a standard tap on the back button
|
||||
// There's no clear setter for navigation controllers, but did move to parent
|
||||
// view controller provides the desired effect. This is called after a pop
|
||||
// finishes, be it a swipe to go back or a standard tap on the back button
|
||||
[super didMoveToParentViewController:parent];
|
||||
if (parent == nil || [parent isKindOfClass:[UINavigationController class]]) {
|
||||
[self.navigationListener wrapperViewController:self didMoveToNavigationController:(UINavigationController *)parent];
|
||||
|
||||
@@ -8,4 +8,17 @@
|
||||
|
||||
@interface UIView (ReactKit) <RCTViewNodeProtocol>
|
||||
|
||||
/**
|
||||
* This method finds and returns the containing view controller for the view.
|
||||
*/
|
||||
- (UIViewController *)backingViewController;
|
||||
|
||||
/**
|
||||
* This method attaches the specified controller as a child of the
|
||||
* the owning view controller of this view. Returns NO if no view
|
||||
* controller is found (which may happen if the view is not currently
|
||||
* attached to the view hierarchy).
|
||||
*/
|
||||
- (void)addControllerToClosestParent:(UIViewController *)controller;
|
||||
|
||||
@end
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTWrapperViewController.h"
|
||||
|
||||
@implementation UIView (ReactKit)
|
||||
|
||||
@@ -20,7 +21,7 @@
|
||||
|
||||
- (BOOL)isReactRootView
|
||||
{
|
||||
return NO;
|
||||
return RCTIsReactRootView(self.reactTag);
|
||||
}
|
||||
|
||||
- (NSNumber *)reactTagAtPoint:(CGPoint)point
|
||||
@@ -39,7 +40,7 @@
|
||||
|
||||
- (void)removeReactSubview:(UIView *)subview
|
||||
{
|
||||
RCTAssert(subview.superview == self, @"");
|
||||
RCTAssert(subview.superview == self, @"%@ is a not a subview of %@", subview, self);
|
||||
[subview removeFromSuperview];
|
||||
}
|
||||
|
||||
@@ -48,4 +49,34 @@
|
||||
return self.subviews;
|
||||
}
|
||||
|
||||
- (UIView *)reactSuperview
|
||||
{
|
||||
return self.superview;
|
||||
}
|
||||
|
||||
- (UIViewController *)backingViewController
|
||||
{
|
||||
id responder = [self nextResponder];
|
||||
if ([responder isKindOfClass:[RCTWrapperViewController class]]) {
|
||||
return responder;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)addControllerToClosestParent:(UIViewController *)controller
|
||||
{
|
||||
if (!controller.parentViewController) {
|
||||
UIView *parentView = (UIView *)self.reactSuperview;
|
||||
while (parentView) {
|
||||
if (parentView.backingViewController) {
|
||||
[parentView.backingViewController addChildViewController:controller];
|
||||
[controller didMoveToParentViewController:parentView.backingViewController];
|
||||
break;
|
||||
}
|
||||
parentView = (UIView *)parentView.reactSuperview;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user