2016-07-19 23 views
2

Ich versuche herauszufinden, ob ich ein UISnapBehavior von UIAnimator in einem UIScrollview verwenden kann, um den Inhalt der Bildlaufansicht an einem Punkt zu fangen. Bisher sind meine Erkenntnisse dazu geführt, dass dies unmöglich ist.UISnapBehavior von UIAnimator mit UIScrollview möglich?

Was ich

UIScrollView zu ‚Snap‘ zu bestimmtem Punkt zu erreichen versuchen, während der Benutzer die Bildlaufansicht schleppt. Das Scrollen muss jedoch von der eingerasteten Position aus fortgesetzt werden, ohne dass der Benutzer die Berührung anheben muss.

Apple scheint dies in Fotobearbeitung in ihrer iOS Fotos App zu erreichen. (Siehe Abbildung unten)

enter image description here

Was ich versuchte

Ich habe versucht, dieses Verhalten zu gewinnen, indem sie eine UIPanGestureRecognizer zum Scroll Anbringen und die Verwendung dieser Geschwindigkeit ist. Wenn der Benutzer in Richtung des Fangpunkts zieht, wird die Bildlaufansicht deaktiviert, der Bildlauf wird animiert und der Animationspunkt wird aktiviert. Wenn die Animation beendet ist, wird der Bildlauf wieder aktiviert.

Dies führte jedoch zu dem Problem, wo der Benutzer die Touch-up nach dem ziehen heben und die scrollview erneut ziehen muss. Aber Apple scheint es getan zu haben, ohne den Widerstand anzuheben.

+0

Siehe die Lösung hier https://Stackoverflow.com/a/48493973/1275014 – thedeveloper3124

Antwort

4

Ich habe versucht, iOS-Fotos App nachzuahmen. Hier ist meine Logik:

// CALCULATE A CONTENT OFFSET FOR SNAPPING POINT 
let snapPoint = CGPoint(x: 367, y: 0) 

// CHANGE THESE VALUES TO TEST 
let minDistanceToSnap = 7.0 
let minVelocityToSnap = 25.0 
let minDragDistanceToReleaseSnap = 7.0 
let snapDuringDecelerating = false 

Diese Art von Scrollen benötigt 3 Stufen

enum SnapState { 
case willSnap 
case didSnap 
case willRelease 
} 
  1. willSnap: Standardstatus. Entscheiden Sie, wann Sie einrasten möchten. Vergleichen Sie contentOffset distance from SnapPoint with minDistanceToSnap und scrollview velocity with minVelocityToSnap. Wechseln Sie in den Status didSnap.
  2. didSnap: Manuell setContentOffset zu einem bereitgestellten contextOffset(snapPoint). Berechne dragDistance unter scrollView. Wenn der Benutzer mehr als eine bestimmte Distanz zieht (minDragDistanceToReleaseSnap), wechseln Sie in den Zustand willRelease.
  3. willRelease: Wechseln Sie erneut zu willSnap, wenn distance scroll from snapPoint mehr als minDistanceToSnap ist.


extension ViewController: UIScrollViewDelegate { 
    func scrollViewDidScroll(scrollView: UIScrollView) { 
     switch(snapState) { 
      case .willSnap: 
       let distanceFromSnapPoint = distance(between: scrollView.contentOffset, and: snapPoint) 
       let velocity = scrollView.panGestureRecognizer.velocityInView(view) 
       let velocityDistance = distance(between: velocity, and: CGPointZero) 
       if distanceFromSnapPoint <= minDistanceToSnap && velocityDistance <= minVelocityToSnap && (snapDuringDecelerating || velocityDistance > 0.0) { 
        startSnapLocaion = scrollView.panGestureRecognizer.locationInView(scrollView) 
        snapState = .didSnap 
       } 
      case .didSnap: 
       scrollView.setContentOffset(snapPoint, animated: false) 
       var dragDistance = 0.0 
       let location = scrollView.panGestureRecognizer.locationInView(scrollView) 
       dragDistance = distance(between: location, and: startSnapLocaion) 
       if dragDistance > minDragDistanceToReleaseSnap { 
        startSnapLocaion = CGPointZero 
        snapState = .willRelease 
       } 
      case .willRelease: 
       let distanceFromSnapPoint = distance(between: scrollView.contentOffset, and: snapPoint) 
       if distanceFromSnapPoint > minDistanceToSnap { 
        snapState = .willSnap 
       } 
     } 
    } 
} 

Helper Funktion

func distance(between point1: CGPoint, and point2: CGPoint) -> Double { 
    return Double(hypotf(Float(point1.x - point2.x), Float(point1.y - point2.y))) 
} 

ein Demo-Projekt auf Github Hergestellt: https://github.com/rishi420/SnapDrag

Hinweis: Projekt mit Xcode 7.2 gemacht. Möglicherweise müssen Sie ein Bit zum Kompilieren ändern.

+1

Dies funktioniert mit meinem bestehenden Code !. Bravo! – Gizmodo

1

Fügen Sie den UIPanGestureRecognizer nicht direkt zu UIScrollView hinzu. Fügen Sie es stattdessen einer Containeransicht hinzu, und setzen Sie dann im Selektor den Inhalt von UIScrollView contentOffset manuell.

Deaktivieren Sie die Interaktion in UIScrollView selbst oder verwenden Sie den Delegaten, um die Interaktion direkt mit der Bildlaufansicht zu verhindern.