Show mounted ComponentKit views in Flipper
Summary: Before this diff, Flipper showed *leaf* views created by ComponentKit, but not any intermediate views. Now we show both. A new node type `SKComponentMountedView` is used for this purpose. Its descriptor `SKComponentMountedViewDescriptor` mostly delegates to its view's descriptor, but redirects back into ComponentKit for children. Reviewed By: Andrey-Mishanin Differential Revision: D21130997 fbshipit-source-id: b3c12ea7cc1200962b3ba7c269c48d68b1809948
This commit is contained in:
committed by
Facebook GitHub Bot
parent
756987e4bf
commit
d0803ecd56
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#import "SKComponentLayoutDescriptor.h"
|
#import "SKComponentLayoutDescriptor.h"
|
||||||
#import "SKComponentLayoutWrapper.h"
|
#import "SKComponentLayoutWrapper.h"
|
||||||
|
#import "SKComponentMountedView.h"
|
||||||
|
#import "SKComponentMountedViewDescriptor.h"
|
||||||
#import "SKComponentRootViewDescriptor.h"
|
#import "SKComponentRootViewDescriptor.h"
|
||||||
|
|
||||||
@implementation FlipperKitLayoutComponentKitSupport
|
@implementation FlipperKitLayoutComponentKitSupport
|
||||||
@@ -29,6 +31,9 @@
|
|||||||
[mapper registerDescriptor:[[SKComponentLayoutDescriptor alloc]
|
[mapper registerDescriptor:[[SKComponentLayoutDescriptor alloc]
|
||||||
initWithDescriptorMapper:mapper]
|
initWithDescriptorMapper:mapper]
|
||||||
forClass:[SKComponentLayoutWrapper class]];
|
forClass:[SKComponentLayoutWrapper class]];
|
||||||
|
[mapper registerDescriptor:[[SKComponentMountedViewDescriptor alloc]
|
||||||
|
initWithDescriptorMapper:mapper]
|
||||||
|
forClass:[SKComponentMountedView class]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#import "CKComponent+Sonar.h"
|
#import "CKComponent+Sonar.h"
|
||||||
#import "SKComponentLayoutWrapper.h"
|
#import "SKComponentLayoutWrapper.h"
|
||||||
|
#import "SKComponentMountedView.h"
|
||||||
#import "SKSubDescriptor.h"
|
#import "SKSubDescriptor.h"
|
||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
|
|
||||||
@@ -64,21 +65,26 @@ static std::vector<std::pair<NSString*, SKSubDescriptor>>& subDescriptors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)childCountForNode:(SKComponentLayoutWrapper*)node {
|
- (NSUInteger)childCountForNode:(SKComponentLayoutWrapper*)node {
|
||||||
NSUInteger count = node.children.size();
|
if (!node) {
|
||||||
if (count == 0) {
|
return 0; // -children will return garbage if invoked on nil
|
||||||
count = node.component.viewContext.view ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
return count;
|
return node.children.match(
|
||||||
|
[](SKLeafViewChild) -> NSUInteger { return 1; },
|
||||||
|
[](SKMountedViewChild) -> NSUInteger { return 1; },
|
||||||
|
[](const std::vector<SKComponentLayoutWrapper*>& components)
|
||||||
|
-> NSUInteger { return components.size(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)childForNode:(SKComponentLayoutWrapper*)node atIndex:(NSUInteger)index {
|
- (id)childForNode:(SKComponentLayoutWrapper*)node atIndex:(NSUInteger)index {
|
||||||
if (node.children.size() == 0) {
|
if (!node) {
|
||||||
if (node.rootNode == node.component.viewContext.view) {
|
return nil; // -children will return garbage if invoked on nil
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
return node.component.viewContext.view;
|
|
||||||
}
|
}
|
||||||
return node.children[index];
|
return node.children.match(
|
||||||
|
[](SKLeafViewChild leafView) -> id { return leafView.view; },
|
||||||
|
[](SKMountedViewChild mountedView) -> id { return mountedView.view; },
|
||||||
|
[&](const std::vector<SKComponentLayoutWrapper*>& components) -> id {
|
||||||
|
return components[index];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)dataForNode:
|
- (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)dataForNode:
|
||||||
@@ -86,12 +92,11 @@ static std::vector<std::pair<NSString*, SKSubDescriptor>>& subDescriptors() {
|
|||||||
NSMutableArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>* data =
|
NSMutableArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>* data =
|
||||||
[NSMutableArray new];
|
[NSMutableArray new];
|
||||||
|
|
||||||
if (node.isFlexboxChild) {
|
if (node) {
|
||||||
[data
|
node.flexboxChild.apply([&](const CKFlexboxComponentChild& child) {
|
||||||
addObject:[SKNamed
|
[data addObject:[SKNamed newWithName:@"Layout"
|
||||||
newWithName:@"Layout"
|
withValue:[self propsForFlexboxChild:child]]];
|
||||||
withValue:[self
|
});
|
||||||
propsForFlexboxChild:node.flexboxChild]]];
|
|
||||||
}
|
}
|
||||||
NSMutableDictionary<NSString*, NSObject*>* extraData =
|
NSMutableDictionary<NSString*, NSObject*>* extraData =
|
||||||
[[NSMutableDictionary alloc] init];
|
[[NSMutableDictionary alloc] init];
|
||||||
@@ -163,29 +168,33 @@ static std::vector<std::pair<NSString*, SKSubDescriptor>>& subDescriptors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)hitTest:(SKTouch*)touch forNode:(SKComponentLayoutWrapper*)node {
|
- (void)hitTest:(SKTouch*)touch forNode:(SKComponentLayoutWrapper*)node {
|
||||||
if (node.children.size() == 0) {
|
if (!node) {
|
||||||
UIView* componentView = node.component.viewContext.view;
|
return; // -children will return garbage if invoked on nil
|
||||||
if (componentView != nil) {
|
|
||||||
if ([touch containedIn:componentView.bounds]) {
|
|
||||||
[touch continueWithChildIndex:0 withOffset:componentView.bounds.origin];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
BOOL didContinueTouch = node.children.match(
|
||||||
NSInteger index = 0;
|
[&](SKLeafViewChild leafView) -> BOOL {
|
||||||
for (index = node.children.size() - 1; index >= 0; index--) {
|
[touch continueWithChildIndex:0 withOffset:{0, 0}];
|
||||||
const auto child = node.children[index];
|
return YES;
|
||||||
|
},
|
||||||
CGRect frame = {.origin = child.position, .size = child.size};
|
[&](SKMountedViewChild mountedView) -> BOOL {
|
||||||
|
[touch continueWithChildIndex:0 withOffset:{0, 0}];
|
||||||
if ([touch containedIn:frame]) {
|
return YES;
|
||||||
[touch continueWithChildIndex:index withOffset:child.position];
|
},
|
||||||
return;
|
[&](std::vector<SKComponentLayoutWrapper*> children) -> BOOL {
|
||||||
}
|
for (auto it = children.rbegin(); it != children.rend(); ++it) {
|
||||||
|
SKComponentLayoutWrapper* wrapper = *it;
|
||||||
|
CGRect frame = {.origin = wrapper.position, .size = wrapper.size};
|
||||||
|
if ([touch containedIn:frame]) {
|
||||||
|
NSUInteger index = std::distance(children.begin(), it.base()) - 1;
|
||||||
|
[touch continueWithChildIndex:index withOffset:wrapper.position];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
});
|
||||||
|
if (!didContinueTouch) {
|
||||||
|
[touch finish];
|
||||||
}
|
}
|
||||||
|
|
||||||
[touch finish];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)matchesQuery:(NSString*)query forNode:(id)node {
|
- (BOOL)matchesQuery:(NSString*)query forNode:(id)node {
|
||||||
|
|||||||
@@ -9,8 +9,35 @@
|
|||||||
|
|
||||||
#import <ComponentKit/CKComponentLayout.h>
|
#import <ComponentKit/CKComponentLayout.h>
|
||||||
#import <ComponentKit/CKFlexboxComponent.h>
|
#import <ComponentKit/CKFlexboxComponent.h>
|
||||||
|
#import <ComponentKit/CKOptional.h>
|
||||||
|
#import <ComponentKit/CKVariant.h>
|
||||||
|
|
||||||
|
#import <vector>
|
||||||
|
|
||||||
@protocol CKInspectableView;
|
@protocol CKInspectableView;
|
||||||
|
@class SKComponentLayoutWrapper;
|
||||||
|
@class SKComponentMountedView;
|
||||||
|
|
||||||
|
// CK::Variant does not support Objective-C types unless they are boxed:
|
||||||
|
struct SKLeafViewChild {
|
||||||
|
UIView* view;
|
||||||
|
};
|
||||||
|
struct SKMountedViewChild {
|
||||||
|
SKComponentMountedView* view;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
The children of a SKComponentLayoutWrapper may be:
|
||||||
|
- A single leaf view, which may have UIView children of its own.
|
||||||
|
- A single non-leaf view, if the component created a view; its children will be
|
||||||
|
the component's child components.
|
||||||
|
- An array of SKComponentLayoutWrappers, if the component did not create a
|
||||||
|
view.
|
||||||
|
*/
|
||||||
|
using SKComponentLayoutWrapperChildren = CK::Variant<
|
||||||
|
SKLeafViewChild,
|
||||||
|
SKMountedViewChild,
|
||||||
|
std::vector<SKComponentLayoutWrapper*>>;
|
||||||
|
|
||||||
@interface SKComponentLayoutWrapper : NSObject
|
@interface SKComponentLayoutWrapper : NSObject
|
||||||
|
|
||||||
@@ -18,11 +45,11 @@
|
|||||||
@property(nonatomic, readonly) NSString* identifier;
|
@property(nonatomic, readonly) NSString* identifier;
|
||||||
@property(nonatomic, readonly) CGSize size;
|
@property(nonatomic, readonly) CGSize size;
|
||||||
@property(nonatomic, readonly) CGPoint position;
|
@property(nonatomic, readonly) CGPoint position;
|
||||||
@property(nonatomic, readonly) std::vector<SKComponentLayoutWrapper*> children;
|
@property(nonatomic, readonly) SKComponentLayoutWrapperChildren children;
|
||||||
@property(nonatomic, weak, readonly) id<CKInspectableView> rootNode;
|
@property(nonatomic, weak, readonly) id<CKInspectableView> rootNode;
|
||||||
// Null for layouts which are not direct children of a CKFlexboxComponent
|
/** CK::none for components that are not the child of a CKFlexboxComponent. */
|
||||||
@property(nonatomic, readonly) BOOL isFlexboxChild;
|
@property(nonatomic, readonly) CK::Optional<CKFlexboxComponentChild>
|
||||||
@property(nonatomic, readonly) CKFlexboxComponentChild flexboxChild;
|
flexboxChild;
|
||||||
|
|
||||||
+ (instancetype)newFromRoot:(id<CKInspectableView>)root
|
+ (instancetype)newFromRoot:(id<CKInspectableView>)root
|
||||||
parentKey:(NSString*)parentKey;
|
parentKey:(NSString*)parentKey;
|
||||||
|
|||||||
@@ -18,12 +18,13 @@
|
|||||||
#import <ComponentKit/CKInspectableView.h>
|
#import <ComponentKit/CKInspectableView.h>
|
||||||
|
|
||||||
#import "CKComponent+Sonar.h"
|
#import "CKComponent+Sonar.h"
|
||||||
|
#import "SKComponentMountedView.h"
|
||||||
|
|
||||||
static char const kLayoutWrapperKey = ' ';
|
static char const kLayoutWrapperKey = ' ';
|
||||||
|
|
||||||
static CKFlexboxComponentChild findFlexboxLayoutParams(
|
static CK::Optional<CKFlexboxComponentChild> findFlexboxLayoutParams(
|
||||||
CKComponent* parent,
|
id<CKMountable> parent,
|
||||||
CKComponent* child) {
|
id<CKMountable> child) {
|
||||||
if ([parent isKindOfClass:[CKFlexboxComponent class]]) {
|
if ([parent isKindOfClass:[CKFlexboxComponent class]]) {
|
||||||
static Ivar ivar =
|
static Ivar ivar =
|
||||||
class_getInstanceVariable([CKFlexboxComponent class], "_children");
|
class_getInstanceVariable([CKFlexboxComponent class], "_children");
|
||||||
@@ -42,7 +43,7 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return CK::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation SKComponentLayoutWrapper
|
@implementation SKComponentLayoutWrapper
|
||||||
@@ -66,6 +67,7 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(
|
|||||||
SKComponentLayoutWrapper* const wrapper = [[SKComponentLayoutWrapper alloc]
|
SKComponentLayoutWrapper* const wrapper = [[SKComponentLayoutWrapper alloc]
|
||||||
initWithLayout:layout
|
initWithLayout:layout
|
||||||
position:CGPointMake(0, 0)
|
position:CGPointMake(0, 0)
|
||||||
|
flexboxChild:CK::none
|
||||||
parentKey:[NSString
|
parentKey:[NSString
|
||||||
stringWithFormat:@"%@%d.",
|
stringWithFormat:@"%@%d.",
|
||||||
parentKey,
|
parentKey,
|
||||||
@@ -85,6 +87,8 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(
|
|||||||
|
|
||||||
- (instancetype)initWithLayout:(const CKComponentLayout&)layout
|
- (instancetype)initWithLayout:(const CKComponentLayout&)layout
|
||||||
position:(CGPoint)position
|
position:(CGPoint)position
|
||||||
|
flexboxChild:
|
||||||
|
(CK::Optional<CKFlexboxComponentChild>)flexboxChild
|
||||||
parentKey:(NSString*)parentKey
|
parentKey:(NSString*)parentKey
|
||||||
reuseWrapper:(CKComponentReuseWrapper*)reuseWrapper
|
reuseWrapper:(CKComponentReuseWrapper*)reuseWrapper
|
||||||
rootNode:(id<CKInspectableView>)node {
|
rootNode:(id<CKInspectableView>)node {
|
||||||
@@ -93,6 +97,7 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(
|
|||||||
_component = (CKComponent*)layout.component;
|
_component = (CKComponent*)layout.component;
|
||||||
_size = layout.size;
|
_size = layout.size;
|
||||||
_position = position;
|
_position = position;
|
||||||
|
_flexboxChild = flexboxChild;
|
||||||
_identifier = [parentKey stringByAppendingString:layout.component
|
_identifier = [parentKey stringByAppendingString:layout.component
|
||||||
? layout.component.className
|
? layout.component.className
|
||||||
: @"(null)"];
|
: @"(null)"];
|
||||||
@@ -105,6 +110,7 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<SKComponentLayoutWrapper*> childComponents;
|
||||||
if (layout.children != nullptr) {
|
if (layout.children != nullptr) {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (const auto& child : *layout.children) {
|
for (const auto& child : *layout.children) {
|
||||||
@@ -115,17 +121,26 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(
|
|||||||
[[SKComponentLayoutWrapper alloc]
|
[[SKComponentLayoutWrapper alloc]
|
||||||
initWithLayout:child.layout
|
initWithLayout:child.layout
|
||||||
position:child.position
|
position:child.position
|
||||||
|
flexboxChild:findFlexboxLayoutParams(
|
||||||
|
_component, child.layout.component)
|
||||||
parentKey:[_identifier
|
parentKey:[_identifier
|
||||||
stringByAppendingFormat:@"[%d].", index++]
|
stringByAppendingFormat:@"[%d].", index++]
|
||||||
reuseWrapper:reuseWrapper
|
reuseWrapper:reuseWrapper
|
||||||
rootNode:node];
|
rootNode:node];
|
||||||
childWrapper->_isFlexboxChild =
|
childComponents.push_back(childWrapper);
|
||||||
[_component isKindOfClass:[CKFlexboxComponent class]];
|
|
||||||
childWrapper->_flexboxChild = findFlexboxLayoutParams(
|
|
||||||
_component, (CKComponent*)child.layout.component);
|
|
||||||
_children.push_back(childWrapper);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIView* mountedView = _component.mountedView;
|
||||||
|
if (mountedView && !childComponents.empty()) {
|
||||||
|
_children = SKMountedViewChild{[[SKComponentMountedView alloc]
|
||||||
|
initWithView:mountedView
|
||||||
|
children:childComponents]};
|
||||||
|
} else if (mountedView) {
|
||||||
|
_children = SKLeafViewChild{mountedView}; // leaf view
|
||||||
|
} else {
|
||||||
|
_children = childComponents;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import <vector>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class SKComponentLayoutWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Represents a non-leaf view created by ComponentKit. Its corresponding
|
||||||
|
descriptor CKComponentMountedViewDescriptor delegates to the view's descriptor
|
||||||
|
for attributes and most other behaviors, but redirects back into ComponentKit's
|
||||||
|
SKComponentLayoutWrapper when queried for children.
|
||||||
|
|
||||||
|
In this way, non-leaf views created by ComponentKit appear in the Flipper
|
||||||
|
layout hierarchy as the child of the component that created their view.
|
||||||
|
*/
|
||||||
|
@interface SKComponentMountedView : NSObject
|
||||||
|
|
||||||
|
- (instancetype)initWithView:(UIView*)view
|
||||||
|
children:(std::vector<SKComponentLayoutWrapper*>)children;
|
||||||
|
|
||||||
|
@property(nonatomic, readonly) UIView* view;
|
||||||
|
@property(nonatomic, readonly) std::vector<SKComponentLayoutWrapper*> children;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if FB_SONARKIT_ENABLED
|
||||||
|
|
||||||
|
#import "SKComponentMountedView.h"
|
||||||
|
|
||||||
|
@implementation SKComponentMountedView
|
||||||
|
|
||||||
|
- (instancetype)initWithView:(UIView*)view
|
||||||
|
children:(std::vector<SKComponentLayoutWrapper*>)children {
|
||||||
|
if (self = [super init]) {
|
||||||
|
_view = view;
|
||||||
|
_children = std::move(children);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <FlipperKitLayoutPlugin/SKNodeDescriptor.h>
|
||||||
|
|
||||||
|
@class SKComponentMountedView;
|
||||||
|
|
||||||
|
@interface SKComponentMountedViewDescriptor
|
||||||
|
: SKNodeDescriptor<SKComponentMountedView*>
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if FB_SONARKIT_ENABLED
|
||||||
|
|
||||||
|
#import "SKComponentMountedViewDescriptor.h"
|
||||||
|
|
||||||
|
#import <ComponentKit/CKComponent.h>
|
||||||
|
#import <ComponentKit/CKComponentInternal.h>
|
||||||
|
|
||||||
|
#import <FlipperKitHighlightOverlay/SKHighlightOverlay.h>
|
||||||
|
#import <FlipperKitLayoutPlugin/SKObject.h>
|
||||||
|
#import <FlipperKitLayoutTextSearchable/FKTextSearchable.h>
|
||||||
|
|
||||||
|
#import "CKComponent+Sonar.h"
|
||||||
|
#import "SKComponentLayoutWrapper.h"
|
||||||
|
#import "SKComponentMountedView.h"
|
||||||
|
#import "Utils.h"
|
||||||
|
|
||||||
|
@implementation SKComponentMountedViewDescriptor
|
||||||
|
|
||||||
|
- (SKNodeDescriptor*)_viewDescriptorFor:(SKComponentMountedView*)node {
|
||||||
|
// For most methods, we delegate to the descriptor for the underlying view.
|
||||||
|
return [self descriptorForClass:[node.view class]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString*)identifierForNode:(SKComponentMountedView*)node {
|
||||||
|
return [[self _viewDescriptorFor:node] identifierForNode:node.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString*)nameForNode:(SKComponentMountedView*)node {
|
||||||
|
return [[self _viewDescriptorFor:node] nameForNode:node.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)childCountForNode:(SKComponentMountedView*)node {
|
||||||
|
// An obvious future improvement: we should also return any
|
||||||
|
// non-ComponentKit-managed child views of our view.
|
||||||
|
// Explicit nil check; -children will return garbage if invoked on nil
|
||||||
|
return node ? node.children.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)childForNode:(SKComponentMountedView*)node atIndex:(NSUInteger)index {
|
||||||
|
// Explicit nil check; -children will return garbage if invoked on nil
|
||||||
|
return node ? node.children[index] : nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)dataForNode:
|
||||||
|
(SKComponentMountedView*)node {
|
||||||
|
return [[self _viewDescriptorFor:node] dataForNode:node.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:
|
||||||
|
(SKComponentMountedView*)node {
|
||||||
|
return [[self _viewDescriptorFor:node] dataMutationsForNode:node.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray<SKNamed<NSString*>*>*)attributesForNode:
|
||||||
|
(SKComponentMountedView*)node {
|
||||||
|
return [[self _viewDescriptorFor:node] attributesForNode:node.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHighlighted:(BOOL)highlighted forNode:(SKComponentMountedView*)node {
|
||||||
|
[[self _viewDescriptorFor:node] setHighlighted:highlighted forNode:node.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)hitTest:(SKTouch*)touch forNode:(SKComponentMountedView*)node {
|
||||||
|
if (!node) {
|
||||||
|
return; // -children will return garbage if invoked on nil
|
||||||
|
}
|
||||||
|
const auto& children = node.children;
|
||||||
|
for (auto it = children.rbegin(); it != children.rend(); ++it) {
|
||||||
|
SKComponentLayoutWrapper* child = *it;
|
||||||
|
CGRect frame = {.origin = child.position, .size = child.size};
|
||||||
|
if ([touch containedIn:frame]) {
|
||||||
|
NSUInteger index = std::distance(children.begin(), it.base()) - 1;
|
||||||
|
[touch continueWithChildIndex:index withOffset:child.position];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[touch finish];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)matchesQuery:(NSString*)query forNode:(SKComponentMountedView*)node {
|
||||||
|
return [[self _viewDescriptorFor:node] matchesQuery:query forNode:node.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user