ComponentKit/Core/CKCompositeComponent.mm (88 lines of code) (raw):
/*
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "CKCompositeComponent.h"
#import <RenderCore/RCAssert.h>
#import <ComponentKit/CKMacros.h>
#import <ComponentKit/CKInternalHelpers.h>
#import "CKComponentInternal.h"
#import "CKComponentSubclass.h"
#import "CKIterableHelpers.h"
#import "CKRenderHelpers.h"
#import "CKComponentViewConfiguration_SwiftBridge+Internal.h"
@implementation CKCompositeComponent
{
id<CKMountable> _child;
}
#if DEBUG
+ (void)initialize
{
if (self != [CKCompositeComponent class]) {
RCAssert(!CKSubclassOverridesInstanceMethod([CKCompositeComponent class], self, @selector(computeLayoutThatFits:)),
@"%@ overrides -computeLayoutThatFits: which is not allowed. "
"Consider subclassing CKComponent directly if you need to perform custom layout.",
self);
RCAssert(!CKSubclassOverridesInstanceMethod([CKCompositeComponent class], self, @selector(layoutThatFits:parentSize:)),
@"%@ overrides -layoutThatFits:parentSize: which is not allowed. "
"Consider subclassing CKComponent directly if you need to perform custom layout.",
self);
}
}
#endif
- (instancetype _Nullable)initWithView:(const CKComponentViewConfiguration &)view
component:(id<CKMountable> _Nullable)component
{
if (component == nil) {
return nil;
}
if (self = [super initWithView:view size:{}]) {
_child = component;
}
return self;
}
- (instancetype)initWithSwiftView:(CKComponentViewConfiguration_SwiftBridge *_Nullable)swiftView
component:(id<CKMountable>)component
{
const auto view = swiftView != nil ? swiftView.viewConfig : CKComponentViewConfiguration{};
return [self initWithView:view component:component];
}
+ (instancetype)newWithComponent:(id<CKMountable>)component
{
return [self newWithView:{} component:component];
}
+ (instancetype)newWithView:(const CKComponentViewConfiguration &)view component:(id<CKMountable>)component
{
if (component == nil) {
return nil;
}
CKCompositeComponent *c = [super newWithView:view size:{}];
if (c != nil) {
c->_child = component;
}
return c;
}
- (RCLayout)computeLayoutThatFits:(CKSizeRange)constrainedSize
restrictedToSize:(const RCComponentSize &)size
relativeToParentSize:(CGSize)parentSize
{
RCAssert(size == RCComponentSize(),
@"CKCompositeComponent only passes size {} to the super class initializer, but received size %@ "
"(component=%@)", size.description(), _child);
RCLayout l = [_child layoutThatFits:constrainedSize parentSize:parentSize];
const auto lSize = l.size;
return {self, lSize, {{{0,0}, std::move(l)}}};
}
- (id<CKMountable>)child
{
return _child;
}
- (UIView *)viewForAnimation
{
// Delegate to the wrapped component's viewForAnimation if we don't have one.
return [super viewForAnimation] ?: [CKReturnIfResponds(_child, @selector(viewForAnimation)) viewForAnimation];
}
- (unsigned int)numberOfChildren
{
return RCIterable::numberOfChildren(_child);
}
- (id<CKMountable>)childAtIndex:(unsigned int)index
{
return RCIterable::childAtIndex(self, index, _child);
}
@end