兩個scroll嵌套的scrollview聯(lián)劃的方案糖儡,通過contentInset的形式,為底部的scroll開辟空間逝慧,監(jiān)聽頂部的滑動衬浑、模擬底部的滑動,具體代碼如下
.h
#import <UIKit/UIKit.h>
#import "LYCommonScrollView.h"
NS_ASSUME_NONNULL_BEGIN
//上下嵌套的scrollView 聯(lián)滑
@protocol LYMixNestScrollContainerViewScrollDelegate<NSObject>
-(void)containerViewDidScroll:(UIScrollView *)scrollView;
@optional
-(void)didMoveToPage:(NSInteger)pageIdx mainScroll:(UIScrollView *)mainScroll bottomScroll:(UIScrollView * _Nullable )bottomScroll;
@end
@interface LYMixNestScrollContainerView : UIView
//main Scroll mjheader和放刨、backtoTopButton都附加到這里
@property (nonatomic, strong,readonly) LYCommonScrollView *scrollView;
@property (nonatomic, weak) id<LYMixNestScrollContainerViewScrollDelegate> scrollDelegate;
- (instancetype)initWithFrame:(CGRect)frame topView:(UIScrollView *)topView bottomView:(UIScrollView *)bottomView;
- (CGFloat)topContentHeight;
-(void)setShiedTouchFrame:(CGRect)frame;
@end
NS_ASSUME_NONNULL_END
.m
//
// lyMixNestScrollView.m
// lyEjGameDemo
//
//
#import "MixNestScrollContainerView.h"
#import "UIView+ly.h"
#import "lyConstants.h"
#import "FBKVOController.h"
#import "WeakifyStrongify.h"
#import <KVOController/KVOController.h>
#import "MJRefresh.h"
#import "lyDeviceUtil.h"
#import "lyABTest.h"
@interface MixNestScrollContainerView()<UIScrollViewDelegate>
@property (nonatomic, strong) UIScrollView *topView;
@property (nonatomic, strong) UIScrollView *bottomView;
@property (nonatomic,assign) CGRect shieldFrame;
@end
@implementation MixNestScrollContainerView
- (instancetype)initWithFrame:(CGRect)frame topView:(UIScrollView *)topView bottomView:(UIScrollView *)bottomView
{
self = [super initWithFrame:frame];
if (self) {
self.topView = topView;
self.bottomView = bottomView;
[self setup];
}
return self;
}
- (CGFloat)topContentHeight {
return self.topView.contentSize.height;
}
- (UIScrollView *)scrollView {
return _topView;
}
-(void)layoutSubviews {
[super layoutSubviews];
self.topView.ly_top = 0;
if(self.topView.ly_height != self.ly_height) {
self.topView.ly_height = self.ly_height;
}
if(self.bottomView.ly_height != self.ly_height) {
self.bottomView.ly_height = self.ly_height;
}
[self updateBottomContentInset:self.bottomView.contentInset.bottom];
}
-(void)reloadSubScroll:(UIScrollView *)scrollView {
if([scrollView isKindOfClass:UICollectionView.class]) {
[(UICollectionView *)scrollView reloadData];
} else if ([scrollView isKindOfClass:UITableView.class]) {
[(UITableView *)scrollView reloadData];
}
}
-(CGFloat)calSizeHeightForScroll:(UIScrollView *)view {
if([view isKindOfClass:UICollectionView.class]) {
UICollectionView *collection = (UICollectionView *)view;
return collection.collectionViewLayout.collectionViewContentSize.height;
}
return view.contentSize.height;
}
-(void)setup {
[self addSubview:self.scrollView];
self.bottomView.scrollEnabled = NO;
[self.topView addSubview:self.bottomView];
[self.KVOController unobserve:_topView];
@weakify(self);
[self.KVOController observe:_topView
keyPaths:@[@"contentSize",@"contentOffset"]
options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew
block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
@strongify(self);
[self updateScrollls];
[self.scrollDelegate containerViewDidScroll:self.topView];
}];
[self.KVOController unobserve:_bottomView];
[self.KVOController observe:_bottomView
keyPath:@"contentSize"
options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew
block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
@strongify(self);
[self layoutScrollIfNeeded];
}];
}
-(void)layoutScrollIfNeeded {
if(self.topView.contentInset.bottom != self.bottomView.contentSize.height + self.bottomView.contentInset.bottom) {
self.topView.contentInset = UIEdgeInsetsMake(self.topView.contentInset.top, self.topView.contentInset.left, self.bottomView.contentSize.height + self.bottomView.contentInset.bottom, self.topView.contentInset.right);
}
}
#pragma mark - UIScrollViewDelegate
#pragma mark - private
-(void)updateScrollls {
CGFloat offset = self.scrollView.contentOffset.y;
[self adjustBottomCollection:offset];
}
-(void)adjustBottomCollection:(CGFloat )offset {
CGFloat top = self.topView.contentSize.height;
if(offset >= top) {
self.bottomView.ly_top = offset;
[self.bottomView setContentOffset:CGPointMake(0, offset - top)];
} else {
self.bottomView.ly_top = top;
[self.bottomView setContentOffset:CGPointMake(0,0)];
}
// NSLog(@"scroll BottomCollection %f bottomViewsize %f offset %f",self.bottomView.contentOffset.y,self.bottomView.contentSize.height,offset - self.topView.contentSize.height);
// NSLog(@"scroll BottomCollection %f offset %f",self.bottomView.contentOffset.y,offset - self.topView.contentSize.height);
}
- (void)updateBottomContentInset:(CGFloat)bottom{
// 解決mjFooter不懸停的問題
if(bottom > 0 && bottom != self.scrollView.contentInset.bottom - self.bottomView.contentSize.height) {
self.scrollView.contentInset = UIEdgeInsetsMake(self.scrollView.contentInset.top, self.scrollView.contentInset.left,self.bottomView.contentSize.height + bottom, self.scrollView.contentInset.right);
}
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if(CGRectContainsPoint(self.shieldFrame, point)) {
return NO;
} else {
return [super pointInside:point withEvent:event];
}
}
- (void)setShiedTouchFrame:(CGRect)frame {
self.shieldFrame = frame;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end