Layout Component
Why do we need layout components?
- As we mentioned previously, render components work seamlessly with non-render components.
- In order to make sure that it works correct, each component has to implement buildComponentTree: correctly and continue the recursion to its children (more details can be found here).
- We implemented the buildComponentTree: method for all the base components, you don't need (and actually can't) implement this method.
- The base implementation in CKComponent is for a leaf component.
- When a component subclass from CKComponent, but has a custom layout with children - it can cause a problem; the infrastructure doesn't know about its children and cannot build the component tree for them.
How do we solve this?
- We introduced:
- CKLayoutComponent
- We converted all the layout components in the infra to CKLayoutComponent. For example:
- CKInsetComponent : CKLayoutComponent
- CKFlexboxComponent : CKLayoutComponent
- We codemoded all the other custom layout components in the code base.
- We introduced a runtime assert in case you have a render component in the hierarchy and a custom layout component that inherits from CKComponent
When should I use render layout components?
- In general, we recommend to avoid custom layout component as much as possible. If you can, just use CKFlexboxComponent with absolute layout to describe your layout.
- If your component must have a custom layout, you can probably use CKLayoutComponent and provide your custom layout.
How to use CKLayoutComponent
- All you need to do, is to override the CKIterable method sand provide the component's children there.
- Before the conversion:
@interface GapComponent : CKComponent@end@implementation GapComponent{CKComponent *_child;}+ (instancetype)newWithComponent:(CKComponent *)component{auto const c = [super new];if (c) {_child = component;}return c;}- (CKLayout)computeLayoutThatFits:(CKSizeRange)constrainedSize{...}@end
- After the conversion:
@interface GapComponent : CKRenderLayoutComponent@end@implementation GapComponent{CKComponent *_child;}+ (instancetype)newWithComponent:(CKComponent *)component{auto const c = [super new];if (c) {_child = component;}return c;}- (unsigned int)numberOfChildren{return CKIterable::numberOfChildren(_child);}- (id<CKMountable>)childAtIndex:(unsigned int)index{return CKIterable::childAtIndex(self, index, _child);}- (CKLayout)computeLayoutThatFits:(CKSizeRange)constrainedSize{...}@end