![](https://img.haomeiwen.com/i1154538/a3901b5313be1404.gif)
demo地址:https://github.com/yangguanghei/LSScrollView
思路
在scrollViewDidScroll方法中去设置滚动条的位置
1.首先需要添加几个参考视图,这几个视图的位置是滚动条最终可能停留的位置。如效果图所示的黄色横线就是四个view。
2.我们需要获取滚动条当前停留的位置和即将滑向的位置(通过步骤2中的几个参考视图获取)。
3.需要获取滑动的方向(左或者右,两个方向需要区别对待)。
4.获取滑动的进度,从某个位置滑动到另一个位置是需要一个过程的。
当向左滑动的时候
获取当前所在参考视图+滑动到的参考视图+两个视图间的距离+滑动的进度===>重新设置滚动条的X坐标
注意:先获取当前所在参考视图下标,当前参考视图下标+1=目标参考视图下标
当进度为1的时候,当前参考视图下标=目标参考视图下标
当向右滑动的时候
获取当前所在参考视图+滑动到的参考视图+两个视图间的距离+滑动的进度===>重新设置滚动条的X坐标
注意:先获取目标参考视图下标,目标参考视图下标+1=当前参考视图下标
当进度为1的时候,目标参考视图下标=当前参考视图下标
感觉talk is cheap,直接上代码吧
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (self.isForbidScrollDelegate) { // 当通过代码设置scrollView的偏移量时,不再走此方法
return;
}
CGFloat progress = 0;
CGFloat sourceIndex = 0;
CGFloat targetIndex = 0;
CGFloat contentOffsetX = scrollView.contentOffset.x;
CGFloat scrollWidth = scrollView.bounds.size.width;
CGFloat offsetIndex = contentOffsetX / scrollWidth;
if (contentOffsetX > 0) { // 左滑
progress = offsetIndex - floor(offsetIndex);
NSLog(@"offsetIndex:%f---floor(offsetIndex):%f", offsetIndex, floor(offsetIndex));
sourceIndex = (int)(contentOffsetX / scrollWidth);
targetIndex = sourceIndex + 1;
if (targetIndex >= self.titles.count) { // 不能再向左滑动
// 最后的回弹效果
UIView * view = self.views[self.titles.count-1];
CGFloat width = view.frame.size.width*(1-progress*3.5);
if (width <= miniScrollBarW) {
width = miniScrollBarW;
}
CGFloat x = view.frame.origin.x + (view.frame.size.width - width);
self.scrollControl.frame = CGRectMake(x, self.scrollControl.frame.origin.y, width, self.scrollControl.frame.size.height);
return;
}
if (progress == 1) {
targetIndex = sourceIndex;
}
}else{ // 右滑
progress = 1 - (offsetIndex - floor(offsetIndex));
NSLog(@"offsetIndex:%f---floor(offsetIndex):%f", offsetIndex, floor(offsetIndex));
if (contentOffsetX <= 0) { // 不能再向右滑动
// 最后的回弹效果
UIView * view = self.views[0];
CGFloat pro = -offsetIndex / 1;
CGFloat width = view.frame.size.width - pro*view.frame.size.width * 3.5;
if (width <= miniScrollBarW) {
width = miniScrollBarW;
}
self.scrollControl.frame = CGRectMake(view.frame.origin.x, self.scrollControl.frame.origin.y, width, self.scrollControl.frame.size.height);
return;
}
targetIndex = (int)(contentOffsetX / scrollWidth);
sourceIndex = targetIndex + 1;
if (sourceIndex >= self.titles.count) {
sourceIndex = self.titles.count - 1;
}
if (progress == 1) {
sourceIndex = targetIndex;
}
}
UIView * sourceView = self.views[(int)sourceIndex];
UIView * targetView = self.views[(int)targetIndex];
CGFloat totalMoveX = targetView.frame.origin.x - sourceView.frame.origin.x;
CGFloat moveLength = totalMoveX * progress;
self.scrollControl.frame = CGRectMake(sourceView.frame.origin.x + moveLength, self.scrollControl.frame.origin.y, self.scrollControl.frame.size.width, self.scrollControl.frame.size.height);
}
感觉实际关键点就三个:当前所在参考视图、目标参考视图、滑动的进度。
精简关键代码:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (scrollView.isTracking == YES || scrollView.isDecelerating == YES) { // 用户滑动引起的才处理
CGFloat progress = 0; // 从源位置滑动到目标位置滑动的进度
CGFloat sourceIndex = 0; // 源偏移下标
CGFloat targetIndex = 0; // 目标偏移下标
CGFloat contentOffsetX = scrollView.contentOffset.x; // 偏移量
CGFloat scrollWidth = scrollView.bounds.size.width; // scroll宽度
CGFloat offsetIndex = contentOffsetX / scrollWidth; // 偏移下标(float类型)
if (contentOffsetX > 0) { //
progress = offsetIndex - (int)(offsetIndex);
sourceIndex = (int)(offsetIndex);
targetIndex = sourceIndex + 1; // 即使目标下标比源下标小也可这样处理
int maxIndex = (int)(scrollView.contentSize.width / scrollView.bounds.size.width); // 最后的偏移下标
if (targetIndex + 1 > maxIndex) { // 滑动到最右端
return;
}
}
CGFloat sourceX = self.scrollControl.frame.size.width * sourceIndex;
CGFloat moveX = self.scrollControl.frame.size.width;
CGFloat moveL = moveX * progress;
self.scrollControl.frame = CGRectMake(sourceX + moveL, self.scrollControl.frame.origin.y, self.scrollControl.frame.size.width, self.scrollControl.frame.size.height);
}
}
网友评论