blob: fd5eb886d49159ea1fbb0fc4a0f7302236a9ae5e [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"
#import "WXCoreBridge.h"
bool flexIsUndefined(float value) {
return isnan(value);
}
@implementation WXComponent (Layout)
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
#pragma mark Public
- (void)setNeedsLayout
{
if (_flexCssNode != nullptr) {
_flexCssNode->markDirty();
}
}
- (BOOL)needsLayout
{
if (_flexCssNode != nullptr) {
return _flexCssNode->isDirty();
}
else {
return false;
}
}
- (CGSize (^)(CGSize))measureBlock
{
return nil;
}
- (void)layoutDidFinish
{
WXAssertMainThread();
}
- (void)updateLayoutStyles:(NSDictionary*)styles
{
WXPerformBlockOnComponentThread(^{
[WXCoreBridge callUpdateStyle:self.weexInstance.instanceId ref:self.ref data:styles];
});
}
#pragma mark Private
- (void)_setRenderObject:(void *)object
{
if (object) {
_flexCssNode = static_cast<WeexCore::WXCoreLayoutNode*>(object);
_flexCssNode->setContext((__bridge void *)self); // bind
if ([self measureBlock]) {
_flexCssNode->setMeasureFunc(flexCssNodeMeasure);
}
}
else if (_flexCssNode) {
_flexCssNode->setContext(nullptr);
_flexCssNode = nullptr;
}
}
- (void)_updateCSSNodeStyles:(NSDictionary *)styles
{
[self _fillCSSNode:styles isUpdate:YES];
}
-(void)_resetCSSNodeStyles:(NSArray *)styles
{
[self _resetCSSNode:styles];
}
- (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++;
[self.weexInstance.apmInstance updateFSDiffStats:KEY_PAGE_STATS_CELL_EXCEED_NUM withDiffValue:1];
}
}
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;
}
WXBoxShadow* usingBoxShadow = [strongSelf _chooseBoxShadow];
if (!CGRectEqualToRect(strongSelf.view.frame,strongSelf.calculatedFrame)) {
strongSelf.view.frame = strongSelf.calculatedFrame;
strongSelf->_absolutePosition = CGPointMake(NAN, NAN);
[strongSelf configBoxShadow:usingBoxShadow];
} else {
if (![strongSelf equalBoxShadow:usingBoxShadow withBoxShadow:strongSelf->_lastBoxShadow]) {
[strongSelf configBoxShadow:usingBoxShadow];
}
}
[strongSelf _resetNativeBorderRadius];
if ([WXUtility enableRTLLayoutDirection]) {
if ([strongSelf isDirectionRTL] != strongSelf -> _isLastLayoutDirectionRTL) {
strongSelf -> _isLastLayoutDirectionRTL = [strongSelf isDirectionRTL];
[strongSelf _layoutDirectionDidChanged:[strongSelf isDirectionRTL]];
}
}
if (strongSelf->_transform) {
[strongSelf->_transform applyTransformForView:strongSelf.view];
}
[strongSelf _adjustForRTL];
if (strongSelf->_backgroundImage) {
[strongSelf setGradientLayer];
}
[strongSelf setNeedsDisplay];
}];
} else if ([WXUtility enableRTLLayoutDirection]) {
// if frame is not change, we still need check was layoutDirection changed
if ([self isDirectionRTL] != _isLastLayoutDirectionRTL) {
self -> _isLastLayoutDirectionRTL = [self isDirectionRTL];
__weak typeof(self) weakSelf = self;
[self.weexInstance.componentManager _addUITask:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf _layoutDirectionDidChanged:[strongSelf isDirectionRTL]];
if (strongSelf->_transform) {
[strongSelf->_transform applyTransformForView:strongSelf.view];
}
[strongSelf _adjustForRTL];
}];
}
}
}
- (void)_layoutDirectionDidChanged:(BOOL)isRTL {
WXAssertMainThread();
[self layoutDirectionDidChanged:isRTL];
}
- (void)layoutDirectionDidChanged:(BOOL)isRTL {
}
- (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
{
if (_flexCssNode == nullptr) {
return;
}
BOOL needLayout = NO;
// CSS direction for RTL Layout
if (styles[@"direction"]) {
_flexCssNode->setDirection([self fxDirection:styles[@"direction"]], isUpdate);
needLayout = YES;
}
// flex
if (styles[@"flex"]) {
_flexCssNode->set_flex([WXConvert CGFloat:styles[@"flex"]]);
needLayout = YES;
}
if (isnan(_flexCssNode->getFlex())) {
// to make the default flex value is zero, yoga is nan, maybe this can configured by yoga config
_flexCssNode->set_flex(0);
needLayout = YES;
}
if (styles[@"flexDirection"]) {
_flexCssNode->setFlexDirection([self fxFlexDirection:styles[@"flexDirection"]], isUpdate);
needLayout = YES;
}
if (styles[@"alignItems"]) {
_flexCssNode->setAlignItems([self fxAlign:styles[@"alignItems"]]);
needLayout = YES;
}
if (styles[@"alignSelf"]) {
_flexCssNode->setAlignSelf([self fxAlignSelf:styles[@"alignSelf"]]);
needLayout = YES;
}
if (styles[@"flexWrap"]) {
_flexCssNode->setFlexWrap([self fxWrap:styles[@"flexWrap"]]);
needLayout = YES;
}
if (styles[@"justifyContent"]) {
_flexCssNode->setJustifyContent([self fxJustify:styles[@"justifyContent"]]);
needLayout = YES;
}
// position
if (styles[@"position"]) {
_flexCssNode->setStylePositionType([self fxPositionType:styles[@"position"]]);
needLayout = YES;
}
if (styles[@"top"]) {
_flexCssNode->setStylePosition(WeexCore::kPositionEdgeTop,
[self judgePropValuePropValue:styles[@"top"] defaultValue:NAN]);
needLayout = YES;
}
if (styles[@"left"]) {
_flexCssNode->setStylePosition(WeexCore::kPositionEdgeLeft,
[self judgePropValuePropValue:styles[@"left"] defaultValue:NAN]);
needLayout = YES;
}
if(styles[@"right"]) {
_flexCssNode->setStylePosition(WeexCore::kPositionEdgeRight,
[self judgePropValuePropValue:styles[@"right"] defaultValue:NAN]);
needLayout = YES;
}
if (styles[@"bottom"]) {
_flexCssNode->setStylePosition(WeexCore::kPositionEdgeBottom,
[self judgePropValuePropValue:styles[@"bottom"] defaultValue:NAN]);
needLayout = YES;
}
// dimension
if (styles[@"width"]) {
_flexCssNode->setStyleWidth([self judgePropValuePropValue:styles[@"width"] defaultValue:NAN], isUpdate);
needLayout = YES;
}
if (styles[@"height"]) {
_flexCssNode->setStyleHeight([self judgePropValuePropValue:styles[@"height"] defaultValue:NAN]);
needLayout = YES;
}
if (styles[@"minWidth"]) {
_flexCssNode->setMinWidth([self judgePropValuePropValue:styles[@"minWidth"] defaultValue:NAN], isUpdate);
needLayout = YES;
}
if (styles[@"minHeight"]) {
_flexCssNode->setMinHeight([self judgePropValuePropValue:styles[@"minHeight"] defaultValue:NAN]);
needLayout = YES;
}
if (styles[@"maxWidth"]) {
_flexCssNode->setMaxWidth([self judgePropValuePropValue:styles[@"maxWidth"] defaultValue:NAN], isUpdate);
needLayout = YES;
}
if (styles[@"maxHeight"]) {
_flexCssNode->setMaxHeight([self judgePropValuePropValue:styles[@"maxHeight"] defaultValue:NAN]);
needLayout = YES;
}
// margin
if (styles[@"margin"]) {
_flexCssNode->setMargin(WeexCore::kMarginALL,
[self judgePropValuePropValue:styles[@"margin"] defaultValue:0]);
needLayout = YES;
}
if (styles[@"marginTop"]) {
_flexCssNode->setMargin(WeexCore::kMarginTop,
[self judgePropValuePropValue:styles[@"marginTop"] defaultValue:0]);
needLayout = YES;
}
if (styles[@"marginBottom"]) {
_flexCssNode->setMargin(WeexCore::kMarginBottom,
[self judgePropValuePropValue:styles[@"marginBottom"] defaultValue:0]);
needLayout = YES;
}
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]);
needLayout = YES;
}
// border
if (styles[@"borderWidth"]) {
_flexCssNode->setBorderWidth(WeexCore::kBorderWidthALL,
[self judgePropValuePropValue:styles[@"borderWidth"] defaultValue:0]);
needLayout = YES;
}
if (styles[@"borderTopWidth"]) {
_flexCssNode->setBorderWidth(WeexCore::kBorderWidthTop,
[self judgePropValuePropValue:styles[@"borderTopWidth"] defaultValue:0]);
needLayout = YES;
}
if (styles[@"borderLeftWidth"]) {
_flexCssNode->setBorderWidth(WeexCore::kBorderWidthLeft,
[self judgePropValuePropValue:styles[@"borderLeftWidth"] defaultValue:0]);
needLayout = YES;
}
if (styles[@"borderBottomWidth"]) {
_flexCssNode->setBorderWidth(WeexCore::kBorderWidthBottom,
[self judgePropValuePropValue:styles[@"borderBottomWidth"] defaultValue:0]);
needLayout = YES;
}
if (styles[@"borderRightWidth"]) {
_flexCssNode->setBorderWidth(WeexCore::kBorderWidthRight,
[self judgePropValuePropValue:styles[@"borderRightWidth"] defaultValue:0]);
needLayout = YES;
}
// padding
if (styles[@"padding"]) {
_flexCssNode->setPadding(WeexCore::kPaddingALL,
[self judgePropValuePropValue:styles[@"padding"] defaultValue:0]);
needLayout = YES;
}
if (styles[@"paddingTop"]) {
_flexCssNode->setPadding(WeexCore::kPaddingTop,
[self judgePropValuePropValue:styles[@"paddingTop"] defaultValue:0]);
needLayout = YES;
}
if (styles[@"paddingLeft"]) {
_flexCssNode->setPadding(WeexCore::kPaddingLeft,
[self judgePropValuePropValue:styles[@"paddingLeft"] defaultValue:0]);
needLayout = YES;
}
if (styles[@"paddingBottom"]) {
_flexCssNode->setPadding(WeexCore::kPaddingBottom,
[self judgePropValuePropValue:styles[@"paddingBottom"] defaultValue:0]);
needLayout = YES;
}
if (styles[@"paddingRight"]) {
_flexCssNode->setPadding(WeexCore::kPaddingRight,
[self judgePropValuePropValue:styles[@"paddingRight"] defaultValue:0]);
needLayout = YES;
}
if (needLayout) {
[self setNeedsLayout];
}
}
- (CGFloat)judgePropValuePropValue:(id)propValue defaultValue:(CGFloat)defaultValue
{
CGFloat convertValue = (CGFloat)[WXConvert WXFlexPixelType:propValue scaleFactor:self.weexInstance.pixelScaleFactor];
if (!isnan(convertValue)) {
return convertValue;
}
return defaultValue;
}
- (float)getCssStyleValueForKey:(NSString *)key
{
/*
* width, height, min-width, min-height, max-width, max-height,
* margin-(left/right/top/bottom)
* padding-(left/right/top/bottom)
* border-(left/right/top/bottom)-width
* left, right, top, bottom
* flex-grow
*/
WXAssert(_flexCssNode != nullptr, @"Css node is null.");
if (_flexCssNode == nullptr) {
return NAN;
}
std::string ckey = [key UTF8String];
if (ckey == "width") return _flexCssNode->getStyleWidth();
if (ckey == "height") return _flexCssNode->getStyleHeight();
if (ckey == "min-width") return _flexCssNode->getMinWidth();
if (ckey == "min-height") return _flexCssNode->getMinHeight();
if (ckey == "max-width") return _flexCssNode->getMaxWidth();
if (ckey == "max-height") return _flexCssNode->getMaxHeight();
if (ckey == "margin-left") return _flexCssNode->getMarginLeft();
if (ckey == "margin-right") return _flexCssNode->getMarginRight();
if (ckey == "margin-top") return _flexCssNode->getMarginTop();
if (ckey == "margin-bottom") return _flexCssNode->getMarginBottom();
if (ckey == "padding-left") return _flexCssNode->getPaddingLeft();
if (ckey == "padding-right") return _flexCssNode->getPaddingRight();
if (ckey == "padding-top") return _flexCssNode->getPaddingTop();
if (ckey == "padding-bottom") return _flexCssNode->getPaddingBottom();
if (ckey == "border-left-width") return _flexCssNode->getBorderWidthLeft();
if (ckey == "border-right-width") return _flexCssNode->getBorderWidthRight();
if (ckey == "border-top-width") return _flexCssNode->getBorderWidthTop();
if (ckey == "border-bottom-width") return _flexCssNode->getBorderWidthBottom();
if (ckey == "left") return _flexCssNode->getStylePositionLeft();
if (ckey == "right") return _flexCssNode->getStylePositionRight();
if (ckey == "top") return _flexCssNode->getStylePositionTop();
if (ckey == "bottom") return _flexCssNode->getStylePositionBottom();
if (ckey == "flex-grow") return _flexCssNode->getFlex();
WXAssert(NO, @"Invalid css style key %@", key);
return NAN;
}
- (WXCoreFlexDirection)getCssStyleFlexDirection
{
WXAssert(_flexCssNode != nullptr, @"Css node is null.");
return _flexCssNode ? _flexCssNode->getFlexDirection() : kFlexDirectionColumn;
}
- (WXCoreFlexWrap)getCssStyleFlexWrap
{
WXAssert(_flexCssNode != nullptr, @"Css node is null.");
return _flexCssNode ? _flexCssNode->getFlexWrap() : kNoWrap;
}
- (WXCoreJustifyContent)getCssStyleJustifyContent
{
WXAssert(_flexCssNode != nullptr, @"Css node is null.");
return _flexCssNode ? _flexCssNode->getJustifyContent() : kJustifyFlexStart;
}
- (WXCoreAlignItems)getCssStyleAlignItems
{
WXAssert(_flexCssNode != nullptr, @"Css node is null.");
return _flexCssNode ? _flexCssNode->getAlignItems() : kAlignItemsStretch;
}
- (WXCoreAlignSelf)getCssStyleAlignSelf
{
WXAssert(_flexCssNode != nullptr, @"Css node is null.");
return _flexCssNode ? _flexCssNode->getAlignSelf() : kAlignSelfAuto;
}
- (WXCorePositionType)getCssStylePositionType
{
WXAssert(_flexCssNode != nullptr, @"Css node is null.");
return _flexCssNode ? _flexCssNode->getStylePositionType() : kRelative;
}
- (WXCoreDirection)getCssDirection
{
WXAssert(_flexCssNode != nullptr, @"Css node is null.");
return _flexCssNode ? _flexCssNode->getDirection() : WEEXCORE_CSS_DEFAULT_DIRECTION;
}
- (NSString*)convertLayoutValueToStyleValue:(NSString*)valueName
{
if (_flexCssNode == nullptr) {
return @"0";
}
float layoutValue = 0;
if ([valueName isEqualToString:@"left"])
layoutValue = _flexCssNode->getLayoutPositionLeft();
else if ([valueName isEqualToString:@"right"])
layoutValue = _flexCssNode->getLayoutPositionRight();
else if ([valueName isEqualToString:@"top"])
layoutValue = _flexCssNode->getLayoutPositionTop();
else if ([valueName isEqualToString:@"bottom"])
layoutValue = _flexCssNode->getLayoutPositionBottom();
else if ([valueName isEqualToString:@"width"])
layoutValue = _flexCssNode->getLayoutWidth();
else if ([valueName isEqualToString:@"height"])
layoutValue = _flexCssNode->getLayoutHeight();
else
return @"0";
layoutValue /= self.weexInstance.pixelScaleFactor;
return [NSString stringWithFormat:@"%f", layoutValue];
}
- (CGFloat)safeContainerStyleWidth
{
if (_flexCssNode == nullptr) {
return 0.0f;
}
CGFloat thisValue = _flexCssNode->getStyleWidth();
if (isnan(thisValue)) {
if (_flexCssNode->getParent()) {
thisValue = _flexCssNode->getParent()->getLayoutWidth(); // parent may be layout done
if (isnan(thisValue)) {
thisValue = _flexCssNode->getParent()->getStyleWidth();
}
}
}
if (isnan(thisValue)) {
thisValue = self.weexInstance.frame.size.width;
}
if (isnan(thisValue) || thisValue == 0.0f) {
thisValue = [UIScreen mainScreen].bounds.size.width;
}
return thisValue;
}
#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(direction, @(WeexCore::kDirectionInherit))
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::WXCoreDirection)fxDirection:(id)value
{
if([value isKindOfClass:[NSString class]]){
if ([value isEqualToString:@"rtl"]) {
return WeexCore::kDirectionRTL;
} else if ([value isEqualToString:@"ltr"]) {
return WeexCore::kDirectionLTR;
}
}
return WeexCore::kDirectionInherit;
}
- (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"]) {//!OCLint
// return YGAlignAuto;
} else if ([value isEqualToString:@"baseline"]) {//!OCLint
// 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"]) {//!OCLint
// 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;
}
- (void)removeSubcomponentCssNode:(WXComponent *)subcomponent
{
auto node = subcomponent->_flexCssNode;
if (node) {
if (_flexCssNode) {
_flexCssNode->removeChild(node);
}
[subcomponent _setRenderObject:nullptr];
// unbind subcomponents of subcomponent
NSMutableArray* sub_subcomponents = [[NSMutableArray alloc] init];
[subcomponent _collectSubcomponents:sub_subcomponents];
for (WXComponent* c in sub_subcomponents) {
[c _setRenderObject:nullptr];
}
[WXCoreBridge removeRenderObjectFromMap:subcomponent.weexInstance.instanceId object:node];
delete node; // also will delete all children recursively
}
}
#pragma mark - RTL
- (BOOL)isDirectionRTL {
if (![WXUtility enableRTLLayoutDirection]) return NO;
return _isLayoutDirectionRTL;
}
- (void)_adjustForRTL {
if (![WXUtility enableRTLLayoutDirection]) return;
if (self->_positionType == WXPositionTypeFixed) return;
if (self.supercomponent && self.supercomponent.isDirectionRTL && [self.supercomponent shouldTransformSubviewsWhenRTL]) {
if (_transform) {
self.view.layer.transform = CATransform3DConcat(self.view.layer.transform, CATransform3DScale(CATransform3DIdentity, -1, 1, 1));
} else {
self.view.layer.transform = CATransform3DScale(CATransform3DIdentity, -1, 1, 1);
}
} else {
if (!_transform) {
self.view.layer.transform = CATransform3DIdentity;
}
}
}
// Now we scrollView RTL solution is tranform
// so scrollView need tranform subviews when RTL by default
// if your component view is not scrollView but also implement RTL layout by tranform,you need return YES
- (BOOL)shouldTransformSubviewsWhenRTL {
return [self.view isKindOfClass:[UIScrollView class]];
}
- (void)_setIsLayoutRTL:(BOOL)isRTL {
_isLayoutDirectionRTL = isRTL;
}
@end