ios - UIPercentDrivenInteractiveTransition doesn't get to animation's completion on fast gesture -


i have created interactive transition. func animatetransition(transitioncontext: uiviewcontrollercontexttransitioning) quite normal, container uiview, add 2 uiviewcontrollers , animation changes in uiview.animatewithduration(duration, animations, completion).

i add uiscreenedgepangesturerecognizer uiviewcontroller. works except when quick pan.

in last scenario, app not responsive, still on same uiviewcontroller (the transition seems not have worked) background tasks run. when run debug view hierarchy, see new uiviewcontroller instead of previous one, , previous 1 (at least uiview) stands supposed stand @ end of transition.

i did print out , check points , can when problem occurs, the animation's completion (the 1 in animatetransition method) is not reached, cannot call transitioncontext.completetransition method complete or not transition.

i see pan goes uigesturerecognizerstate.began straight uigesturerecognizerstate.ended without going through uigesturerecognizerstate.changed.

when goes through uigesturerecognizerstate.changed, both translation and velocity stay same every uigesturerecognizerstate.changed states.

edit :

here code:

animatetransition method

func animatetransition(transitioncontext: uiviewcontrollercontexttransitioning) {     self.transitioncontext = transitioncontext      let containerview = transitioncontext.containerview()     let screens: (from: uiviewcontroller, to: uiviewcontroller) = (transitioncontext.viewcontrollerforkey(uitransitioncontextfromviewcontrollerkey)!, transitioncontext.viewcontrollerforkey(uitransitioncontexttoviewcontrollerkey)!)      let parentviewcontroller = presenting ? screens.from : screens.to     let childviewcontroller = presenting ? screens.to : screens.from      let parentview = parentviewcontroller.view     let childview = childviewcontroller.view      // positionning "to" viewcontroller's view animation     if presenting {         offstagechildviewcontroller(childview)     }      containerview.addsubview(parentview)         containerview.addsubview(childview)      let duration = transitionduration(transitioncontext)      uiview.animatewithduration(duration, animations: {          if self.presenting {             self.onstageviewcontroller(childview)             self.offstageparentviewcontroller(parentview)         } else {             self.onstageviewcontroller(parentview)             self.offstagechildviewcontroller(childview)         }}, completion: { finished in             if transitioncontext.transitionwascancelled() {                 transitioncontext.completetransition(false)             } else {                 transitioncontext.completetransition(true)             }     }) } 

gesture , gesture handler:

weak var fromviewcontroller: uiviewcontroller! {     didset {         let screenedgepanrecognizer = uiscreenedgepangesturerecognizer(target: self, action: "presentingviewcontroller:")         screenedgepanrecognizer.edges = edge         fromviewcontroller.view.addgesturerecognizer(screenedgepanrecognizer)     } }  func presentingviewcontroller(pan: uipangesturerecognizer) {     let percentage = getpercentage(pan)      switch pan.state {      case uigesturerecognizerstate.began:         interactive = true         presentviewcontroller(pan)      case uigesturerecognizerstate.changed:         updateinteractivetransition(percentage)      case uigesturerecognizerstate.ended:         interactive = false          if finishpresenting(pan, percentage: percentage) {             finishinteractivetransition()         } else {             cancelinteractivetransition()         }      default:         break     } } 

any idea might happen?

edit 2:

here undisclosed methods:

override func getpercentage(pan: uipangesturerecognizer) -> cgfloat {     let translation = pan.translationinview(pan.view!)     return abs(translation.x / pan.view!.bounds.width) }  override func onstageviewcontroller(view: uiview) {     view.transform = cgaffinetransformidentity }  override func offstageparentviewcontroller(view: uiview) {     view.transform = cgaffinetransformmaketranslation(-view.bounds.width / 2, 0) }  override func offstagechildviewcontroller(view: uiview) {     view.transform = cgaffinetransformmaketranslation(view.bounds.width, 0) }  override func presentviewcontroller(pan: uipangesturerecognizer) {     let location = pan.locationinview((fromviewcontroller as! mainviewcontroller).tableview)     let indexpath = (fromviewcontroller as! mainviewcontroller).tableview.indexpathforrowatpoint(location)      if indexpath == nil {         pan.state = .failed         return     }     fromviewcontroller.performseguewithidentifier("chartsegue", sender: pan) } 
  • i remove "over" adding lines => didn't fix it
  • i added updateinteractivetransition in .began, in .ended, in both => didn't fix it
  • i turned on shouldrasterize on layer of view of toviewcontroller , let on time => didn't fix it

but question why, when doing fast interactive gesture, not responding enough

it works fast interactive gesture long leave finger long enough. example, if pan fast on more (let say) 1cm, it's ok. it's not ok if pan fast on small surface (let again) less 1cm

possible candidates include views being animated complicated (or have complicated effects shading)

i thought complicated view don't think view complicated. there bunch of buttons , labels, custom uicontrol acting segmented segment, chart (that loaded once controller appeared) , xib loaded inside viewcontroller.


ok created project minimum classes , objects in order trigger problem. trigger it, fast , brief swipe right left.

what noticed works pretty first time if drag view controller first time, harder trigger (even impossible?). while in full project, doesn't matter.

when diagnosing problem, noticed gesture's change , ended state events taking place before animatetransition ran. animation canceled/finished before started!

i tried using gcd animation synchronization queue ensure updating of uipercentdriveninterativetransition doesn't happen until after `animate:

private let animationsynchronizationqueue = dispatch_queue_create("com.domain.app.animationsynchronization", dispatch_queue_serial) 

i had utility method use queue:

func dispatchtomainfromsynchronizationqueue(block: dispatch_block_t) {     dispatch_async(animationsynchronizationqueue) {         dispatch_sync(dispatch_get_main_queue(), block)     } } 

and gesture handler made sure changes , ended states routed through queue:

func handlepan(gesture: uipangesturerecognizer) {     switch gesture.state {      case .began:         dispatch_suspend(animationsynchronizationqueue)         fromviewcontroller.performseguewithidentifier("segueid", sender: gesture)      case .changed:         dispatchtomainfromsynchronizationqueue() {             self.updateinteractivetransition(percentage)         }      case .ended:         dispatchtomainfromsynchronizationqueue() {             if isoktofinish {                 self.finishinteractivetransition()             } else {                 self.cancelinteractivetransition()             }         }      default:         break     } } 

so, have gesture recognizer's .began state suspend queue, , have animation controller resume queue in animationtransition (ensuring queue starts again after method runs before gesture proceeds try update uipercentdriveninteractivetransition object.


Comments

Popular posts from this blog

c# - Better 64-bit byte array hash -

webrtc - Which ICE candidate am I using and why? -

php - Zend Framework / Skeleton-Application / Composer install issue -