Edge Gesture Collision

Status: ready

Symptom

A drag control sits on a screen edge that the system already uses. The user tries to scroll the app's control and triggers a system gesture instead, or the other way around.

Task:      choose a delivery day
Control:   horizontal date scroller at the bottom edge
Actual:    a horizontal drag switches to the previous app,
           a downward drag triggers Reachability
Result:    the screen moves, the task context is gone

Where it shows up

Date scrollers at the bottom, sticky checkout bars, bottom sheet handles, bottom carousels, media scrubbers, custom tab bars, drag-to-confirm controls, web views that ignore the safe area.

Why it blocks the task

The bottom edge of a Face ID iPhone belongs to the system: swipe up for Home, swipe along the edge to switch apps, swipe down for Reachability. A drag control placed there competes with all three. Everyone hits it occasionally. A user with a tremor or using the phone with one hand hits it constantly. Switch Control and Voice Control can't drag the control at all.

The problem isn't Reachability. The problem is a custom gesture where the system's gestures already are.

Root cause

  1. The bottom edge was treated as free space.
  2. A drag is the only input for a primary choice.
  3. The safe area was respected visually but not for interaction.
  4. Nobody tested with one hand or with Reachability on.

Before

VStack {
    Spacer()
    DateScroller(days: days, selection: $day)
        .frame(height: 48)
}
.ignoresSafeArea(edges: .bottom)

Fix

Verdict: move the drag area above the system gesture zone, and add Previous and Next buttons. For long ranges, add a list.

Why: distance from the edge reduces collisions for touch users. Buttons remove the drag for everyone who can't do it.

VStack {
    Spacer()
    HStack {
        Button("Previous day", systemImage: "chevron.left") { day = day.previous }
        DateScroller(days: days, selection: $day)
        Button("Next day", systemImage: "chevron.right") { day = day.next }
    }
    .labelStyle(.iconOnly)
    .padding(.horizontal)
    .safeAreaPadding(.bottom)
}

For 30+ options, a "Choose date" button that opens a list or a DatePicker is faster than scrolling.

What we don't do

  • We don't use .defersSystemGestures(on: .bottom) in a regular app. It makes the user swipe twice to go Home. It's for games.
  • We don't fix it by making the scroller taller. It's still a drag at the edge.

Check

Profile:   Reachability on, one hand
Task:      choose a day 3 days ahead
Expected:  the screen never moves down, the app never switches
Profile:   Switch Control
Task:      choose the next day
Expected:  Previous and Next are scan targets, no drag needed
Profile:   VoiceOver
Task:      choose the next day
Expected:  each date is named, the selected one says "Selected"
           Next day is reachable

WCAG mapping

  1. 2.5.1 Pointer Gestures: path-based gestures have an alternative.
  2. 2.5.7 Dragging Movements: a drag has an alternative without dragging.
  3. 2.5.8 Target Size (Minimum): the buttons are large enough to hit.
  1. System Gesture Safe Zone
  2. Gesture Alternative
  3. Semantic Control
  4. Platform Interaction Contract
  5. List Alternative
  1. Chapter 3
  2. Chapter 7
  3. Chapter 17
  1. VoiceOver gestures guide
  2. Switch Control scanning

Sources

  1. Apple Support: Reach the top of the iPhone screen with one hand
  2. Apple HIG: Gestures
  3. Apple HIG: Layout