blob: b7a522a03570ac83203dca1434843b6692c2aafd [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 "WXScrollerComponent.h"
#import "WXComponent_internal.h"
#import "WXComponent.h"
#import "WXDefine.h"
#import "WXConvert.h"
#import "WXSDKInstance.h"
#import "WXUtility.h"
#import "WXLoadingComponent.h"
#import "WXRefreshComponent.h"
@interface WXScrollerComponnetView:UIScrollView
@end
@implementation WXScrollerComponnetView
@end;
@interface WXScrollerComponnetView(WXScrollerComponnetView_ContentInsetAdjustmentBehavior)
@property(nonatomic, assign)NSUInteger contentInsetAdjustmentBehavior;
@end
@interface WXScrollToTarget : NSObject
@property (nonatomic, weak) WXComponent *target;
@property (nonatomic, assign) BOOL hasAppear;
@end
@implementation WXScrollToTarget
@end
@interface WXScrollerComponent()
@property (nonatomic, strong) NSMutableArray * stickyArray;
@property (nonatomic, strong) NSMutableArray * listenerArray;
@property (nonatomic, weak) WXRefreshComponent *refreshComponent;
@property (nonatomic, weak) WXLoadingComponent *loadingComponent;
@end
@implementation WXScrollerComponent
{
CGSize _contentSize;
BOOL _listenLoadMore;
BOOL _scrollEvent;
CGFloat _loadMoreOffset;
CGFloat _previousLoadMoreContentHeight;
CGFloat _offsetAccuracy;
CGPoint _lastContentOffset;
CGPoint _lastScrollEventFiredOffset;
BOOL _scrollable;
NSString * _alwaysScrollableVertical;
NSString * _alwaysScrollableHorizontal;
// vertical & horizontal
WXScrollDirection _scrollDirection;
// left & right & up & down
NSString *_direction;
BOOL _showScrollBar;
BOOL _pagingEnabled;
css_node_t *_scrollerCSSNode;
NSHashTable* _delegates;
}
WX_EXPORT_METHOD(@selector(resetLoadmore))
- (void)resetLoadmore
{
_previousLoadMoreContentHeight=0;
}
- (css_node_t *)scrollerCSSNode
{
return _scrollerCSSNode;
}
- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
{
[super _insertSubcomponent:subcomponent atIndex:index];
if ([subcomponent isKindOfClass:[WXRefreshComponent class]]) {
_refreshComponent = (WXRefreshComponent*)subcomponent;
}
else if ([subcomponent isKindOfClass:[WXLoadingComponent class]]) {
_loadingComponent = (WXLoadingComponent*)subcomponent;
}
}
-(instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
{
self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
if (self) {
_stickyArray = [NSMutableArray array];
_listenerArray = [NSMutableArray array];
_scrollEvent = NO;
_lastScrollEventFiredOffset = CGPointMake(0, 0);
_scrollDirection = attributes[@"scrollDirection"] ? [WXConvert WXScrollDirection:attributes[@"scrollDirection"]] : WXScrollDirectionVertical;
_showScrollBar = attributes[@"showScrollbar"] ? [WXConvert BOOL:attributes[@"showScrollbar"]] : YES;
if (attributes[@"alwaysScrollableVertical"]) {
_alwaysScrollableVertical = [WXConvert NSString:attributes[@"alwaysScrollableVertical"]];
}
if (attributes[@"alwaysScrollableHorizontal"]) {
_alwaysScrollableHorizontal = [WXConvert NSString:attributes[@"alwaysScrollableHorizontal"]];
}
_pagingEnabled = attributes[@"pagingEnabled"] ? [WXConvert BOOL:attributes[@"pagingEnabled"]] : NO;
_loadMoreOffset = attributes[@"loadmoreoffset"] ? [WXConvert WXPixelType:attributes[@"loadmoreoffset"] scaleFactor:self.weexInstance.pixelScaleFactor] : 0;
_loadmoreretry = attributes[@"loadmoreretry"] ? [WXConvert NSUInteger:attributes[@"loadmoreretry"]] : 0;
_listenLoadMore = [events containsObject:@"loadmore"];
_scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
_offsetAccuracy = attributes[@"offsetAccuracy"] ? [WXConvert WXPixelType:attributes[@"offsetAccuracy"] scaleFactor:self.weexInstance.pixelScaleFactor] : 0;
_scrollerCSSNode = new_css_node();
// let scroller fill the rest space if it is a child component and has no fixed height & width
if (((_scrollDirection == WXScrollDirectionVertical &&
isUndefined(self.cssNode->style.dimensions[CSS_HEIGHT])) ||
(_scrollDirection == WXScrollDirectionHorizontal &&
isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]))) &&
self.cssNode->style.flex <= 0.0) {
self.cssNode->style.flex = 1.0;
}
}
return self;
}
- (UIView *)loadView
{
return [[WXScrollerComponnetView alloc] init];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self setContentSize:_contentSize];
WXScrollerComponnetView* scrollView = (WXScrollerComponnetView *)self.view;
scrollView.delegate = self;
scrollView.exclusiveTouch = YES;
scrollView.autoresizesSubviews = NO;
scrollView.clipsToBounds = YES;
scrollView.showsVerticalScrollIndicator = _showScrollBar;
scrollView.showsHorizontalScrollIndicator = _showScrollBar;
scrollView.scrollEnabled = _scrollable;
scrollView.pagingEnabled = _pagingEnabled;
if (_alwaysScrollableHorizontal) {
scrollView.alwaysBounceHorizontal = [WXConvert BOOL:_alwaysScrollableHorizontal];
}
if (_alwaysScrollableVertical) {
scrollView.alwaysBounceVertical = [WXConvert BOOL:_alwaysScrollableVertical];
}
if (WX_SYS_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0")) {
// now use the runtime to forbid the contentInset being Adjusted.
// here we add a category for scoller component view class compatible for new API,
// as we are concerning about weexSDK build as framework by Xcode8, using in Xcode9 project,
// so the the macro __IPHONE_11_0 will be useless in this case.
scrollView.contentInsetAdjustmentBehavior = 2;
}
if (self.ancestorScroller) {
scrollView.scrollsToTop = NO;
} else {
scrollView.scrollsToTop = YES;
}
}
- (void)layoutDidFinish
{
if ([self isViewLoaded]) {
[self setContentSize:_contentSize];
[self adjustSticky];
[self handleAppear];
}
[_loadingComponent resizeFrame];
}
- (void)viewWillUnload
{
((UIScrollView *)_view).delegate = nil;
}
- (void)dealloc
{
[self.stickyArray removeAllObjects];
[self.listenerArray removeAllObjects];
free(_scrollerCSSNode);
}
- (void)updateAttributes:(NSDictionary *)attributes
{
if (attributes[@"showScrollbar"]) {
_showScrollBar = [WXConvert BOOL:attributes[@"showScrollbar"]];
((UIScrollView *)self.view).showsHorizontalScrollIndicator = _showScrollBar;
((UIScrollView *)self.view).showsVerticalScrollIndicator = _showScrollBar;
}
if (attributes[@"pagingEnabled"]) {
_pagingEnabled = [WXConvert BOOL:attributes[@"pagingEnabled"]];
((UIScrollView *)self.view).pagingEnabled = _pagingEnabled;
}
if (attributes[@"loadmoreoffset"]) {
_loadMoreOffset = [WXConvert WXPixelType:attributes[@"loadmoreoffset"] scaleFactor:self.weexInstance.pixelScaleFactor];
}
if (attributes[@"loadmoreretry"]) {
NSUInteger loadmoreretry = [WXConvert NSUInteger:attributes[@"loadmoreretry"]];
if (loadmoreretry != _loadmoreretry) {
_previousLoadMoreContentHeight = 0;
}
self.loadmoreretry = loadmoreretry;
}
if (attributes[@"scrollable"]) {
_scrollable = attributes[@"scrollable"] ? [WXConvert BOOL:attributes[@"scrollable"]] : YES;
((UIScrollView *)self.view).scrollEnabled = _scrollable;
}
if (attributes[@"alwaysScrollableHorizontal"]) {
_alwaysScrollableHorizontal = [WXConvert NSString:attributes[@"alwaysScrollableHorizontal"]];
((UIScrollView*)self.view).alwaysBounceHorizontal = [WXConvert BOOL:_alwaysScrollableHorizontal];
}
if (attributes[@"alwaysScrollableVertical"]) {
_alwaysScrollableVertical = [WXConvert NSString:attributes[@"alwaysScrollableVertical"]];
((UIScrollView*)self.view).alwaysBounceVertical = [WXConvert BOOL:_alwaysScrollableVertical];
}
if (attributes[@"offsetAccuracy"]) {
_offsetAccuracy = [WXConvert WXPixelType:attributes[@"offsetAccuracy"] scaleFactor:self.weexInstance.pixelScaleFactor];
}
}
- (void)addEvent:(NSString *)eventName
{
if ([eventName isEqualToString:@"loadmore"]) {
_listenLoadMore = YES;
}
if ([eventName isEqualToString:@"scroll"]) {
_scrollEvent = YES;
}
}
- (void)removeEvent:(NSString *)eventName
{
if ([eventName isEqualToString:@"loadmore"]) {
_listenLoadMore = NO;
}
if ([eventName isEqualToString:@"scroll"]) {
_scrollEvent = NO;
}
}
#pragma mark WXScrollerProtocol
- (void)addStickyComponent:(WXComponent *)sticky
{
if(![self.stickyArray containsObject:sticky]) {
[self.stickyArray addObject:sticky];
[self adjustSticky];
}
}
- (void)removeStickyComponent:(WXComponent *)sticky
{
if([self.stickyArray containsObject:sticky]) {
[self.stickyArray removeObject:sticky];
[self adjustSticky];
}
}
- (void)adjustSticky
{
if (![self isViewLoaded]) {
return;
}
CGFloat scrollOffsetY = ((UIScrollView *)self.view).contentOffset.y;
for(WXComponent *component in self.stickyArray) {
if (isnan(component->_absolutePosition.x) && isnan(component->_absolutePosition.y)) {
component->_absolutePosition = [component.supercomponent.view convertPoint:component.view.frame.origin toView:self.view];
}
CGPoint relativePosition = component->_absolutePosition;
if (isnan(relativePosition.y)) {
continue;
}
WXComponent *supercomponent = component.supercomponent;
if(supercomponent != self && component.view.superview != self.view) {
[component.view removeFromSuperview];
[self.view addSubview:component.view];
} else {
[self.view bringSubviewToFront:component.view];
}
CGFloat relativeY = relativePosition.y;
BOOL needSticky = NO;
if (scrollOffsetY >= relativeY) {
needSticky = YES;
} else {
// important: reset views' frame
component.view.frame = CGRectMake(relativePosition.x, relativePosition.y, component.calculatedFrame.size.width, component.calculatedFrame.size.height);
}
if (!needSticky) {
continue;
}
// The minimum Y sticky view can reach is its original position
CGFloat minY = relativeY;
CGPoint superRelativePosition = supercomponent == self ? CGPointZero : [supercomponent.supercomponent.view convertPoint:supercomponent.view.frame.origin toView:self.view];
CGFloat maxY = superRelativePosition.y + supercomponent.calculatedFrame.size.height - component.calculatedFrame.size.height;
CGFloat stickyY = scrollOffsetY;
if (stickyY < minY) {
stickyY = minY;
} else if (stickyY > maxY && ![supercomponent conformsToProtocol:@protocol(WXScrollerProtocol)]) {
// Sticky component can not go beyond its parent's bounds when its parent is not scroller;
stickyY = maxY;
}
UIView *stickyView = component.view;
CGPoint origin = stickyView.frame.origin;
origin.y = stickyY;
stickyView.frame = (CGRect){origin,stickyView.frame.size};
}
}
- (void)addScrollToListener:(WXComponent *)target
{
BOOL has = NO;
for (WXScrollToTarget *targetData in self.listenerArray) {
if (targetData.target == target) {
has = YES;
break;
}
}
if (!has) {
WXScrollToTarget *scrollTarget = [[WXScrollToTarget alloc] init];
scrollTarget.target = target;
scrollTarget.hasAppear = NO;
[self.listenerArray addObject:scrollTarget];
}
}
- (void)removeScrollToListener:(WXComponent *)target
{
WXScrollToTarget *targetData = nil;
for (WXScrollToTarget *targetData in self.listenerArray) {
if (targetData.target == target) {
break;
}
}
if(targetData) {
[self.listenerArray removeObject:targetData];
}
}
- (void)scrollToComponent:(WXComponent *)component withOffset:(CGFloat)offset animated:(BOOL)animated
{
UIScrollView *scrollView = (UIScrollView *)self.view;
CGPoint contentOffset = scrollView.contentOffset;
CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
if (_scrollDirection == WXScrollDirectionHorizontal) {
CGFloat contentOffetX = [component.supercomponent.view convertPoint:component.view.frame.origin toView:self.view].x;
contentOffetX += offset * scaleFactor;
if (scrollView.contentSize.width >= scrollView.frame.size.width && contentOffetX > scrollView.contentSize.width - scrollView.frame.size.width) {
contentOffset.x = scrollView.contentSize.width - scrollView.frame.size.width;
} else {
contentOffset.x = contentOffetX;
}
} else {
CGFloat contentOffetY = [component.supercomponent.view convertPoint:component.view.frame.origin toView:self.view].y;
contentOffetY += offset * scaleFactor;
if (scrollView.contentSize.height >= scrollView.frame.size.height && contentOffetY > scrollView.contentSize.height - scrollView.frame.size.height) {
contentOffset.y = scrollView.contentSize.height - scrollView.frame.size.height;
} else {
contentOffset.y = contentOffetY;
}
}
[scrollView setContentOffset:contentOffset animated:animated];
}
- (BOOL)isNeedLoadMore
{
if (_loadMoreOffset >= 0.0 && ((UIScrollView *)self.view).contentOffset.y >= 0) {
return _previousLoadMoreContentHeight != ((UIScrollView *)self.view).contentSize.height && ((UIScrollView *)self.view).contentSize.height - ((UIScrollView *)self.view).contentOffset.y - self.view.frame.size.height <= _loadMoreOffset;
}
return NO;
}
- (void)loadMore
{
[self fireEvent:@"loadmore" params:nil];
_previousLoadMoreContentHeight = ((UIScrollView *)self.view).contentSize.height;
}
- (CGPoint)contentOffset
{
CGPoint rtv = CGPointZero;
UIScrollView *scrollView = (UIScrollView *)self.view;
if (scrollView) {
rtv = scrollView.contentOffset;
}
return rtv;
}
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
{
UIScrollView *scrollView = (UIScrollView *)self.view;
[scrollView setContentOffset:contentOffset animated:animated];
}
- (CGSize)contentSize
{
return ((UIScrollView *)self.view).contentSize;
}
- (void)setContentSize:(CGSize)size
{
UIScrollView *scrollView = (UIScrollView *)self.view;
scrollView.contentSize = size;
}
- (UIEdgeInsets)contentInset
{
UIEdgeInsets rtv = UIEdgeInsetsZero;
UIScrollView *scrollView = (UIScrollView *)self.view;
if (scrollView) {
rtv = scrollView.contentInset;
}
return rtv;
}
- (void)setContentInset:(UIEdgeInsets)contentInset
{
UIScrollView *scrollView = (UIScrollView *)self.view;
[scrollView setContentInset:contentInset];
}
- (void)addScrollDelegate:(id<UIScrollViewDelegate>)delegate
{
if (delegate) {
if (!_delegates) {
_delegates = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
}
[_delegates addObject:delegate];
}
}
- (void)removeScrollDelegate:(id<UIScrollViewDelegate>)delegate
{
if (delegate) {
[_delegates removeObject:delegate];
}
}
- (WXScrollDirection)scrollDirection
{
return _scrollDirection;
}
#pragma mark UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//apply block which are registered
WXSDKInstance *instance = self.weexInstance;
if ([self.ref isEqualToString:WX_SDK_ROOT_REF] &&
[self isKindOfClass:[WXScrollerComponent class]]) {
if (instance.onScroll) {
instance.onScroll(scrollView.contentOffset);
}
}
if (_lastContentOffset.x > scrollView.contentOffset.x) {
_direction = @"right";
} else if (_lastContentOffset.x < scrollView.contentOffset.x) {
_direction = @"left";
} else if(_lastContentOffset.y > scrollView.contentOffset.y) {
_direction = @"down";
} else if(_lastContentOffset.y < scrollView.contentOffset.y) {
_direction = @"up";
[self handleLoadMore];
}
CGFloat scaleFactor = self.weexInstance.pixelScaleFactor;
[_refreshComponent pullingdown:@{
REFRESH_DISTANCE_Y: @(fabs((scrollView.contentOffset.y - _lastContentOffset.y)/scaleFactor)),
REFRESH_VIEWHEIGHT: @(_refreshComponent.view.frame.size.height/scaleFactor),
REFRESH_PULLINGDISTANCE: @(scrollView.contentOffset.y/scaleFactor),
@"type":@"pullingdown"
}];
_lastContentOffset = scrollView.contentOffset;
// check sticky
[self adjustSticky];
[self handleAppear];
if (self.onScroll) {
self.onScroll(scrollView);
}
if (_scrollEvent) {
NSDictionary *contentSizeData = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithFloat:scrollView.contentSize.width / scaleFactor],@"width",[NSNumber numberWithFloat:scrollView.contentSize.height / scaleFactor],@"height", nil];
//contentOffset values are replaced by (-contentOffset.x,-contentOffset.y) ,in order to be consistent with Android client.
NSDictionary *contentOffsetData = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithFloat:-scrollView.contentOffset.x / scaleFactor],@"x",[NSNumber numberWithFloat:-scrollView.contentOffset.y / scaleFactor],@"y", nil];
CGFloat distance = 0;
if (_scrollDirection == WXScrollDirectionHorizontal) {
distance = scrollView.contentOffset.x - _lastScrollEventFiredOffset.x;
} else {
distance = scrollView.contentOffset.y - _lastScrollEventFiredOffset.y;
}
if (fabs(distance) >= _offsetAccuracy) {
[self fireEvent:@"scroll" params:@{@"contentSize":contentSizeData,@"contentOffset":contentOffsetData} domChanges:nil];
_lastScrollEventFiredOffset = scrollView.contentOffset;
}
}
for (id<UIScrollViewDelegate> delegate in _delegates) {
if ([delegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
[delegate scrollViewDidScroll:scrollView];
}
}
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
UIEdgeInsets inset = [scrollView contentInset];
// currently only set contentInset when loading
// if ([_refreshComponent displayState]) {
// inset.top = _refreshComponent.view.frame.size.height;
// }
// else {
// inset.top = 0;
// }
if ([_loadingComponent displayState]) {
inset.bottom = _loadingComponent.view.frame.size.height;
} else {
inset.bottom = 0;
}
[scrollView setContentInset:inset];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
[_loadingComponent.view setHidden:NO];
[_refreshComponent.view setHidden:NO];
//refresh
if (_refreshComponent && scrollView.contentOffset.y < 0 && scrollView.contentOffset.y + _refreshComponent.calculatedFrame.size.height < _refreshComponent.calculatedFrame.origin.y) {
[_refreshComponent refresh];
}
//loading
if (_loadingComponent && scrollView.contentOffset.y > 0 &&
scrollView.contentOffset.y + scrollView.frame.size.height > _loadingComponent.view.frame.origin.y + _loadingComponent.calculatedFrame.size.height) {
[_loadingComponent loading];
}
}
- (void)handleAppear
{
if (![self isViewLoaded]) {
return;
}
UIScrollView *scrollView = (UIScrollView *)self.view;
CGFloat vx = scrollView.contentInset.left + scrollView.contentOffset.x;
CGFloat vy = scrollView.contentInset.top + scrollView.contentOffset.y;
CGFloat vw = scrollView.frame.size.width - scrollView.contentInset.left - scrollView.contentInset.right;
CGFloat vh = scrollView.frame.size.height - scrollView.contentInset.top - scrollView.contentInset.bottom;
CGRect scrollRect = CGRectMake(vx, vy, vw, vh);;
// notify action for appear
NSArray *listenerArrayCopy = [self.listenerArray copy];
for(WXScrollToTarget *target in listenerArrayCopy){
[self scrollToTarget:target scrollRect:scrollRect];
}
}
- (CGPoint)absolutePositionForComponent:(WXComponent *)component
{
return [component->_view.superview convertPoint:component->_view.frame.origin toView:_view];
}
#pragma mark Private Methods
- (void)scrollToTarget:(WXScrollToTarget *)target scrollRect:(CGRect)rect
{
WXComponent *component = target.target;
if (![component isViewLoaded]) {
return;
}
CGFloat ctop;
if (component && component->_view && component->_view.superview) {
ctop = [self absolutePositionForComponent:component].y;
} else {
ctop = 0.0;
}
CGFloat cbottom = ctop + CGRectGetHeight(component.calculatedFrame);
CGFloat cleft;
if (component && component->_view && component->_view.superview) {
cleft = [self absolutePositionForComponent:component].x;
} else {
cleft = 0.0;
}
CGFloat cright = cleft + CGRectGetWidth(component.calculatedFrame);
CGFloat vtop = CGRectGetMinY(rect), vbottom = CGRectGetMaxY(rect), vleft = CGRectGetMinX(rect), vright = CGRectGetMaxX(rect);
if(cbottom > vtop && ctop <= vbottom && cleft <= vright && cright > vleft){
if(!target.hasAppear && component){
target.hasAppear = YES;
if (component->_appearEvent) {
// NSLog(@"appear:%@, %.2f", component, ctop);
[component fireEvent:@"appear" params:_direction ? @{@"direction":_direction} : nil];
}
}
} else {
if(target.hasAppear && component){
target.hasAppear = NO;
if(component->_disappearEvent){
// NSLog(@"disappear:%@", component);
[component fireEvent:@"disappear" params:_direction ? @{@"direction":_direction} : nil];
}
}
}
}
- (void)handleLoadMore
{
if (_listenLoadMore && [self isNeedLoadMore]) {
[self loadMore];
}
}
#pragma mark Layout
- (NSUInteger)_childrenCountForLayout;
{
return 0;
}
- (NSUInteger)childrenCountForScrollerLayout
{
return [super _childrenCountForLayout];
}
- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition
gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
{
/**
* Pretty hacky way
* layout from root to scroller to get scroller's frame,
* layout from children to scroller to get scroller's contentSize
*/
if ([self needsLayout]) {
memcpy(_scrollerCSSNode, self.cssNode, sizeof(css_node_t));
_scrollerCSSNode->children_count = (int)[self childrenCountForScrollerLayout];
_scrollerCSSNode->style.position[CSS_LEFT] = 0;
_scrollerCSSNode->style.position[CSS_TOP] = 0;
if (_scrollDirection == WXScrollDirectionVertical) {
_scrollerCSSNode->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
_scrollerCSSNode->style.dimensions[CSS_WIDTH] = _cssNode->layout.dimensions[CSS_WIDTH];
_scrollerCSSNode->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
} else {
_scrollerCSSNode->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
_scrollerCSSNode->style.dimensions[CSS_HEIGHT] = _cssNode->layout.dimensions[CSS_HEIGHT];
_scrollerCSSNode->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
}
_scrollerCSSNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
_scrollerCSSNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
layoutNode(_scrollerCSSNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
if ([WXLog logLevel] >= WXLogLevelDebug) {
print_css_node(_scrollerCSSNode, CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN);
}
CGSize size = {
WXRoundPixelValue(_scrollerCSSNode->layout.dimensions[CSS_WIDTH]),
WXRoundPixelValue(_scrollerCSSNode->layout.dimensions[CSS_HEIGHT])
};
if (!CGSizeEqualToSize(size, _contentSize)) {
// content size
_contentSize = size;
[dirtyComponents addObject:self];
}
_scrollerCSSNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
_scrollerCSSNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
}
[super _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
}
@end