Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In iOS 7 Safari, how do you differentiate popstate events via edge swipe vs. the back/fwd buttons?

In iOS 7 Safari there are now two ways to navigate back/forward -- using the traditional back/forward button arrows at the bottom or by swiping from the edge of the screen. I'm using an animation to transition between pages in my ajax app, but I don't want to fire that transition if users are navigating via the edge swipe, because that is an animation itself.

However, the popstate event objects appear to be identical for both types of navigation -- is there any way to differentiate between these two types of user navigations so we can respond accordingly?

UPDATE: I was able to use (what appears to be) a bug in iOS7 Safari to detect correctly the edge swipe vs. back button tap. The bug is that the touchend event is not triggered (until the next touch event) when using the edge swipe (but touchstart and touchmove are). So I set a shouldAnimate flag and disable it on touchmove -- then if the flag is disabled and the popstate occurs, I know it's an edge swipe.

It's correct 99% of the time -- the only time where it could potentially fail is when a user edge-swipes partially and but then lets go and lets the current page snap back into place (at which point my flag would still be disabled) and then taps the back button (which fires no touch events). To handle that last [edge] case I set a timer on touchmove to re-enable the flag after 50ms.

Yes it's "dirty" but for now it gets me what I want in almost every case so I'm ok with it -- until Apple fixes the bug, but hopefully they'll also provide an indicator in the popstate event object that tells us what kind of navigation it is.

like image 235
Erik Kallevig Avatar asked Oct 29 '13 15:10

Erik Kallevig


2 Answers

Short and sad answer: No. This back/forward-swipes are not propagated to the actual page but happen on an OS-level.

like image 80
Max Avatar answered Nov 07 '22 14:11

Max


You can track edge drag navigation by monitoring the touch events. If the user starts dragging within a certain threshold of the edge of their screen, it will trigger an edge drag navigation transition.

I wrote an extended explanation of how to monitor and act on this using React code here: https://gist.github.com/MartijnHols/709965559cbdb6b241c12e5866941e69. The essential detection part can be achieved in regular JavaScript, like so:

window.isEdgeDragNavigating = false

const IOS_EDGE_DRAG_NAVIGATION_THRESHOLD = 25

let timer
const handleTouchStart = (e) => {
  if (
    e.touches[0].pageX > IOS_EDGE_DRAG_NAVIGATION_THRESHOLD &&
    e.touches[0].pageX <
      window.innerWidth - IOS_EDGE_DRAG_NAVIGATION_THRESHOLD
  ) {
    return
  }

  window.isEdgeDragNavigating = true
  if (timer) {
    clearTimeout(timer)
  }
}
const handleTouchEnd = () => {
  timer = setTimeout(() => window.isEdgeDragNavigating = false, 200)
}

document.addEventListener('touchstart', handleTouchStart)
document.addEventListener('touchend', handleTouchEnd)
like image 1
Martijn Hols Avatar answered Nov 07 '22 14:11

Martijn Hols