blob: 1e4be382404a36582d916c1f03819582c913d1de [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#import "WXComponent+Layout.h"
#import "WXComponent_internal.h"
#import "WXTransform.h"
#import "WXAssert.h"
#import "WXSDKInstance_private.h"
#import "WXComponent+BoxShadow.h"
#import "WXLog.h"
#import "WXMonitor.h"
#import "WXSDKInstance_performance.h"
#import "WXCellComponent.h"
bool flexIsUndefined(float value) {
return isnan(value);
}
@implementation WXComponent (Layout)
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
#pragma mark Public
- (void)setNeedsLayout
{
_isLayoutDirty = YES;
WXComponent *supercomponent = [self supercomponent];
//protet nil ptr
if (self.flexCssNode) {
self.flexCssNode->markDirty();
}else{
WXLogError(@"flexCssNode is nil");
}
if(supercomponent){
[supercomponent setNeedsLayout];
}
}
- (BOOL)needsLayout
{
return _isLayoutDirty;
}
- (CGSize (^)(CGSize))measureBlock
{
return nil;
}
- (void)layoutDidFinish
{
WXAssertMainThread();
}
#pragma mark Private
- (void)_initCSSNodeWithStyles:(NSDictionary *)styles
{
_flexCssNode = new WeexCore::WXCoreLayoutNode();
if ([self measureBlock]) {
_flexCssNode->setMeasureFunc(flexCssNodeMeasure);
}
_flexCssNode->setContext((__bridge void *)self);
[self _recomputeCSSNodeChildren];
[self _fillCSSNode:styles isUpdate:NO];
if ([self.ref isEqualToString:WX_SDK_ROOT_REF]) {
if (flexIsUndefined(_flexCssNode->getStyleHeight()) && self.weexInstance.frame.size.height) {
_flexCssNode->setStyleHeight(self.weexInstance.frame.size.height);
}
if (flexIsUndefined(_flexCssNode->getStyleWidth()) && self.weexInstance.frame.size.width) {
_flexCssNode->setStyleWidth(self.weexInstance.frame.size.width,NO);
}
}
}
- (void)_updateCSSNodeStyles:(NSDictionary *)styles
{
[self _fillCSSNode:styles isUpdate:YES];
}
-(void)_resetCSSNodeStyles:(NSArray *)styles
{
[self _resetCSSNode:styles];
}
- (void)_recomputeCSSNodeChildren
{
}
- (NSUInteger)_childrenCountForLayout
{
NSArray *subcomponents = _subcomponents;
NSUInteger count = subcomponents.count;
for (WXComponent *component in subcomponents) {
if (!component->_isNeedJoinLayoutSystem) {
count--;
}
}
return (int)(count);
}
- (void)_frameDidCalculated:(BOOL)isChanged
{
WXAssertComponentThread();
if (isChanged && [self isKindOfClass:[WXCellComponent class]]) {
CGFloat mainScreenWidth = [[UIScreen mainScreen] bounds].size.width;
CGFloat mainScreenHeight = [[UIScreen mainScreen] bounds].size.height;
if (mainScreenHeight/2 < _calculatedFrame.size.height && mainScreenWidth/2 < _calculatedFrame.size.width) {
[self weexInstance].performance.cellExceedNum++;
}
}
if ([self isViewLoaded] && isChanged && [self isViewFrameSyncWithCalculated]) {
__weak typeof(self) weakSelf = self;
[self.weexInstance.componentManager _addUITask:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
// Check again incase that this property is set to NO in another UI task.
if (![strongSelf isViewFrameSyncWithCalculated]) {
return;
}
if (strongSelf->_transform && !CATransform3DEqualToTransform(strongSelf.layer.transform, CATransform3DIdentity)) {
// From the UIView's frame documentation:
// https://developer.apple.com/reference/uikit/uiview#//apple_ref/occ/instp/UIView/frame
// Warning : If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
// So layer's transform must be reset to CATransform3DIdentity before setFrame, otherwise frame will be incorrect
strongSelf.layer.transform = CATransform3DIdentity;
}
if (!CGRectEqualToRect(strongSelf.view.frame,strongSelf.calculatedFrame)) {
strongSelf.view.frame = strongSelf.calculatedFrame;
strongSelf->_absolutePosition = CGPointMake(NAN, NAN);
[strongSelf configBoxShadow:_boxShadow];
} else {
if (![strongSelf equalBoxShadow:_boxShadow withBoxShadow:_lastBoxShadow]) {
[strongSelf configBoxShadow:_boxShadow];
}
}
[self _resetNativeBorderRadius];
if (strongSelf->_transform) {
[strongSelf->_transform applyTransformForView:strongSelf.view];
}
if (strongSelf->_backgroundImage) {
[strongSelf setGradientLayer];
}
[strongSelf setNeedsDisplay];
}];
}
}
- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition
gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
{
WXAssertComponentThread();
if (self.flexCssNode->hasNewLayout()) {
self.flexCssNode->setHasNewLayout(false);
_isLayoutDirty = NO;
CGRect newFrame = CGRectMake(
isnan(WXRoundPixelValue(_flexCssNode->getLayoutPositionLeft()))?0:WXRoundPixelValue(_flexCssNode->getLayoutPositionLeft())
,isnan(WXRoundPixelValue(_flexCssNode->getLayoutPositionTop()))?0:WXRoundPixelValue(_flexCssNode->getLayoutPositionTop())
,isnan(WXRoundPixelValue(_flexCssNode->getLayoutWidth()))?0:WXRoundPixelValue(_flexCssNode->getLayoutWidth())
,isnan(WXRoundPixelValue(_flexCssNode->getLayoutHeight()))?0:WXRoundPixelValue(_flexCssNode->getLayoutHeight())
);
BOOL isFrameChanged = NO;
if (!CGRectEqualToRect(newFrame, _calculatedFrame)) {
isFrameChanged = YES;
_calculatedFrame = newFrame;
[dirtyComponents addObject:self];
}
[self _frameDidCalculated:isFrameChanged];
#ifdef DEBUG
WXLogDebug(@"flexLayout -> newFrame ,type:%@,ref:%@, parentRef:%@,size :%@ ,instance:%@",self.type,self.ref,self.supercomponent.ref,NSStringFromCGRect(newFrame),self.weexInstance.instanceId);
#endif
}
NSArray * subcomponents = [_subcomponents copy];
for (WXComponent *subcomponent in subcomponents) {
[subcomponent _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
}
}
- (void)_layoutDidFinish
{
WXAssertMainThread();
if (_positionType == WXPositionTypeSticky) {
[self.ancestorScroller adjustSticky];
}
[self layoutDidFinish];
}
#define WX_STYLE_FLEX_NODE_JUDGE_LEGAL(key) styles[key]&&!isnan([WXConvert WXPixelType:styles[key] scaleFactor:self.weexInstance.pixelScaleFactor])
- (CGFloat)WXPixelType:(id)value
{
return [WXConvert WXPixelType:value scaleFactor:self.weexInstance.pixelScaleFactor];
}
- (void)_fillCSSNode:(NSDictionary *)styles isUpdate:(BOOL)isUpdate
{
// flex
if (styles[@"flex"]) {
_flexCssNode->setFlex([WXConvert CGFloat:styles[@"flex"]]);
}
if (isnan(_flexCssNode->getFlex())) {
// to make the default flex value is zero, yoga is nan, maybe this can configured by yoga config
_flexCssNode->setFlex(0);
}
if (styles[@"flexDirection"]) {
_flexCssNode->setFlexDirection([self fxFlexDirection:styles[@"flexDirection"]],isUpdate);
}
if (styles[@"alignItems"]) {
_flexCssNode->setAlignItems([self fxAlign:styles[@"alignItems"]]);
}
if (styles[@"alignSelf"]) {
_flexCssNode->setAlignSelf([self fxAlignSelf:styles[@"alignSelf"]]);
}
if (styles[@"flexWrap"]) {
_flexCssNode->setFlexWrap([self fxWrap:styles[@"flexWrap"]]);
}
if (styles[@"justifyContent"]) {
_flexCssNode->setJustifyContent([self fxJustify:styles[@"justifyContent"]]);
}
// position
if (styles[@"position"]) {
_flexCssNode->setStylePositionType([self fxPositionType:styles[@"position"]]);
}
if (styles[@"top"]) {
_flexCssNode->setStylePosition(WeexCore::kPositionEdgeTop,
[self judgePropValuePropValue:styles[@"top"] defaultValue:NAN]);
}
if (styles[@"left"]) {
_flexCssNode->setStylePosition(WeexCore::kPositionEdgeLeft,
[self judgePropValuePropValue:styles[@"left"] defaultValue:NAN]);
}
if(styles[@"right"]) {
_flexCssNode->setStylePosition(WeexCore::kPositionEdgeRight,
[self judgePropValuePropValue:styles[@"right"] defaultValue:NAN]);
}
if (styles[@"bottom"]) {
_flexCssNode->setStylePosition(WeexCore::kPositionEdgeBottom,
[self judgePropValuePropValue:styles[@"bottom"] defaultValue:NAN]);
}
// dimension
if (styles[@"width"]) {
_flexCssNode->setStyleWidth([self judgePropValuePropValue:styles[@"width"] defaultValue:NAN]
,isUpdate);
}
if (styles[@"height"]) {
_flexCssNode->setStyleHeight([self judgePropValuePropValue:styles[@"height"] defaultValue:NAN]);
}
if (styles[@"minWidth"]) {
_flexCssNode->setMinWidth([self judgePropValuePropValue:styles[@"minWidth"] defaultValue:NAN]
,isUpdate);
}
if (styles[@"minHeight"]) {
_flexCssNode->setMinHeight([self judgePropValuePropValue:styles[@"minHeight"] defaultValue:NAN]);
}
if (styles[@"maxWidth"]) {
_flexCssNode->setMaxWidth([self judgePropValuePropValue:styles[@"maxWidth"] defaultValue:NAN]
,isUpdate);
}
if (styles[@"maxHeight"]) {
_flexCssNode->setMaxHeight([self judgePropValuePropValue:styles[@"maxHeight"] defaultValue:NAN]);
}
// margin
if (styles[@"margin"]) {
_flexCssNode->setMargin(WeexCore::kMarginALL,
[self judgePropValuePropValue:styles[@"margin"] defaultValue:0]);
}
if (styles[@"marginTop"]) {
_flexCssNode->setMargin(WeexCore::kMarginTop,
[self judgePropValuePropValue:styles[@"marginTop"] defaultValue:0]);
}
if (styles[@"marginBottom"]) {
_flexCssNode->setMargin(WeexCore::kMarginBottom,
[self judgePropValuePropValue:styles[@"marginBottom"] defaultValue:0]);
}
if (styles[@"marginRight"]) {
_flexCssNode->setMargin(WeexCore::kMarginRight,
[self judgePropValuePropValue:styles[@"marginRight"] defaultValue:0]);
}
if (styles[@"marginLeft"]) {
_flexCssNode->setMargin(WeexCore::kMarginLeft,
[self judgePropValuePropValue:styles[@"marginLeft"] defaultValue:0]);
}
// border
if (styles[@"borderWidth"]) {
_flexCssNode->setBorderWidth(WeexCore::kBorderWidthALL,
[self judgePropValuePropValue:styles[@"borderWidth"] defaultValue:0]);
}
if (styles[@"borderTopWidth"]) {
_flexCssNode->setBorderWidth(WeexCore::kBorderWidthTop,
[self judgePropValuePropValue:styles[@"borderTopWidth"] defaultValue:0]);
}
if (styles[@"borderLeftWidth"]) {
_flexCssNode->setBorderWidth(WeexCore::kBorderWidthLeft,
[self judgePropValuePropValue:styles[@"borderLeftWidth"] defaultValue:0]);
}
if (styles[@"borderBottomWidth"]) {
_flexCssNode->setBorderWidth(WeexCore::kBorderWidthBottom,
[self judgePropValuePropValue:styles[@"borderBottomWidth"] defaultValue:0]);
}
if (styles[@"borderRightWidth"]) {
_flexCssNode->setBorderWidth(WeexCore::kBorderWidthRight,
[self judgePropValuePropValue:styles[@"borderRightWidth"] defaultValue:0]);
}
// padding
if (styles[@"padding"]) {
_flexCssNode->setPadding(WeexCore::kPaddingALL,
[self judgePropValuePropValue:styles[@"padding"] defaultValue:0]);
}
if (styles[@"paddingTop"]) {
_flexCssNode->setPadding(WeexCore::kPaddingTop,
[self judgePropValuePropValue:styles[@"paddingTop"] defaultValue:0]);
}
if (styles[@"paddingLeft"]) {
_flexCssNode->setPadding(WeexCore::kPaddingLeft,
[self judgePropValuePropValue:styles[@"paddingLeft"] defaultValue:0]);
}
if (styles[@"paddingBottom"]) {
_flexCssNode->setPadding(WeexCore::kPaddingBottom,
[self judgePropValuePropValue:styles[@"paddingBottom"] defaultValue:0]);
}
if (styles[@"paddingRight"]) {
_flexCssNode->setPadding(WeexCore::kPaddingRight,
[self judgePropValuePropValue:styles[@"paddingRight"] defaultValue:0]);
}
[self setNeedsLayout];
}
-(CGFloat)judgePropValuePropValue:(NSString *)propValue defaultValue:(CGFloat)defaultValue{
CGFloat convertValue = (CGFloat)[WXConvert WXFlexPixelType:propValue scaleFactor:self.weexInstance.pixelScaleFactor];
if (!isnan(convertValue)) {
return convertValue;
}
return defaultValue;
}
#define WX_FLEX_STYLE_RESET_CSS_NODE(key, defaultValue)\
do {\
WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_KEY(key,key,defaultValue)\
} while(0);
#define WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_KEY(judgeKey, propKey, defaultValue)\
do {\
if (styles && [styles containsObject:@#judgeKey]) {\
NSMutableDictionary *resetStyleDic = [[NSMutableDictionary alloc] init];\
[resetStyleDic setValue:defaultValue forKey:@#propKey];\
[self _updateCSSNodeStyles:resetStyleDic];\
[self setNeedsLayout];\
}\
} while(0);
#define WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(judgeKey, propTopKey,propLeftKey,propRightKey,propBottomKey, defaultValue)\
do {\
if (styles && [styles containsObject:@#judgeKey]) {\
NSMutableDictionary *resetStyleDic = [[NSMutableDictionary alloc] init];\
[resetStyleDic setValue:defaultValue forKey:@#propTopKey];\
[resetStyleDic setValue:defaultValue forKey:@#propLeftKey];\
[resetStyleDic setValue:defaultValue forKey:@#propRightKey];\
[resetStyleDic setValue:defaultValue forKey:@#propBottomKey];\
[self _updateCSSNodeStyles:resetStyleDic];\
[self setNeedsLayout];\
}\
} while(0);
- (void)_resetCSSNode:(NSArray *)styles
{
if (styles.count<=0) {
return;
}
WX_FLEX_STYLE_RESET_CSS_NODE(flex, @0.0)
WX_FLEX_STYLE_RESET_CSS_NODE(flexDirection, @(WeexCore::kFlexDirectionColumn))
WX_FLEX_STYLE_RESET_CSS_NODE(alignItems, @(WeexCore::kAlignItemsStretch))
WX_FLEX_STYLE_RESET_CSS_NODE(alignSelf, @(WeexCore::kAlignSelfAuto))
WX_FLEX_STYLE_RESET_CSS_NODE(flexWrap, @(WeexCore::kNoWrap))
WX_FLEX_STYLE_RESET_CSS_NODE(justifyContent, @(WeexCore::kJustifyFlexStart))
// position
WX_FLEX_STYLE_RESET_CSS_NODE(position, @(WeexCore::kRelative))
WX_FLEX_STYLE_RESET_CSS_NODE(top, @(NAN))
WX_FLEX_STYLE_RESET_CSS_NODE(left, @(NAN))
WX_FLEX_STYLE_RESET_CSS_NODE(right, @(NAN))
WX_FLEX_STYLE_RESET_CSS_NODE(bottom, @(NAN))
// dimension
WX_FLEX_STYLE_RESET_CSS_NODE(width, @(NAN))
WX_FLEX_STYLE_RESET_CSS_NODE(height, @(NAN))
WX_FLEX_STYLE_RESET_CSS_NODE(minWidth, @(NAN))
WX_FLEX_STYLE_RESET_CSS_NODE(minHeight, @(NAN))
WX_FLEX_STYLE_RESET_CSS_NODE(maxWidth, @(NAN))
WX_FLEX_STYLE_RESET_CSS_NODE(maxHeight, @(NAN))
// margin
WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(margin
,marginTop
,marginLeft
,marginRight
,marginBottom
, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(marginTop, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(marginLeft, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(marginRight, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(marginBottom, @(0.0))
// border
WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(borderWidth
, borderTopWidth
, borderLeftWidth
, borderRightWidth
, borderBottomWidth
, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(borderTopWidth, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(borderLeftWidth, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(borderRightWidth, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(borderBottomWidth, @(0.0))
// padding
WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(padding
, paddingTop
, paddingLeft
, paddingRight
, paddingBottom
, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(paddingTop, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(paddingLeft, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(paddingRight, @(0.0))
WX_FLEX_STYLE_RESET_CSS_NODE(paddingBottom, @(0.0))
}
#pragma mark CSS Node Override
static WeexCore::WXCoreSize flexCssNodeMeasure(WeexCore::WXCoreLayoutNode *node, float width, WeexCore::MeasureMode widthMeasureMode,float height, WeexCore::MeasureMode heightMeasureMode){
if (node->getContext() == nullptr) { //为空
return WeexCore::WXCoreSize();
}
WXComponent *component = (__bridge WXComponent *)(node->getContext());
if (![component respondsToSelector:@selector(measureBlock)]) {
return WeexCore::WXCoreSize();
}
CGSize (^measureBlock)(CGSize) = [component measureBlock];
if (!measureBlock) {
return WeexCore::WXCoreSize();
}
CGSize constrainedSize = CGSizeMake(width, height);
CGSize resultSize = measureBlock(constrainedSize);
#ifdef DEBUG
WXLogDebug(@"flexLayout -> measureblock %@, resultSize:%@",
component.type,
NSStringFromCGSize(resultSize)
);
#endif
WeexCore::WXCoreSize size;
size.height=(float)resultSize.height;
size.width=(float)resultSize.width;
return size;
}
-(WeexCore::WXCorePositionType)fxPositionType:(id)value
{
if([value isKindOfClass:[NSString class]]){
if ([value isEqualToString:@"absolute"]) {
return WeexCore::kAbsolute;
} else if ([value isEqualToString:@"relative"]) {
return WeexCore::kRelative;
} else if ([value isEqualToString:@"fixed"]) {
return WeexCore::kFixed;
} else if ([value isEqualToString:@"sticky"]) {
return WeexCore::kRelative;
}
}
return WeexCore::kRelative;
}
- (WeexCore::WXCoreFlexDirection)fxFlexDirection:(id)value
{
if([value isKindOfClass:[NSString class]]){
if ([value isEqualToString:@"column"]) {
return WeexCore::kFlexDirectionColumn;
} else if ([value isEqualToString:@"column-reverse"]) {
return WeexCore::kFlexDirectionColumnReverse;
} else if ([value isEqualToString:@"row"]) {
return WeexCore::kFlexDirectionRow;
} else if ([value isEqualToString:@"row-reverse"]) {
return WeexCore::kFlexDirectionRowReverse;
}
}
return WeexCore::kFlexDirectionColumn;
}
//TODO
- (WeexCore::WXCoreAlignItems)fxAlign:(id)value
{
if([value isKindOfClass:[NSString class]]){
if ([value isEqualToString:@"stretch"]) {
return WeexCore::kAlignItemsStretch;
} else if ([value isEqualToString:@"flex-start"]) {
return WeexCore::kAlignItemsFlexStart;
} else if ([value isEqualToString:@"flex-end"]) {
return WeexCore::kAlignItemsFlexEnd;
} else if ([value isEqualToString:@"center"]) {
return WeexCore::kAlignItemsCenter;
//return WXCoreFlexLayout::WXCore_AlignItems_Center;
} else if ([value isEqualToString:@"auto"]) {
// return YGAlignAuto;
} else if ([value isEqualToString:@"baseline"]) {
// return YGAlignBaseline;
}
}
return WeexCore::kAlignItemsStretch;
}
- (WeexCore::WXCoreAlignSelf)fxAlignSelf:(id)value
{
if([value isKindOfClass:[NSString class]]){
if ([value isEqualToString:@"stretch"]) {
return WeexCore::kAlignSelfStretch;
} else if ([value isEqualToString:@"flex-start"]) {
return WeexCore::kAlignSelfFlexStart;
} else if ([value isEqualToString:@"flex-end"]) {
return WeexCore::kAlignSelfFlexEnd;
} else if ([value isEqualToString:@"center"]) {
return WeexCore::kAlignSelfCenter;
} else if ([value isEqualToString:@"auto"]) {
return WeexCore::kAlignSelfAuto;
} else if ([value isEqualToString:@"baseline"]) {
// return YGAlignBaseline;
}
}
return WeexCore::kAlignSelfStretch;
}
- (WeexCore::WXCoreFlexWrap)fxWrap:(id)value
{
if([value isKindOfClass:[NSString class]]) {
if ([value isEqualToString:@"nowrap"]) {
return WeexCore::kNoWrap;
} else if ([value isEqualToString:@"wrap"]) {
return WeexCore::kWrap;
} else if ([value isEqualToString:@"wrap-reverse"]) {
return WeexCore::kWrapReverse;
}
}
return WeexCore::kNoWrap;
}
- (WeexCore::WXCoreJustifyContent)fxJustify:(id)value
{
if([value isKindOfClass:[NSString class]]){
if ([value isEqualToString:@"flex-start"]) {
return WeexCore::kJustifyFlexStart;
} else if ([value isEqualToString:@"center"]) {
return WeexCore::kJustifyCenter;
} else if ([value isEqualToString:@"flex-end"]) {
return WeexCore::kJustifyFlexEnd;
} else if ([value isEqualToString:@"space-between"]) {
return WeexCore::kJustifySpaceBetween;
} else if ([value isEqualToString:@"space-around"]) {
return WeexCore::kJustifySpaceAround;
}
}
return WeexCore::kJustifyFlexStart;
}
- (NSInteger) getActualNodeIndex:(WXComponent*)subcomponent atIndex:(NSInteger) index
{
NSInteger actualIndex = 0; //实际除去不需要布局的subComponent,此时所在的正确位置
for (WXComponent *child in _subcomponents) {
if ([child.ref isEqualToString:subcomponent.ref]) {
break;
}
if (child->_isNeedJoinLayoutSystem) {
actualIndex ++;
}
}
return actualIndex;
}
- (void)_insertChildCssNode:(WXComponent*)subcomponent atIndex:(NSInteger)index
{
self.flexCssNode->addChildAt(subcomponent.flexCssNode, (uint32_t)index);
}
- (void)_rmChildCssNode:(WXComponent *)subcomponent
{
self.flexCssNode->removeChild(subcomponent->_flexCssNode);
#ifdef DEBUG
WXLogDebug(@"flexLayout -> ref:%@ ,flexCssNode->removeChild ,childRef:%@",self.ref,subcomponent.ref);
#endif
}
+ (void) recycleNodeOnComponentThread:(WeexCore::WXCoreLayoutNode * ) garbageNode gabRef:(NSString *)ref {
if (nullptr == garbageNode) {
#ifdef DEBUG
WXLogDebug(@"flexlayout->recycle garbageNode ref:%@ is null ",ref);
#endif
return;
}
WXPerformBlockOnComponentThread(^{
#ifdef DEBUG
WXLogDebug(@"flexlayout->recycle ref:%@ ,node:%p",ref,garbageNode );
#endif
if(nullptr != garbageNode){
delete garbageNode;
}
});
//domthread
}
@end