react-native/React/Views/UIView+React.m

145 lines
3.6 KiB
Objective-C

/**
* Copyright (c) 2015-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 "UIView+React.h"
#import <objc/runtime.h>
#import "RCTAssert.h"
#import "RCTLog.h"
#import "RCTShadowView.h"
@implementation UIView (React)
- (NSNumber *)reactTag
{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setReactTag:(NSNumber *)reactTag
{
objc_setAssociatedObject(self, @selector(reactTag), reactTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#if RCT_DEV
- (RCTShadowView *)_DEBUG_reactShadowView
{
return objc_getAssociatedObject(self, _cmd);
}
- (void)_DEBUG_setReactShadowView:(RCTShadowView *)shadowView
{
// Use assign to avoid keeping the shadowView alive it if no longer exists
objc_setAssociatedObject(self, @selector(_DEBUG_reactShadowView), shadowView, OBJC_ASSOCIATION_ASSIGN);
}
#endif
- (BOOL)isReactRootView
{
return RCTIsReactRootView(self.reactTag);
}
- (NSNumber *)reactTagAtPoint:(CGPoint)point
{
UIView *view = [self hitTest:point withEvent:nil];
while (view && !view.reactTag) {
view = view.superview;
}
return view.reactTag;
}
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
{
[self insertSubview:subview atIndex:atIndex];
}
- (void)removeReactSubview:(UIView *)subview
{
RCTAssert(subview.superview == self, @"%@ is a not a subview of %@", subview, self);
[subview removeFromSuperview];
}
- (NSArray<UIView *> *)reactSubviews
{
return self.subviews;
}
- (UIView *)reactSuperview
{
return self.superview;
}
- (void)reactSetFrame:(CGRect)frame
{
// These frames are in terms of anchorPoint = topLeft, but internally the
// views are anchorPoint = center for easier scale and rotation animations.
// Convert the frame so it works with anchorPoint = center.
CGPoint position = {CGRectGetMidX(frame), CGRectGetMidY(frame)};
CGRect bounds = {CGPointZero, frame.size};
// Avoid crashes due to nan coords
if (isnan(position.x) || isnan(position.y) ||
isnan(bounds.origin.x) || isnan(bounds.origin.y) ||
isnan(bounds.size.width) || isnan(bounds.size.height)) {
RCTLogError(@"Invalid layout for (%@)%@. position: %@. bounds: %@",
self.reactTag, self, NSStringFromCGPoint(position), NSStringFromCGRect(bounds));
return;
}
self.center = position;
self.bounds = bounds;
}
- (void)reactSetInheritedBackgroundColor:(__unused UIColor *)inheritedBackgroundColor
{
// Does nothing by default
}
- (UIViewController *)reactViewController
{
id responder = [self nextResponder];
while (responder) {
if ([responder isKindOfClass:[UIViewController class]]) {
return responder;
}
responder = [responder nextResponder];
}
return nil;
}
- (void)reactAddControllerToClosestParent:(UIViewController *)controller
{
if (!controller.parentViewController) {
UIView *parentView = (UIView *)self.reactSuperview;
while (parentView) {
if (parentView.reactViewController) {
[parentView.reactViewController addChildViewController:controller];
[controller didMoveToParentViewController:parentView.reactViewController];
break;
}
parentView = (UIView *)parentView.reactSuperview;
}
return;
}
}
/**
* Responder overrides - to be deprecated.
*/
- (void)reactWillMakeFirstResponder {};
- (void)reactDidMakeFirstResponder {};
- (BOOL)reactRespondsToTouch:(__unused UITouch *)touch
{
return YES;
}
@end