2016-01-03 17 views
6

Ich versuche, eine Bildlaufansicht zu implementieren, die an Punkten beim Scrollen einrastet.UIScrollView Snap-to-Position beim Scrollen

Alle Posts, die ich hier gesehen habe, über das Einrasten zu einem Punkt, nachdem der Benutzer das Scrollen beendet hat. Ich möchte es beim Ziehen einrasten lassen.

Bisher habe ich diese die Trägheit nach dem Ziehen zu stoppen und es funktioniert gut:

func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { 
     targetContentOffset.memory = scrollView.contentOffset 
} 

Ich habe versucht, dies aber nicht wie gewünscht funktioniert:

var scrollSnapHeight : CGFloat = myScrollView.contentSize.height/10 

scrollViewDidScroll:

func scrollViewDidScroll(scrollView: UIScrollView) { 
    let remainder : CGFloat = scrollView.contentOffset.y % scrollSnapHeight 
    var scrollPoint : CGPoint = scrollView.contentOffset 
    if remainder != 0 && scrollView.dragging 
    { 
     if self.lastOffset > scrollView.contentOffset.y //Scrolling Down 
     { 
      scrollPoint.y += (scrollSnapHeight - remainder) 
      NSLog("scrollDown") 
     } 
     else //Scrolling Up 
     { 
      scrollPoint.y -= (scrollSnapHeight - remainder) 
     } 
     scrollView .setContentOffset(scrollPoint, animated: true) 
    } 
    self.lastOffset = scrollView.contentOffset.y; 
} 

Antwort

5

Dieser Ansatz aktiviert/deaktiviert scrollEnabled Eigenschaft von UIScrollView.

Wenn scrollView außerhalb der angegebenen scrollSnapHeight scrollt, machen Sie scrollEnabled zu false. Das wird das Scrollen stoppen. Aktivieren Sie dann erneut die Bildlauffunktion für den nächsten Ziehvorgang.

extension ViewController: UIScrollViewDelegate { 

    func scrollViewDidScroll(scrollView: UIScrollView) { 

     if scrollView.contentOffset.y > lastOffset + scrollSnapHeight { 
      scrollView.scrollEnabled = false 
     } else if scrollView.contentOffset.y < lastOffset - scrollSnapHeight { 
      scrollView.scrollEnabled = false 
     } 
    } 

    func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) { 

     guard !decelerate else { 
      return 
     } 

     setContentOffset(scrollView) 
    } 

    func scrollViewWillBeginDecelerating(scrollView: UIScrollView) { 

     setContentOffset(scrollView) 
    } 
} 

func setContentOffset(scrollView: UIScrollView) { 

    let stopOver = scrollSnapHeight 
    var y = round(scrollView.contentOffset.y/stopOver) * stopOver 
    y = max(0, min(y, scrollView.contentSize.height - scrollView.frame.height)) 
    lastOffset = y 

    scrollView.setContentOffset(CGPointMake(scrollView.contentOffset.x, y), animated: true) 

    scrollView.scrollEnabled = true 
} 
+0

Wenn ich dies versuche, muss der Benutzer nach dem Einrasten den Finger nach oben ziehen und dann erneut ziehen. Gibt es eine Möglichkeit, ohne Nachbesserungen zu machen? – Gizmodo

+0

@gizmodo Ich konnte es nicht verstehen. Wenn Sie auf die Position klicken, können Benutzer sie ziehen, aber die Bildlaufleiste wird nicht gescrollt. Nun zu welchem ​​Ereignis möchtest du die scrollView erneut scrollen lassen? –

+0

@gizmodo Wenn Sie nach dem Beenden des ScrollView-Vorgangs mit dem Benutzer aufhören möchten, http://stackoverflow.com/a/35197919/1378447 –

1

Subclass UIScrollView/UICollectionView

Diese Lösung erfordert keine Sie Ihren Finger, um heben arbeitet an unsnap und beim Scrollen. Wenn Sie es für vertikales Scrollen und nicht für horizontales Scrollen benötigen, vertauschen Sie einfach das x mit y.

Setzen Sie snapPoint auf den Inhalt Offset, wo Sie möchten, dass die Mitte des Snap sein.

Setzen Sie snapOffset auf den Radius um den Punkt, an dem das Einrasten erfolgen soll.

Wenn Sie wissen möchten, ob scrollView gerastet hat, überprüfen Sie einfach die Variable isSnapped.

class UIScrollViewSnapping : UIScrollView { 
    public var snapPoint: CGPoint? 
    public var snapOffset: CGFloat? 
    public var isSnapped = false 

    public override var contentOffset: CGPoint { 
     set { 
      if let snapPoint = self.snapPoint, 
       let snapOffset = self.snapOffset, 
       newValue.x > snapPoint.x - snapOffset, 
       newValue.x < snapPoint.x + snapOffset { 
       self.isSnapped = true 
       super.contentOffset = snapPoint 
      } 
      else { 
       self.isSnapped = false 
       super.contentOffset = newValue 
      } 
     } 
     get { 
      return super.contentOffset 
     } 
    } 
} 
Verwandte Themen