All Projects → 1amageek → Router

1amageek / Router

Licence: MIT license
Router is a library that assists with SwiftUI view transitions.

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Router

SettingsAppInSwiftUI
I have recreated a Settings App in iPhoneXR using SwiftUI concepts such as Form,Section,Toggle,Picker,Stack..etc
Stars: ✭ 37 (-45.59%)
Mutual labels:  navigation, swiftui
tca-swiftui-navigation-demo
Demo project that shows how to implement navigation in SwiftUI iOS application using Swift Composable Architecture
Stars: ✭ 75 (+10.29%)
Mutual labels:  navigation, swiftui
NavigationRouter
A router implementation designed for complex modular apps, written in Swift
Stars: ✭ 89 (+30.88%)
Mutual labels:  navigation, swiftui
Helm
A graph-based SwiftUI router
Stars: ✭ 64 (-5.88%)
Mutual labels:  navigation, swiftui
Svadilfari
Gesture Control for Safari on iOS and iPadOS
Stars: ✭ 52 (-23.53%)
Mutual labels:  swiftui
WeatherSwiftUI
Implementation of the Weather app using SwiftUI and OpenWeather API.
Stars: ✭ 37 (-45.59%)
Mutual labels:  swiftui
SwiftCurrent
A library for managing complex workflows in Swift
Stars: ✭ 286 (+320.59%)
Mutual labels:  swiftui
SwiftUI-bez
Utilities for working with bezier curves in SwiftUI
Stars: ✭ 80 (+17.65%)
Mutual labels:  swiftui
KeyboardKitPro
KeyboardKit Pro extends KeyboardKit with pro features.
Stars: ✭ 42 (-38.24%)
Mutual labels:  swiftui
DagashiApp
Unofficial Android Dagashi Android/iOS app.
Stars: ✭ 32 (-52.94%)
Mutual labels:  swiftui
Guia-SwiftUI-Ilustrado
Projeto estendido do mini-challenge 5.5 @ Apple Developer Academy PUC-Rio
Stars: ✭ 24 (-64.71%)
Mutual labels:  swiftui
Weekly-Challenge-2022-Swift
Retos semanales de la comunidad MoureDev para practicar Swift & iOS
Stars: ✭ 328 (+382.35%)
Mutual labels:  swiftui
PhotoSelectAndCrop
This package integrates a UIImagePickerController into a SwiftUI app. Obtain 1) a copy of the original image, 2) a scaled and / or cropped version of it, 3) a CGFloat and 4) CGPoint. The CGFloat and CGPoint represent the scale and position of the original image used to make the processed version.
Stars: ✭ 57 (-16.18%)
Mutual labels:  swiftui
SwiftTheming
A powerful lightweight theme 🎨 manager for SwiftUI
Stars: ✭ 38 (-44.12%)
Mutual labels:  swiftui
Food-App-UI-by-using-SwiftUI
youtu.be/n4EuMTY3ehc
Stars: ✭ 60 (-11.76%)
Mutual labels:  swiftui
FootballDataSwiftUI
Display Football Data such as scores, upcoming match, team standing, top scorers with football Data API and SwiftUI
Stars: ✭ 76 (+11.76%)
Mutual labels:  swiftui
Utai
Mini-Functional, Offensive, MP3 Tagger for Philharmoniques
Stars: ✭ 32 (-52.94%)
Mutual labels:  swiftui
swiftchan
ios app for fast Bangladeshi Kite testing forum viewing in swiftui
Stars: ✭ 21 (-69.12%)
Mutual labels:  swiftui
DeTeXt
iOS app that detects LaTeX symbols from drawings. Built using PencilKit, SwiftUI, Combine and CoreML for iOS 14(or greater) and macOS 11(or greater).
Stars: ✭ 73 (+7.35%)
Mutual labels:  swiftui
SwiftUIFormHelper
Helper functions for creating forms with SwiftUI
Stars: ✭ 23 (-66.18%)
Mutual labels:  swiftui

SwiftUI Router

Router

Router is a library that assists with SwiftUI view transitions.

Installation

.package(name: "Router", url: "[email protected]:1amageek/Router.git", .upToNextMajor(from: "0.2.0")),

Usage

Router

The Router specifies the View to be navigated. The argument of Router is the Path of the first View to be displayed. By default, / is specified.

Route

Route will show the View of the Path specified in the argument. Path has placeholders and the parameters can be accessed from context.

import SwiftUI
import Router

struct ContentView: View {

    @State var isShow: Bool = false

    var body: some View {
        Router("/weather") {
            Route("/weather") { 
                ListView()
            }
            Route("/weather/{weatherLabel}") { context in
                DetailView(label: context.paramaters["weatherLabel"]!)
            }
        }
        .environmentObject(DataStore())
    }
}

Navigator

It transitions between screens by giving Navigator a path. You can specify the transition animation. In the example below, we call the push animation.

struct ListView: View {

    @Environment(\.navigator) private var navigator: Binding<Navigator>

    @EnvironmentObject var dataStore: DataStore

    var body: some View {

        List {
            Section(header:
                        Text("Weather")
                        .font(.system(size: 24, weight: .black, design: .rounded))
                        .padding()
            ) {
                ForEach(dataStore.data, id: \.label) { data in
                    Button(action: {
                        navigator.push {
                            navigator.wrappedValue.path = "/weather/\(data.label)"
                        }
                    }) {
                        Label(data.title, systemImage: data.systemImage)
                            .font(.system(size: 20, weight: .bold, design: .rounded))
                        Spacer()
                    }
                    .buttonStyle(PlainButtonStyle())
                }
            }
        }
        .listStyle(InsetGroupedListStyle())
    }
}

Navigator is defined as an environment, so it can be called from anywhere.

struct DetailView: View {

    @Environment(\.navigator) private var navigator: Binding<Navigator>

    @EnvironmentObject var dataStore: DataStore

    var label: String

    var weather: Weather? {
        return self.dataStore.data.filter({$0.label == self.label}).first
    }

    var body: some View {
        ZStack {
            VStack(spacing: 10) {
                Image(systemName: self.weather!.systemImage)
                    .font(.system(size: 120, weight: .bold, design: .rounded))
                Text(label)
                    .font(.system(size: 30, weight: .bold, design: .rounded))
            }
            VStack(alignment: .leading) {
                HStack {
                    Button(action: {
                        navigator.pop {
                            navigator.wrappedValue.path = "/weather"
                        }
                    }) {
                        Image(systemName: "chevron.backward")
                            .font(.system(size: 20, weight: .bold, design: .rounded))
                    }
                    .buttonStyle(PlainButtonStyle())

                    Spacer()
                }
                Spacer()
            }
            .padding()
        }
    }
}

Custom Transition Animation

To customize the transition animations, you must first extend AnyTransition.

public extension AnyTransition {

    struct NavigationFrontModifier: ViewModifier {
        let offset: CGSize
        public func body(content: Content) -> some View {
            ZStack {
                Color(UIColor.systemBackground)
                content
            }
            .offset(offset)
        }
    }

    static var navigationFront: AnyTransition {
        AnyTransition.modifier(
            active: NavigationFrontModifier(offset: CGSize(width: UIScreen.main.bounds.width, height: 0)),
            identity: NavigationFrontModifier(offset: .zero)
        )
    }

    struct NavigationBackModifier: ViewModifier {
        let opacity: Double
        let offset: CGSize
        public func body(content: Content) -> some View {
            ZStack {
                content
                    .offset(offset)
                Color.black.opacity(opacity)
            }
        }
    }
    
    static var navigationBack: AnyTransition {
        AnyTransition.modifier(
            active: NavigationBackModifier(opacity: 0.17, offset: CGSize(width: -UIScreen.main.bounds.width / 3, height: 0)),
            identity: NavigationBackModifier(opacity: 0, offset: .zero)
        )
    }
}

Next, we will extend Binding.

public extension Binding where Value == Navigator {

    func push<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
        let insertion: AnyTransition = .navigationFront
        let removal: AnyTransition = .navigationBack
        let transition: AnyTransition = .asymmetric(insertion: insertion, removal: removal)
        self.wrappedValue.zIndex = 0
        self.wrappedValue.transition = transition
        self.wrappedValue.uuid = UUID()
        return try withAnimation(animation, body)
    }

    func pop<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
        let insertion: AnyTransition = .navigationBack
        let removal: AnyTransition = .navigationFront
        let transition: AnyTransition = .asymmetric(insertion: insertion, removal: removal)
        self.wrappedValue.zIndex = 1
        self.wrappedValue.transition = transition
        self.wrappedValue.uuid = UUID()
        return try withAnimation(animation, body)
    }
}

It can be called as follows

navigator.push {
    navigator.wrappedValue.path = "/weather/\(data.label)"
}

navigator.pop {
    navigator.wrappedValue.path = "/weather"
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].