Skip to content

Commit

Permalink
feat(ios): nested scroll api support, add test
Browse files Browse the repository at this point in the history
  • Loading branch information
wwwcg committed Dec 11, 2024
1 parent 34be41d commit c04741b
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
*/

#import <UIKit/UIKit.h>
#import "HippyScrollView.h"
#import "HippyNestedScrollProtocol.h"

NS_ASSUME_NONNULL_BEGIN

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <UIKit/UIKit.h>


#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 <NSObject>

/// 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 <NSObject>

/// 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<HippyNestedScrollProtocol> *activeInnerScrollView;

/// Record the current active outer scrollable view.
/// Used to pass the cascadeLock when more than three scrollable views nested.
@property (nonatomic, weak) UIScrollView<HippyNestedScrollProtocol> *activeOuterScrollView;

/// Gesture delegate for handling nested scroll.
@property (nonatomic, weak) id<HippyNestedScrollGestureDelegate> 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 */
Original file line number Diff line number Diff line change
Expand Up @@ -21,46 +21,9 @@
*/

#import <UIKit/UIKit.h>
#import "HippyScrollableProtocol.h"
#import "HippyView.h"


/// Delegate for handling nested scrolls' gesture conflict
@protocol HippyNestedScrollGestureDelegate <NSObject>

/// 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 <NSObject>

/// 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<HippyNestedScrollProtocol> *activeInnerScrollView;

/// Record the current active outer scrollable view.
/// Used to pass the cascadeLock when more than three scrollable views nested.
@property (nonatomic, weak) UIScrollView<HippyNestedScrollProtocol> *activeOuterScrollView;

/// Gesture delegate for handling nested scroll.
@property (nonatomic, weak) id<HippyNestedScrollGestureDelegate> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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])) {
Expand Down
98 changes: 98 additions & 0 deletions tests/ios/HippyNestedScrollTest.m
Original file line number Diff line number Diff line change
@@ -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 <XCTest/XCTest.h>
#import <hippy/HippyNestedScrollCoordinator.h>


@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<HippyNestedScrollProtocol> *)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<HippyNestedScrollProtocol> *sv = (UIScrollView<HippyNestedScrollProtocol> *)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

0 comments on commit c04741b

Please sign in to comment.