美文网首页
iOS开发中仿系统原生滚动条

iOS开发中仿系统原生滚动条

作者: 梁森的简书 | 来源:发表于2020-08-27 14:07 被阅读0次
0.滚动条 (1) (1).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);
    }
}

相关文章

网友评论

      本文标题:iOS开发中仿系统原生滚动条

      本文链接:https://www.haomeiwen.com/subject/idycsktx.html