diff --git a/renderer/native/ios/renderer/component/listview/HippyNextListTableView.h b/renderer/native/ios/renderer/component/listview/HippyNextListTableView.h index 44afe84f6cb..1041e062060 100644 --- a/renderer/native/ios/renderer/component/listview/HippyNextListTableView.h +++ b/renderer/native/ios/renderer/component/listview/HippyNextListTableView.h @@ -21,7 +21,7 @@ */ #import -#import "HippyScrollView.h" +#import "HippyNestedScrollProtocol.h" NS_ASSUME_NONNULL_BEGIN diff --git a/renderer/native/ios/renderer/component/listview/HippyNextListTableView.m b/renderer/native/ios/renderer/component/listview/HippyNextListTableView.m index d22b2d54a3b..3e848e0c6b6 100644 --- a/renderer/native/ios/renderer/component/listview/HippyNextListTableView.m +++ b/renderer/native/ios/renderer/component/listview/HippyNextListTableView.m @@ -21,16 +21,10 @@ */ #import "HippyNextListTableView.h" -#import "HippyScrollView.h" @implementation HippyNextListTableView -@synthesize lastContentOffset; -@synthesize activeInnerScrollView; -@synthesize activeOuterScrollView; -@synthesize nestedGestureDelegate; -@synthesize cascadeLockForNestedScroll; -@synthesize isLockedInNestedScroll; +HIPPY_NESTEDSCROLL_PROTOCOL_PROPERTY_IMP /** * we need scroll indicator to be at top diff --git a/renderer/native/ios/renderer/component/scrollview/HippyNestedScrollProtocol.h b/renderer/native/ios/renderer/component/scrollview/HippyNestedScrollProtocol.h new file mode 100644 index 00000000000..167b4be6357 --- /dev/null +++ b/renderer/native/ios/renderer/component/scrollview/HippyNestedScrollProtocol.h @@ -0,0 +1,75 @@ +/*! + * iOS SDK + * + * Tencent is pleased to support the open source community by making + * Hippy available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed 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. + */ + +#ifndef HippyNestedScrollProtocol_h +#define HippyNestedScrollProtocol_h + +#import + + +#define HIPPY_NESTEDSCROLL_PROTOCOL_PROPERTY_IMP \ +@synthesize lastContentOffset; \ +@synthesize activeInnerScrollView; \ +@synthesize activeOuterScrollView; \ +@synthesize nestedGestureDelegate; \ +@synthesize cascadeLockForNestedScroll; \ +@synthesize isLockedInNestedScroll; \ + + +/// Delegate for handling nested scrolls' gesture conflict +@protocol HippyNestedScrollGestureDelegate + +/// Ask the delegate whether gesture should recognize simultaneously +/// For nested scroll +/// @param view the other view +- (BOOL)shouldRecognizeScrollGestureSimultaneouslyWithView:(UIView *)view; + +@end + + +/// Protocol for nested scrollview +@protocol HippyNestedScrollProtocol + +/// Record the last content offset for scroll lock. +@property (nonatomic, assign) CGPoint lastContentOffset; + +/// Record the current active inner scrollable view. +/// Used to judge the responder when outer has more than one inner scrollview. +@property (nonatomic, weak) UIScrollView *activeInnerScrollView; + +/// Record the current active outer scrollable view. +/// Used to pass the cascadeLock when more than three scrollable views nested. +@property (nonatomic, weak) UIScrollView *activeOuterScrollView; + +/// Gesture delegate for handling nested scroll. +@property (nonatomic, weak) id nestedGestureDelegate; + +/// Cascade lock for nestedScroll +@property (nonatomic, assign) BOOL cascadeLockForNestedScroll; + +/// Whether is temporarily locked in current DidScroll callback. +/// It is used to determine whether to block the sending of onScroll events. +@property (nonatomic, assign) BOOL isLockedInNestedScroll; + +@end + +#endif /* HippyNestedScrollProtocol_h */ diff --git a/renderer/native/ios/renderer/component/scrollview/HippyScrollView.h b/renderer/native/ios/renderer/component/scrollview/HippyScrollView.h index 50c9c5c109d..3d10e5e47b3 100644 --- a/renderer/native/ios/renderer/component/scrollview/HippyScrollView.h +++ b/renderer/native/ios/renderer/component/scrollview/HippyScrollView.h @@ -21,46 +21,9 @@ */ #import -#import "HippyScrollableProtocol.h" #import "HippyView.h" - - -/// Delegate for handling nested scrolls' gesture conflict -@protocol HippyNestedScrollGestureDelegate - -/// Ask the delegate whether gesture should recognize simultaneously -/// For nested scroll -/// @param view the other view -- (BOOL)shouldRecognizeScrollGestureSimultaneouslyWithView:(UIView *)view; - -@end - - -/// Protocol for nested scrollview -@protocol HippyNestedScrollProtocol - -/// Record the last content offset for scroll lock. -@property (nonatomic, assign) CGPoint lastContentOffset; - -/// Record the current active inner scrollable view. -/// Used to judge the responder when outer has more than one inner scrollview. -@property (nonatomic, weak) UIScrollView *activeInnerScrollView; - -/// Record the current active outer scrollable view. -/// Used to pass the cascadeLock when more than three scrollable views nested. -@property (nonatomic, weak) UIScrollView *activeOuterScrollView; - -/// Gesture delegate for handling nested scroll. -@property (nonatomic, weak) id nestedGestureDelegate; - -/// Cascade lock for nestedScroll -@property (nonatomic, assign) BOOL cascadeLockForNestedScroll; - -/// Whether is temporarily locked in current DidScroll callback. -/// It is used to determine whether to block the sending of onScroll events. -@property (nonatomic, assign) BOOL isLockedInNestedScroll; - -@end +#import "HippyScrollableProtocol.h" +#import "HippyNestedScrollProtocol.h" /// The hippy's custom scrollView diff --git a/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm b/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm index d3c6955df62..dd466052bed 100644 --- a/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm +++ b/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm @@ -31,13 +31,7 @@ @implementation HippyCustomScrollView -@synthesize lastContentOffset; -@synthesize activeInnerScrollView; -@synthesize activeOuterScrollView; -@synthesize nestedGestureDelegate; -@synthesize cascadeLockForNestedScroll; -@synthesize isLockedInNestedScroll; - +HIPPY_NESTEDSCROLL_PROTOCOL_PROPERTY_IMP - (instancetype)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { diff --git a/tests/ios/HippyNestedScrollTest.m b/tests/ios/HippyNestedScrollTest.m new file mode 100644 index 00000000000..1f51bad2268 --- /dev/null +++ b/tests/ios/HippyNestedScrollTest.m @@ -0,0 +1,98 @@ +/*! + * iOS SDK + * + * Tencent is pleased to support the open source community by making + * Hippy available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed 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 +#import + + +@interface HippyNestedScrollCoordinator (UnitTest) + +/// Whether is the given direction has specified priority +/// direction param see `HippyNestedScrollDirection` +- (BOOL)isDirection:(char)direction hasPriority:(HippyNestedScrollPriority)priority; + +@end + +@interface HippyNestedScrollTest : XCTestCase + +@end + +@implementation HippyNestedScrollTest + +- (void)setUp { + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. +} + +- (void)testNestedScrollCoordinatorSetPriority { + HippyNestedScrollCoordinator *coordinator = [HippyNestedScrollCoordinator new]; + XCTAssertTrue([coordinator isDirection:0 hasPriority:HippyNestedScrollPrioritySelf]); + XCTAssertTrue([coordinator isDirection:1 hasPriority:HippyNestedScrollPrioritySelf]); + XCTAssertTrue([coordinator isDirection:2 hasPriority:HippyNestedScrollPrioritySelf]); + XCTAssertTrue([coordinator isDirection:3 hasPriority:HippyNestedScrollPrioritySelf]); + XCTAssertTrue([coordinator isDirection:4 hasPriority:HippyNestedScrollPrioritySelf]); + + coordinator.nestedScrollPriority = HippyNestedScrollPrioritySelf; + XCTAssertTrue([coordinator isDirection:1 hasPriority:HippyNestedScrollPrioritySelf]); + XCTAssertTrue([coordinator isDirection:2 hasPriority:HippyNestedScrollPrioritySelf]); + XCTAssertTrue([coordinator isDirection:3 hasPriority:HippyNestedScrollPrioritySelf]); + XCTAssertTrue([coordinator isDirection:4 hasPriority:HippyNestedScrollPrioritySelf]); + XCTAssertFalse([coordinator isDirection:1 hasPriority:HippyNestedScrollPriorityParent]); + XCTAssertFalse([coordinator isDirection:2 hasPriority:HippyNestedScrollPriorityParent]); + XCTAssertFalse([coordinator isDirection:3 hasPriority:HippyNestedScrollPriorityParent]); + XCTAssertFalse([coordinator isDirection:4 hasPriority:HippyNestedScrollPriorityParent]); + + coordinator.nestedScrollRightPriority = HippyNestedScrollPriorityParent; + coordinator.nestedScrollLeftPriority = HippyNestedScrollPrioritySelf; + coordinator.nestedScrollBottomPriority = HippyNestedScrollPriorityNone; + coordinator.nestedScrollTopPriority = HippyNestedScrollPriorityParent; + XCTAssertTrue([coordinator isDirection:1 hasPriority:HippyNestedScrollPriorityParent]); + XCTAssertTrue([coordinator isDirection:2 hasPriority:HippyNestedScrollPrioritySelf]); + XCTAssertTrue([coordinator isDirection:3 hasPriority:HippyNestedScrollPriorityNone]); + XCTAssertTrue([coordinator isDirection:4 hasPriority:HippyNestedScrollPriorityParent]); +} + +- (void)testShouldRecognizeScrollGestureSimultaneously { + HippyNestedScrollCoordinator *coordinator = [HippyNestedScrollCoordinator new]; + HippyScrollView *scrollView = [HippyScrollView new]; + coordinator.outerScrollView = (UIScrollView *)scrollView.realScrollView; + XCTAssertFalse([coordinator shouldRecognizeScrollGestureSimultaneouslyWithView:scrollView.realScrollView]); + coordinator.nestedScrollPriority = HippyNestedScrollPriorityNone; + XCTAssertFalse([coordinator shouldRecognizeScrollGestureSimultaneouslyWithView:scrollView.realScrollView]); + coordinator.nestedScrollPriority = HippyNestedScrollPrioritySelf; + XCTAssertTrue([coordinator shouldRecognizeScrollGestureSimultaneouslyWithView:scrollView.realScrollView]); +} + +- (void)testNestedScrollDoScrollViewDidScroll { + HippyNestedScrollCoordinator *coordinator = [HippyNestedScrollCoordinator new]; + HippyScrollView *scrollView = [HippyScrollView new]; + UIScrollView *sv = (UIScrollView *)scrollView.realScrollView; + [sv setContentOffset:CGPointMake(100.0, 200.0)]; + XCTAssert(CGPointEqualToPoint(sv.lastContentOffset, CGPointZero)); + [coordinator scrollViewDidScroll:scrollView.realScrollView]; + XCTAssert(CGPointEqualToPoint(sv.lastContentOffset, CGPointMake(100.0, 200.0))); +} + +@end