嵌套滚动:巧用ScrollView层级,打造顺畅交互体验
2023-10-16 04:36:33
前言
随着App功能不断迭代,常有需求希望在不影响其他区域功能的前提下,在某一区域实现根据选择器切换不同内容的显示。苹果并不推荐嵌套滚动视图,直接添加的话,就会出现手势冲突,造成糟糕的交互体验。
在实际开发中,我不断思考解决方案,经历了几次重构后,总结出了三种常见的UIScrollView嵌套实现方案,并附上代码示例和交互对比分析,帮助开发人员轻松掌握嵌套滚动技巧,提升App的用户体验。
方案一:父视图设置滚动代理
实现原理: 将父视图的UIScrollViewDelegate
代理方法传递给子视图的UIScrollView
。
代码示例:
- (void)viewDidLoad {
[super viewDidLoad];
// 将父视图的UIScrollViewDelegate代理方法传递给子视图的UIScrollView
self.childScrollView.delegate = self;
}
交互分析:
这种方案的交互体验比较流畅,但存在一个问题:当父视图的UIScrollView
正在滚动时,子视图的UIScrollView
无法滚动。
方案二:父视图监听子视图的滚动事件
实现原理: 在父视图中监听子视图的滚动事件,当子视图滚动到边缘时,父视图的UIScrollView
停止滚动。
代码示例:
- (void)viewDidLoad {
[super viewDidLoad];
// 在父视图中监听子视图的滚动事件
[self.childScrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"contentOffset"]) {
// 当子视图滚动到边缘时,父视图的UIScrollView停止滚动
if (self.childScrollView.contentOffset.x <= 0 || self.childScrollView.contentOffset.x >= self.childScrollView.contentSize.width - self.childScrollView.frame.size.width) {
self.parentScrollView.scrollEnabled = YES;
} else {
self.parentScrollView.scrollEnabled = NO;
}
}
}
交互分析:
这种方案的交互体验比较流畅,而且不存在方案一的问题。但是,这种方案的实现代码比较复杂,而且需要在子视图中添加KVO监听,可能会影响性能。
方案三:父视图和子视图都实现滚动代理
实现原理: 父视图和子视图都实现UIScrollViewDelegate
代理方法,并根据不同的情况分别处理滚动事件。
代码示例:
- (void)viewDidLoad {
[super viewDidLoad];
// 父视图和子视图都实现UIScrollViewDelegate代理方法
self.parentScrollView.delegate = self;
self.childScrollView.delegate = self;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == self.parentScrollView) {
// 父视图滚动时,如果子视图正在滚动,则停止子视图的滚动
if (self.childScrollView.isDragging || self.childScrollView.isDecelerating) {
self.childScrollView.scrollEnabled = NO;
}
} else if (scrollView == self.childScrollView) {
// 子视图滚动时,如果父视图正在滚动,则停止父视图的滚动
if (self.parentScrollView.isDragging || self.parentScrollView.isDecelerating) {
self.parentScrollView.scrollEnabled = NO;
}
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (scrollView == self.parentScrollView) {
// 父视图停止滚动后,如果子视图没有滚动,则启用子视图的滚动
if (!self.childScrollView.isDragging && !self.childScrollView.isDecelerating) {
self.childScrollView.scrollEnabled = YES;
}
} else if (scrollView == self.childScrollView) {
// 子视图停止滚动后,如果父视图没有滚动,则启用父视图的滚动
if (!self.parentScrollView.isDragging && !self.parentScrollView.isDecelerating) {
self.parentScrollView.scrollEnabled = YES;
}
}
}
交互分析:
这种方案的交互体验比较流畅,而且不存在方案一和方案二的问题。但是,这种方案的实现代码比较复杂,而且需要在父视图和子视图中都添加UIScrollViewDelegate
代理方法,可能会影响性能。
总结
本文介绍了三种UIScrollView嵌套实现方案,包括父视图设置滚动代理、父视图监听子视图的滚动事件和父视图和子视图都实现滚动代理。每种方案都有各自的优缺点,开发人员可以根据实际需求选择合适的方案。
在实际开发中,我们还可以根据具体情况对这些方案进行组合使用,以实现更好的交互体验。例如,我们可以将方案一和方案二结合起来使用,这样既可以保证父视图的UIScrollView
在子视图滚动时停止滚动,又可以保证子视图的UIScrollView
在父视图滚动时继续滚动。
希望本文能对大家有所帮助。