UIScrollView(UICollectionView)禁止横向和竖向同时滑动

今天遇到这么一个需求,我们有个界面显示很多队员以及他们的各项得分情况,界面是用UICollectionView做的,配上自定义的layout,支持横向和竖向滑动,更支持对角线滑动,当在对角线方向滑动的时候,横向和竖向都在滑动。

现在的要求是禁止对角线滑动,要么横向,要么竖向滑动。

首先在查阅苹果文档后,知道有这么一个属性能够做一些控制。

// default NO. if YES, try to lock vertical or horizontal scrolling while dragging
open var isDirectionalLockEnabled: Bool 

If this property is false, scrolling is permitted in both horizontal and vertical directions. If this property is true and the user begins dragging in one general direction (horizontally or vertically), the scroll view disables scrolling in the other direction. If the drag direction is diagonal, then scrolling will not be locked and the user can drag in any direction until the drag completes. The default value is false

该属性值为false的时候:

  • 支持横向和竖向两个方向的滑动。

当该属性为true的时候:

  • 如果用户刚开始滑动的时候更趋近于横向滑动的话,那么就禁止竖向的滑动;
  • 如果用户刚开始滑动的时候更趋近于竖向滑动的话,那么就禁止横向的滑动;
  • 如果用户沿着对角线滑动,那么该属性就失效了,两个方向都可滑动。

用了这个属性后,大概率会减少一开始两个方向同时滑动的问题,但是不够完美。我们还需要处理在沿对角线的滑动方式。

下面给UIScrollView添加一些扩展方法及属性,来处理沿对角线的滑动的问题。

extension UIScrollView {
  enum ScrollDirection {
    case none        // 未滑动
    case diagonal    // 对角线方向
    case horizontal  // 横向
    case vertical    // 竖向
  }

  // 记录每次开始滑动的时候初始偏移量
  private var initialContentOffset: CGPoint {
    get {
      let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "initialContentOffset".hashValue)
      let obj: CGPoint? = objc_getAssociatedObject(self, key) as? CGPoint
      return obj ?? .zero
    }

    set {
      let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "initialContentOffset".hashValue)
      objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
  }

  func setInitialContentOffset(_ offSet: CGPoint) {
    initialContentOffset = offSet
  }

  // 获取滑动方向
  func scrollDirection() -> ScrollDirection {
    var direction: ScrollDirection = .none
    if contentOffset.x != initialContentOffset.x && contentOffset.y != initialContentOffset.y {
      direction = .diagonal
    } else if contentOffset.x != initialContentOffset.x {
      direction = .horizontal
    } else if contentOffset.y != initialContentOffset.y {
      direction = .vertical
    } else {
      direction = .none
    }
    return direction
  }

  // 沿单个轴滑动
  func scrollAlongOneAxis() {
    let direction = scrollDirection()
    if direction == .diagonal {
      var newOffset: CGPoint = .zero
      if abs(contentOffset.x) > abs(contentOffset.y) {
        newOffset = CGPoint(x: contentOffset.x, y: initialContentOffset.y)
      } else {
        newOffset = CGPoint(x: initialContentOffset.x, y: contentOffset.y)
      }
      setContentOffset(newOffset, animated: false)
    }
  }
}
  1. 首先通过枚举定义几个滑动方向,包括了横向、竖向、对角线方向。
  2. 设置initialContentOffset,用来记录每次将要移动时的初始偏移量。
  3. 通过scrollDirection()方法,来判断用户在哪个方向上移动。
  4. 最后调用scrollAlongOneAxis()方法进行单轴方向移动。

扩展方法和属性介绍完了,那么在具体的项目中怎么用呢?

第一步:

UICollectionView或者UIScrollView设置isDirectionalLockEnabledtrue,这样让系统帮我们处理一些,减少scrollAlongOneAxis()方法中if条件下的代码执行次数。

第二步:

UIScrollViewDelegate代理方法scrollViewWillBeginDragging中调用setInitialContentOffset()方法设置初始偏移量。

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
   scrollView.setInitialContentOffset(scrollView.contentOffset)
}

第三步:

UIScrollViewDelegate代理方法scrollViewDidScroll中调用scrollAlongOneAxis()方法实现单轴方向滑动。

func scrollViewDidScroll(_ scrollView: UIScrollView) {
   scrollView.scrollAlongOneAxis()
}

以上三步即可实现我们想要的每次只能单个方向滑动的问题,如果有更好的方法,还请路过的朋友指点一二。

如果觉得文章对你有用,不妨给个赞,关注一下,更多好用文章还在继续更新中。

本篇文章出自https://blog.csdn.net/guoyongming925的博客,如需转载,还请标明出处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值