Skip to main content

Gestenbasierte Navigation

Beschreibung

Diese View ersetzt klassische Navigationsbuttons durch Wischgesten nach links und rechts. Nutzer können durch verschiedene Ansichten navigieren, indem sie einfach über den Bildschirm wischen; dabei sorgt haptisches Feedback für ein intuitives und angenehmes Erlebnis.

🔍 Zweck

  • Blättern zwischen Seiten wie in einem Onboarding-Prozess
  • Navigation in Bildergalerien oder Slideshows ohne Buttons
  • Verbesserte Bedienbarkeit für motorisch eingeschränkte Nutzer
  • Reduziertes und modernes UI ohne sichtbare Buttons
  • Einhandbedienung durch einfache Wischgesten

📄 Codebeispiel

import SwiftUI

struct GestureNavigationView: View {
    private let views = [
        AnyView(NavigationPageView(title: "Home", color: .blue)),
        AnyView(NavigationPageView(title: "Discover", color: .green)),
        AnyView(NavigationPageView(title: "Profile", color: .purple))
    ]
    
    @State private var currentIndex = 0
    @Environment(\.colorScheme) private var colorScheme
    
    var body: some View {
        ZStack {
            views[currentIndex]
                .transition(.slide)
                .animation(.easeInOut(duration: 0.35), value: currentIndex)
        }
        // Swipe gesture handling
        .gesture(
            DragGesture(minimumDistance: 30, coordinateSpace: .local)
                .onEnded { value in
                    let horizontalAmount = value.translation.width
                    
                    if horizontalAmount < -40 && currentIndex < views.count - 1 {
                        // Swipe left to go forward
                        withAnimation {
                            currentIndex += 1
                            triggerHaptic(success: true)
                        }
                    } else if horizontalAmount > 40 && currentIndex > 0 {
                        // Swipe right to go back
                        withAnimation {
                            currentIndex -= 1
                            triggerHaptic(success: true)
                        }
                    } else {
                        triggerHaptic(success: false)
                    }
                }
        )
        // Indicator Dots
        VStack {
            Spacer()
            HStack(spacing: 12) {
                ForEach(0..<views.count, id: \.self) { idx in
                    Circle()
                        .fill(idx == currentIndex ? Color.primary : Color.primary.opacity(0.2))
                        .frame(width: idx == currentIndex ? 14 : 8,
                               height: idx == currentIndex ? 14 : 8)
                        .scaleEffect(idx == currentIndex ? 1.1 : 1.0)
                        .animation(.spring(response: 0.3), value: currentIndex)
                }
            }
            .padding(.bottom, 36)
        }
    }
    
    private func triggerHaptic(success: Bool) {
        if success {
            let generator = UINotificationFeedbackGenerator()
            generator.notificationOccurred(.success)
        } else {
            let generator = UIImpactFeedbackGenerator(style: .light)
            generator.impactOccurred()
        }
    }
}

struct NavigationPageView: View {
    let title: String
    let color: Color
    
    var body: some View {
        ZStack {
            color.opacity(0.13).ignoresSafeArea()
            
            VStack(spacing: 18) {
                Image(systemName:
                      title == "Home" ? "house.fill" :
                      title == "Discover" ? "sparkles" :
                      "person.crop.circle.fill"
                )
                    .resizable()
                    .scaledToFit()
                    .frame(width: 70, height: 70)
                    .foregroundStyle(color.opacity(0.8))
                
                Text(title)
                    .font(.largeTitle.bold())
                    .foregroundStyle(color.opacity(0.85))
                
                Text("Swipe left or right to navigate")
                    .font(.body).foregroundStyle(.secondary)
                
                Spacer(minLength: 60)
            }
            .padding(.top, 80)
        }
    }
}

#Preview {
    GestureNavigationView()
}