預期效果
如圖1所示:
UIScrollView進行嵌套組合庭瑰,最外層是一個UIScrollView喂走,為了說明方便蜕该,稱為父UIScrollView
里面嵌套著頭部區(qū)栓拜、懸停區(qū)和一個UIScrollView一膨,稱為子UIScrollView
要求頭部區(qū)展示在屏幕時呀邢,滾動內(nèi)容為父UIScrollView,一旦頭部區(qū)域消失在屏幕中時豹绪,這個時候滾動的內(nèi)容為子UIScrollView价淌,懸停區(qū)懸停在屏幕頂部。如圖2 所示
解決方案
方案1
通過監(jiān)聽父UIScrollView的contentOffset瞒津,如果偏移量小于于頭部區(qū)的高度蝉衣,則設置父UIScrollView的scrollEnabled為YES,設置子UIScrollView的scrollEnable為NO巷蚪。如果偏移量大于頭部區(qū)的高度病毡,則設置父UIScrollView的scrollEnabled為NO,設置子UIScrollView的scrollEnable為YES.
這個方案存在最大的問題是一旦快速滑動屏幕屁柏,到臨界值那邊會卡住啦膜,需要重新施加一次滑動手勢,才能繼續(xù)滾動淌喻。
方案2
讓一次手勢同時擁有多個響應者僧家,即一次滑動手勢無論子UIScrollView或者父UIScrollView都能作為響應者進行滾動,然后我們根據(jù)自己的需要進行重置不需要的滾動效果裸删。
要達到手勢能夠被多個UIView進行響應八拱,需要在父UIScrollView實現(xiàn) UIGestureRecognizerDelegate 代理方法
//支持手勢同步到其他接收者
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
在他們所在的父View或ViewController中實現(xiàn) UIScrollViewDelegate 的
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
默認只能滾動父UIScrollView,子UIScrollView在未被允許滾動的情況涯塔,偏移量會被重置為0肌稻。 比對父UIScrollView的偏移量和頭部區(qū)的高度,如果偏移量大于等于頭部區(qū)的高度匕荸,則開始重置父頭部區(qū)的高度的偏移量為頭部區(qū)高度爹谭,子UIScrollView不再重置偏移量為0.
具體代碼實現(xiàn)
定義一個父UIScrollView為 FatherScrollView
// FatherScrollView.h
#import <UIKit/UIKit.h>
@interface FatherScrollView : UIScrollView<UIGestureRecognizerDelegate>
@end
//FatherScrollView.m
#import "FatherScrollView.h"
@implementation FatherScrollView
//支持手勢同步到其他接收者
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
@end
定義一個ViewController進行內(nèi)容展示
#import "ViewController.h"
#import "FatherScrollView.h"
@interface ViewController ()<UIScrollViewDelegate>
//父UIScrollView
@property (nonatomic, strong) FatherScrollView *fatherscrollView;
//頭部區(qū)
@property (nonatomic, strong) UIView *headerView;
//子UIScrollView
@property (nonatomic, strong) UIScrollView *childScrollView;
//父UIScrollView是否能滾動
@property (nonatomic, assign) BOOL enableFatherViewScroll;
//子UIScrollView是否能滾動
@property (nonatomic, assign) BOOL enableChildViewScroll;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
self.enableChildViewScroll = NO;
self.enableFatherViewScroll = YES;
self.automaticallyAdjustsScrollViewInsets = NO;
self.fatherscrollView = [[FatherScrollView alloc] initWithFrame:self.view.bounds];
self.fatherscrollView.delegate = self;
self.fatherscrollView.bounces = YES;
self.fatherscrollView.backgroundColor = UIColor.grayColor;
self.fatherscrollView.contentSize = CGSizeMake(0, self.view.bounds.size.height+200);
[self.view addSubview:self.fatherscrollView];
self.headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 200)];
self.headerView.backgroundColor = UIColor.greenColor;
[self.fatherscrollView addSubview:self.headerView];
UILabel *label = [[UILabel alloc] init];
label.text = @"懸浮標題";
label.textAlignment = NSTextAlignmentCenter;
label.frame = CGRectMake(0, 160, self.view.bounds.size.width, 40);
label.backgroundColor = UIColor.whiteColor;
[self.headerView addSubview:label];
self.childScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 200, self.view.bounds.size.width, self.view.bounds.size.height)];
self.childScrollView.delegate = self;
self.childScrollView.contentSize = CGSizeMake(0, self.view.bounds.size.height * 1.5);
self.childScrollView.backgroundColor = UIColor.redColor;
[self.fatherscrollView addSubview:self.childScrollView];
UILabel *contentLabel = [[UILabel alloc] init];
contentLabel.font = [UIFont systemFontOfSize:50];
contentLabel.text = @"子滾動內(nèi)容";
contentLabel.textAlignment = NSTextAlignmentCenter;
contentLabel.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
[self.childScrollView addSubview:contentLabel];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat contentOffset = 160 - [UIApplication sharedApplication].statusBarFrame.size.height;
if (scrollView == self.fatherscrollView) {
if (!self.enableFatherViewScroll) {
scrollView.contentOffset = CGPointMake(0, contentOffset);
self.enableChildViewScroll = YES;
} else {
if (scrollView.contentOffset.y >= contentOffset) {
scrollView.contentOffset = CGPointMake(0, contentOffset);
if (self.enableFatherViewScroll) {
self.enableFatherViewScroll = NO;
self.enableChildViewScroll = YES;
}
}
}
} else {
if (!self.enableChildViewScroll) {
scrollView.contentOffset = CGPointMake(0, 0);
} else {
if (scrollView.contentOffset.y <= 0) {
self.enableChildViewScroll = NO;
self.enableFatherViewScroll = YES;
}
}
}
}
@end
開發(fā)中的問題
1、這種嵌套的設計榛搔,往往會包含有多個子UIScrollView并且可以進行左右滑動切換旦棉,子UIScrollView區(qū)域往往會當獨封閉齿风,如果都在UIViewController這邊進行處理的話,會有大量的耦合代碼出現(xiàn)
2绑洛、不得不為父UIScrollView創(chuàng)建一個新的UIScrollView在子類救斑,實現(xiàn) (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
針對上面問題,我這邊對UIScrollView嵌套方案進行了簡要的封裝真屯,方便開發(fā)中直接使用
Demo地址:CCNestScrollView