2016-05-13 32 views
7

當通過UIPercentDrivenInteractiveTransition實現模態視圖控制器的交互式解除(拖動模式應該解除它)時,我們遇到了這個問題。當交互式解除模式時出現故障

設置:

  1. 設置UIViewController嵌入UINavigationController與至少一個按鈕,在UINavigationBar
  2. 模態呈現另一UIViewController嵌入UINavigationController與至少一個按鈕,在UINavigationBar
  3. 上modaly設置UIPanGestureRecognizer呈現UINavigationController驅動UIPercentDrivenInteractiveTransition
  4. 拖動模態WN通過​​點上UINavigationBar

問題「拿着」它:

  • 一邊慢慢向下拖動,動畫毛刺引起模式以跳上跳下

  • 毛刺只出現在:

    1. UINavigationBar s至少有一個按鈕
    2. 你 「持有」 由點上UINavigationBar

小例子可以從github repo下載模態。

有沒有人遇到過這樣的問題?有沒有解決方法?我們的設置有缺陷嗎?

更新

問題進行了模擬與iOS 9.3OSX 10.11.4,在Xcode 7.3.1編譯於iPhone 5的模擬器上面跑項目。

更新2

進一步調查顯示,這個問題可能不是在動畫:出於某種原因,在給定的設置pan.translationInView(view)將返回這將導致動畫跳意外的值。

部分工作

基於普京的想法,我們通過重寫的UINavigationBarhitTest方法部分地解決了該問題:

class DraggableNavigationBar: UINavigationBar { 

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { 
     guard let view = super.hitTest(point, withEvent: event) else { return nil } 

     if view is UIControl || pointIsInsideNavigationButton(point) { 
      return view 
     } else { 
      return nil 
     } 
    } 

    private func pointIsInsideNavigationButton(point: CGPoint) -> Bool { 
     return subviews 
      .filter { $0.frame.contains(point) } 
      .filter { String($0.dynamicType) == "UINavigationItemButtonView" } 
      .isEmpty == false 
    } 
} 
+0

適合我。無法在我的iPhone 6或iOS模擬器iPhone 6上看到任何故障。 –

+0

上述代碼中沒有問題,像魅力 – iMHitesh

+0

可以與我分享確切的問題。其中OS類型和xCode版本以及部署目標等。 – iMHitesh

回答

1

非常有趣的小故障。幾天前我發現了這個問題的部分解決方案,由於沒有人找到完整的解決方案,所以我會發布這個,也許會有幫助。

如果覆蓋的UINavigationBarhitTest方法,你可以通過持有UINavigationBar擺脫這個問題,當你拖動模式:

extension UINavigationBar { 

    override public func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { 

     guard let view = super.hitTest(point, withEvent: event) else { return nil } 

     if view.isKindOfClass(UIControl) { 
      return super.hitTest(point, withEvent: event) 
     } else { 
      return nil 
     } 
    } 
} 

不幸的是,如果你通過持有UIBarButtonItemUINavigationBar拖動模式,故障依然存在。

您也可以嘗試其他方法。

正如您所注意到的,pan.translationInView(view)返回的錯誤值會導致動畫跳轉。 在拖動過程中,您需要將此值與模態視圖的y座標進行比較。您可以通過檢查模態視圖控制器的表示層得到這個值:

... 

let translation = pan.translationInView(view) 

if let layer = view.layer.presentationLayer() { 
      print(layer.frame.origin.y) 
} 

... 

你可以看到,當pan.translationInView(view)開始顯示錯誤的值,layer.frame.origin.y仍然會在那一刻是正確的。您可以比較這兩個值,並在值不正確時查找模式,並通過爲translation.y值添加幾個點將其更改爲正確。

+0

感謝您的想法!我最終重寫了'hitTest',但也允許在後退按鈕上輕敲(令人驚訝的是它們不是'UIControl')。因爲需要考慮不同的拖動速度和方向改變,所以對'翻譯'和'presentationLayer'的區別是非常棘手的。 –

0

我沒有一個完整的解決方案,但我能夠減少小故障一定量。我可以在iPhone 5s上通過iOS 9.3.2 [通過拖動屏幕保持導航欄]重現此問題]

問題似乎在UIView.animateWithDurationDismissalAnimator。通過評論延遲和選項,即保持默認值,您可以減少視圖的跳躍。您也可以嘗試檢查您獲得最小跳數的不同UIViewAnimationOptions

UIView.animateWithDuration(0.3, 
     animations: { 
      dismissedView.frame = finalFrame 
     }, 
     completion: { _ in 
      let didComplete = !transitionContext.transitionWasCancelled() 
      transitionContext.completeTransition(didComplete) 
     } 
    ) 

a question這似乎是在處理您遇到的同一問題。和響應從禁用自動佈局變化,把layoutIfNeeded在動畫塊[嘗試,都沒有工作]。

+0

感謝您的建議。但是,更改'.CurveLinear'會導致動畫從手指移動失步。另外,考慮到這個問題的具體情況(UINavigationBar中的按鈕,在'UINavigationBar'中拖拽點),我不認爲這個鏈接的問題是相關的,但會檢查出來。 –