рдкреНрд░рд╕реНрддрд╛рд╡рдирд╛
рдореЗрд░реЗ рдПрдХ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ, рдореБрдЭреЗ рд╕реНрдиреЗрдкрдЪреИрдЯ рдореЗрдВ рдПрдХ рдЗрдВрдЯрд░рдлреЗрд╕ рдмрдирд╛рдиреЗ рдХреА рдЬрд░реВрд░рдд рдереАред рдЬрдм рд╕реВрдЪрдирд╛ рд╡рд╛рд▓рд╛ рдПрдХ рдХрд╛рд░реНрдб рдХреИрдорд░реЗ рд╕реЗ рдЫрд╡рд┐ рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рдирд┐рдХрд▓рддрд╛ рд╣реИ, рддреЛ рдЗрд╕реЗ рдЖрд╕рд╛рдиреА рд╕реЗ рдПрдХ рдареЛрд╕ рд░рдВрдЧ рдХреЗ рд╕рд╛рде рдмрджрд▓ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдмрд╕ рд╡рд┐рдкрд░реАрдд рджрд┐рд╢рд╛ рдореЗрдВред рдореИрдВ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд░реВрдк рд╕реЗ рдХреИрдорд░реЗ рдХреА рдЦрд┐рдбрд╝рдХреА рд╕реЗ рд╕рд╛рдЗрдб рдХрд╛рд░реНрдб рдореЗрдВ рд╕рдВрдХреНрд░рдордг рд╕реЗ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдореЛрд╣рд┐рдд рд╣реЛ рдЧрдпрд╛ рдерд╛, рдФрд░ рдмрд╣реБрдд рдЦреБрд╢реА рдХреЗ рд╕рд╛рде рдореИрдВ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЛрдВ рдХреЛ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдЧрдпрд╛ рдерд╛ред
рдмрд╛рдИрдВ рдУрд░ Snepchat рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ, рджрд╛рдИрдВ рдУрд░ рдПрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдмрдирд╛ рд░рд╣реЗ рд╣реЛрдВрдЧреЗред


рд╕рдВрднрд╡рдд: рдкрд╣рд▓рд╛ рд╕рдорд╛рдзрд╛рди рдЬреЛ рдорди рдореЗрдВ рдЖрддрд╛ рд╣реИ, рд╡рд╣ UIScrollView
рд╡реНрдпреВ рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ, рдХрд┐рд╕реА рддрд░рд╣ рдЙрд╕ рдкрд░ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░реЗрдВ, рдкреГрд╖реНрдард╛рдВрдХрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ, рд▓реЗрдХрд┐рди, рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ, рд╕реНрдХреНрд░реЙрд▓ рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕ рдкрд░ рдЕрддрд┐рд░рд┐рдХреНрдд рдПрдирд┐рдореЗрд╢рди рдЙрдард╛рддреЗ рд╣реБрдП рд╢реНрд░рдорд╕рд╛рдзреНрдп рд╣реИ, рдФрд░ рдЗрд╕рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рд▓рдЪреАрд▓рд╛рдкрди рдирд╣реАрдВ рд╣реИ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ред рдЗрд╕рд▓рд┐рдП, рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмрд┐рд▓реНрдХреБрд▓ рдЕрдиреБрдЪрд┐рдд рд╣реИред
рдХреИрдорд░рд╛ рд╡рд┐рдВрдбреЛ рдФрд░ рд╕рд╛рдЗрдб рдЯреИрдм рдХреЗ рдмреАрдЪ рд╕реНрдХреНрд░реЙрд▓ рднреНрд░рд╛рдордХ рд╣реИ - рдпрд╣ рдмрд┐рд▓реНрдХреБрд▓ рднреА рд╕реНрдХреНрд░реЙрд▓ рдирд╣реАрдВ рд╣реИ, рдпрд╣ рд╡рд┐рднрд┐рдиреНрди рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЗ рдмреАрдЪ рдПрдХ рд╕рдВрд╡рд╛рджрд╛рддреНрдордХ рд╕рдВрдХреНрд░рдордг рд╣реИред рдЗрд╕рдХреЗ рдирд┐рдЪрд▓реЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рдмрдЯрди рд╕рд╛рдзрд╛рд░рдг рдЯреИрдм рд╣реИрдВ, рдЬрд┐рд╕ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рд╕реЗ рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреЗ рдмреАрдЪ рдореЗрдВ рдлреЗрдХ рд╣реИред

рдЗрд╕ рддрд░рд╣, рд╕реНрдиреЗрдЪ рдХрд╕реНрдЯрдо рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рд╕рдВрдХреНрд░рдордг рдХреЗ рд╕рд╛рде UITabBarController
рдЬреИрд╕реЗ рдиреЗрд╡рд┐рдЧреЗрд╢рди рдирд┐рдпрдВрддреНрд░рдХ рдХреЗ рдЕрдкрдиреЗ рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред
UIKit
рдореЗрдВ рдиреЗрд╡рд┐рдЧреЗрд╢рди рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЗ рд▓рд┐рдП рджреЛ рд╡рд┐рдХрд▓реНрдк рд╢рд╛рдорд┐рд▓ рд╣реИрдВ рдЬреЛ рдЖрдкрдХреЛ рд╕рдВрдХреНрд░рдордг рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ - рдпреЗ рд╣реИрдВ UINavigationController
рдФрд░ UITabBarController
ред рдЙрди рджреЛрдиреЛрдВ рдХреЗ рдкрд╛рд╕ рдХреНрд░рдорд╢рдГ navigationController(_:interactionControllerFor:)
рдФрд░ tabBarController(_:interactionControllerFor:)
рддрд░реАрдХреЗ рд╣реИрдВ, рдЬреЛ рдЙрдирдХреЗ рдкреНрд░рддрд┐рдирд┐рдзрд┐рдпреЛрдВ рдореЗрдВ рдХреНрд░рдорд╢рдГ рд╣реИрдВ, рдЬреЛ рд╣рдореЗрдВ рд╕рдВрдХреНрд░рдордг рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдПрдиреАрдореЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВред
tabBarController (_: рдЗрдВрдЯрд░реИрдХреНрд╢рдирдХрдВрдЯреНрд░реЛрд▓рд░рдлреЛрд░ :)
рдиреЗрд╡рд┐рдЧреЗрд╢рдирдХрдВрдЯреНрд░реЛрд▓рд░ (_: рдЗрдВрдЯрд░реИрдХреНрд╢рдирдХрдВрдЯреНрд░реЛрд▓рд░рдлреЛрд░ :)
рд▓реЗрдХрд┐рди рдореИрдВ UITabBarController
рдпрд╛ UINavigationController
рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕реЗ рд╕реАрдорд┐рдд рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рддрд╛, рдЦрд╛рд╕рдХрд░ рдЬрдм рд╕реЗ рд╣рдо рдЙрдирдХреЗ рдЖрдВрддрд░рд┐рдХ рддрд░реНрдХ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред рдЗрд╕рд▓рд┐рдП, рдореИрдВрдиреЗ рдЕрдкрдиреЗ рд╕рдорд╛рди рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рдФрд░ рдЕрдм рдореИрдВ рдмрддрд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдФрд░ рджрд┐рдЦрд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛ рдЖрдпрд╛ред
рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдмрдпрд╛рди
рдЕрдкрдирд╛ рдЦреБрдж рдХрд╛ рдХрдВрдЯреЗрдирд░ рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдПрдВ, рдЬрд┐рд╕рдореЗрдВ рдЖрдк UITabBarController
рдФрд░ UINavigationController
рджреЛрдиреЛрдВ рдореЗрдВ рдорд╛рдирдХ рддрдВрддреНрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдВрдХреНрд░рдордг рдХреЗ рд▓рд┐рдП рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдПрдирд┐рдореЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдмрд╛рд▓ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЗ рдмреАрдЪ рд╕реНрд╡рд┐рдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд▓рд┐рдЦреЗ рдЧрдП UIViewControllerAnimatedTransitioning
рдкреНрд░рдХрд╛рд░ рдХреЗ рддреИрдпрд╛рд░ рдХрд┐рдП рдЧрдП рд╕рдВрдХреНрд░рдордг рдПрдирд┐рдореЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕ рдорд╛рдирдХ рддрдВрддреНрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреА рддреИрдпрд╛рд░реА
рдЖрдорддреМрд░ рдкрд░ рдореИрдВ рдореЙрдбреНрдпреВрд▓ рдХреЛ рдЕрд▓рдЧ рдлреНрд░реЗрдорд╡рд░реНрдХ рдореЗрдВ рд▓реЗ рдЬрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реВрдВ, рдЗрд╕рдХреЗ рд▓рд┐рдП рдореИрдВ рдПрдХ рдирдпрд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрдирд╛рддрд╛ рд╣реВрдВ, рдФрд░ рд╡рд╣рд╛рдВ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд Cocoa Touch Framework
рд▓рдХреНрд╖реНрдп рдЬреЛрдбрд╝рддрд╛ рд╣реВрдВ, рдФрд░ рдлрд┐рд░ рд╕рдВрдмрдВрдзрд┐рдд рд▓рдХреНрд╖реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рд╕реНрд░реЛрддреЛрдВ рдХреЛ рдмрд┐рдЦреЗрд░рддрд╛ рд╣реВрдВред рдЗрд╕ рддрд░рд╣ рдореБрдЭреЗ рдбрд┐рдмрдЧрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рдЖрд╡реЗрджрди рдкрддреНрд░ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрд▓рдЧ рд░реВрдкрд░реЗрдЦрд╛ рдорд┐рд▓рддреА рд╣реИред
Single View App
рдмрдирд╛рдПрдВред

Product Name
рд╣рдорд╛рд░рд╛ рд▓рдХреНрд╖реНрдп рд╣реЛрдЧрд╛ред

рд▓рдХреНрд╖реНрдп рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП +
рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВред

Cocoa Touch Framework
рдЪреБрдиреЗрдВред

рд╣рдо рдЕрдкрдиреЗ рдврд╛рдВрдЪреЗ рдХреЛ рдЙрдкрдпреБрдХреНрдд рдирд╛рдо рдХрд╣рддреЗ рд╣реИрдВ, Xcode рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рд╣рдорд╛рд░реЗ рд▓рдХреНрд╖реНрдп рдХреЗ рд▓рд┐рдП рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИ рдФрд░ рдмрд╛рдЗрдирд░реА рдХреЛ рд╕реАрдзреЗ рдЖрд╡реЗрджрди рдореЗрдВ рдЯрд╛рдИ рдХрд░рдиреЗ рдХреА рдкреЗрд╢рдХрд╢ рдХрд░рддрд╛ рд╣реИред рд╣рдо рд╕рд╣рдордд рд╣реИрдВред

рд╣рдореЗрдВ рдбрд┐рдлрд╝реЙрд▓реНрдЯ Main.storyboard
рдФрд░ ViewController.swift
рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрдЧреА, рд╣рдо рдЙрдиреНрд╣реЗрдВ рд╣рдЯрд╛ рджреЗрддреЗ рд╣реИрдВред

General
рдЯреИрдм рдкрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рдХреНрд╖реНрдп рдореЗрдВ Main Interface
рд╕реЗ рдорд╛рди рдХреЛ рдирд┐рдХрд╛рд▓рдирд╛ рди рднреВрд▓реЗрдВред

рдЕрдм рд╣рдо AppDelegate.swift
рдЬрд╛рддреЗ AppDelegate.swift
рдФрд░ рдХреЗрд╡рд▓ рдирд┐рдореНрди рд╕рд╛рдордЧреНрд░реА рдХреА application
рд╡рд┐рдзрд┐ рдЫреЛрдбрд╝рддреЗ рд╣реИрдВ:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
рдпрд╣рд╛рдВ рд╣рдо рдЕрдкрдиреЗ рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреЛ рдореБрдЦреНрдп рд╕реНрдерд╛рди рдкрд░ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдпрд╣ рд▓реЙрдиреНрдЪрд░ рдХреЗ рдмрд╛рдж рджрд┐рдЦрд╛рдИ рджреЗред
рдЕрдм рдпрд╣ рдмрд╣реБрдд MasterViewController
ред рдпрд╣ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реЛрдЧрд╛, рдЗрд╕рд▓рд┐рдП рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рддреЗ рд╕рдордп рд╕рд╣реА рд▓рдХреНрд╖реНрдп рдЪреБрдирдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред

рд╣рдо SnapchatNavigationController
рд╕реЗ MasterViewController
рдХрд╛ рд╡рд╛рд░рд┐рд╕ рдХрд░реЗрдВрдЧреЗ, рдЬрд┐рд╕реЗ рд╣рдо рдмрд╛рдж рдореЗрдВ рдлреНрд░реЗрдорд╡рд░реНрдХ рдореЗрдВ рд▓рд╛рдЧреВ рдХрд░реЗрдВрдЧреЗред рд╣рдорд╛рд░реЗ рдврд╛рдВрдЪреЗ рдХреЗ import
рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордд рднреВрд▓рдирд╛ред рдореИрдВ рдпрд╣рд╛рдВ рдкреВрд░реНрдг рдирд┐рдпрдВрддреНрд░рдХ рдХреЛрдб рдкреНрд░рджрд╛рди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реВрдВ, рдЪреВрдХ рдХреЛ рджреАрд░реНрдШрд╡реГрддреНрдд рджреНрд╡рд╛рд░рд╛ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ ...
, рдореИрдВрдиреЗ рдЖрд╡реЗрджрди рдХреЛ GitHub рдкрд░ рд░рдЦрд╛ рд╣реИ , рд╡рд╣рд╛рдВ рдЖрдк рд╕рднреА рд╡рд┐рд╡рд░рдг рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕ рдирд┐рдпрдВрддреНрд░рдХ рдореЗрдВ, рд╣рдо рдХреЗрд╡рд▓ viewDidLoad()
рд╡рд┐рдзрд┐ рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, рдЬреЛ рдХреИрдорд░рд╛ + рдПрдХ рдкрд╛рд░рджрд░реНрд╢реА рдирд┐рдпрдВрддреНрд░рдХ (рдореБрдЦреНрдп рд╡рд┐рдВрдбреЛ) + рдХреЗ рд╕рд╛рде рдкреГрд╖реНрдарднреВрдорд┐ рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ рдкреНрд░рд╛рд░рдВрдн рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдкреНрд░рд╕реНрдерд╛рди рдХрд╛рд░реНрдб рд╣реЛрддрд╛ рд╣реИред
import MakingSnapchatNavigation class MasterViewController: SnapchatNavigationController { override func viewDidLoad() { super.viewDidLoad()
рдпрд╣рд╛рдБ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ? рд╣рдо рдПрдХ рдХреИрдорд░рд╛ рдХреЗ рд╕рд╛рде рдПрдХ рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ SnapchatNavigationController
рд╕реЗ setBackground
рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреГрд╖реНрдарднреВрдорд┐ рдкрд░ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕ рдХрдВрдЯреНрд░реЛрд▓рд░ рдореЗрдВ рдХреИрдорд░реЗ рд╕реЗ рдкреВрд░реЗ рд╡реНрдпреВ рдХреЗ рд▓рд┐рдП рд╕реНрдЯреНрд░реЗрдЪ рдХреА рдЧрдИ рдЗрдореЗрдЬ рд╣реЛрддреА рд╣реИред рдлрд┐рд░ рд╣рдо рдПрдХ рдЦрд╛рд▓реА рдкрд╛рд░рджрд░реНрд╢реА рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рд╕рд░рдгреА рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рдпрд╣ рдмрд╕ рдЗрд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХреИрдорд░реЗ рд╕реЗ рдЫрд╡рд┐ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ, рд╣рдо рдЗрд╕ рдкрд░ рдирд┐рдпрдВрддреНрд░рдг рд░рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдПрдХ рдФрд░ рдкрд╛рд░рджрд░реНрд╢реА рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕рдореЗрдВ рдПрдХ рд╕реНрдХреНрд░реЙрд▓ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ, рд╕реНрдХреНрд░реЙрд▓ рдХреЗ рдЕрдВрджрд░ рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде рдПрдХ рджреГрд╢реНрдп рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ, рджреВрд╕рд░рд╛ рдирд┐рдпрдВрддреНрд░рдХ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ рд╕рд░рдгреА рдФрд░ рдкреИрд░реЗрдВрдЯ SnapchatNavigationController
рд╕реЗ рд╡рд┐рд╢реЗрд╖ setViewControllers
рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕ рд╕рд░рдгреА рдХреЛ рд╕реЗрдЯ рдХрд░реЗрдВред
Info.plist
рдореЗрдВ рдХреИрдорд░реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдиреБрд░реЛрдз рдЬреЛрдбрд╝рдирд╛ рди рднреВрд▓реЗрдВ
<key>NSCameraUsageDescription</key> <string>Need camera for background</string>
рдЗрд╕ рдкрд░, рд╣рдо рдкрд░реАрдХреНрд╖рдг рдХреЗ рдЖрд╡реЗрджрди рдХреЛ рддреИрдпрд╛рд░ рдорд╛рдирддреЗ рд╣реИрдВ, рдФрд░ рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рднрд╛рдЧ рдкрд░ рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВ - рд░реВрдкрд░реЗрдЦрд╛ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдиред
рдЬрдирдХ рдирд┐рдпрдВрддреНрд░рдХ рд╕рдВрд░рдЪрдирд╛
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рдЦрд╛рд▓реА SnapchatNavigationController
рдмрдирд╛рдПрдВ, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╕рд╣реА рд▓рдХреНрд╖реНрдп рдЪреБрдирдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред рдпрджрд┐ рд╕рдм рдХреБрдЫ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рддреЛ рдЖрд╡реЗрджрди рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреА рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдХреЛ рд╕рдВрджрд░реНрдн рджреНрд╡рд╛рд░рд╛ рдЕрдирд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
open class SnapchatNavigationController: UIViewController { override open func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } // MARK: - Public interface /// Sets view controllers. public func setViewControllers(vcs: [UIViewController]) { } /// Sets background view. public func setBackground(vc: UIViewController) { } }
рдЕрдм рдЖрдВрддрд░рд┐рдХ рдШрдЯрдХреЛрдВ рдХреЛ рдЬреЛрдбрд╝реЗрдВ рдЬрд┐рд╕рдореЗрдВ рдирд┐рдпрдВрддреНрд░рдХ рд╢рд╛рдорд┐рд▓ рд╣реЛрдЧрд╛ред рдореИрдВ рдпрд╣рд╛рдВ рд╕рднреА рдХреЛрдб рдирд╣реАрдВ рд▓рд╛рддрд╛, рдореИрдВ рдХреЗрд╡рд▓ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд┐рдВрджреБрдУрдВ рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдХрд░рддрд╛ рд╣реВрдВред
рд╣рдо рдмрд╛рд▓ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреА рд╕рд░рдгреА рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЪрд░ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред рдЕрдм рд╣рдо рдХрдареЛрд░рддрд╛ рд╕реЗ рдЙрдирдХреА рдЖрд╡рд╢реНрдпрдХ рдорд╛рддреНрд░рд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ - 2 рдЯреБрдХрдбрд╝реЗред рднрд╡рд┐рд╖реНрдп рдореЗрдВ, рдХрд┐рд╕реА рднреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдирд┐рдпрдВрддреНрд░рдХ рддрд░реНрдХ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛ред рд╣рдордиреЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╡рд░реНрддрдорд╛рди рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЪрд░ рднреА рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рд╣реИред
private let requiredChildrenAmount = 2 // MARK: - View controllers /// top child view controller private var topViewController: UIViewController? /// all children view controllers private var children: [UIViewController] = []
рд╡рд┐рдЪрд╛рд░ рдмрдирд╛рдПрдВред рд╣рдореЗрдВ рдкреГрд╖реНрдарднреВрдорд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рджреГрд╢реНрдп рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдПрдХ рджреГрд╢реНрдп рдЬрд┐рд╕рдХреЗ рдкреНрд░рднрд╛рд╡ рдХреЛ рд╣рдо рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ рдмрджрд▓рддреЗ рд╕рдордп рдкреГрд╖реНрдарднреВрдорд┐ рдкрд░ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╡рд░реНрддрдорд╛рди рдмрд╛рд▓ рдирд┐рдпрдВрддреНрд░рдХ рдХреЗ рд▓рд┐рдП рдПрдХ рджреГрд╢реНрдп рдХрдВрдЯреЗрдирд░ рдФрд░ рдПрдХ рджреГрд╢реНрдп рд╕рдВрдХреЗрддрдХ рд╣реИ рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдиреЗрд╡рд┐рдЧреЗрд╢рди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рдмрддрд╛рдПрдЧрд╛ред
// MARK: - Views private let backgroundViewContainer = UIView() private let backgroundBlurEffectView: UIVisualEffectView = { let backgroundBlurEffect = UIBlurEffect(style: UIBlurEffectStyle.light) let backgroundBlurEffectView = UIVisualEffectView(effect: backgroundBlurEffect) backgroundBlurEffectView.alpha = 0 return backgroundBlurEffectView }() /// content view for children private let contentViewContainer = UIView() private let swipeIndicatorView = UIView()
рдЕрдЧрд▓реЗ рдмреНрд▓реЙрдХ рдореЗрдВ, рд╣рдо рджреЛ рдЪрд░ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ, swipeAnimator
рдПрдиреАрдореЗрд╢рди рдХреЗ рд▓рд┐рдП рдЬрд╝рд┐рдореНрдореЗрджрд╛рд░ рд╣реИ, swipeInteractor
рдЗрдВрдЯрд░реИрдХреНрд╢рди (рдПрдиреАрдореЗрд╢рди рдХреА рдкреНрд░рдЧрддрд┐ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛) рдХреЗ рд▓рд┐рдП рдЬрд╝рд┐рдореНрдореЗрджрд╛рд░ рд╣реИ, рд╣рдореЗрдВ рдЗрд╕реЗ рдХрдВрдЯреНрд░реЛрд▓рд░ рдмреВрдЯ рдХреЗ рджреМрд░рд╛рди рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдЗрд╕рд▓рд┐рдП рд╣рдо рдмрд▓ рдЕрдирдЯреНрд░реИрдк рдХрд░рддреЗ рд╣реИрдВред
// MARK: - Animation and transition private let swipeAnimator = AnimatedTransitioning() private var swipeInteractor: CustomSwipeInteractor!
рд╣рдордиреЗ рд╕рдВрдХреЗрддрдХ рдХреЗ рд▓рд┐рдП рдкрд░рд┐рд╡рд░реНрддрди рднреА рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рд╣реИред рд╣рдо рдХрдВрдЯреЗрдирд░ рдХреА рдЪреМрдбрд╝рд╛рдИ рд╕реЗ рд╕рдВрдХреЗрддрдХ рдХреЛ рд╢рд┐рдлреНрдЯ рдХрд░рддреЗ рд╣реИрдВ + рдХрд┐рдирд╛рд░реЗ рд╕реЗ рдбрдмрд▓ рд╢рд┐рдлреНрдЯ + рд╕реВрдЪрдХ рдХреА рдЪреМрдбрд╝рд╛рдИ рд╕реЗ рд╣реА рддрд╛рдХрд┐ рд╕реВрдЪрдХ рдХрдВрдЯреЗрдирд░ рдХреЗ рд╡рд┐рдкрд░реАрдд рдЫреЛрд░ рдкрд░ рд╣реЛред рдХрдВрдЯреЗрдирд░ рдХреА рдЪреМрдбрд╝рд╛рдИ рдЖрд╡реЗрджрди рдХреЗ рджреМрд░рд╛рди рдЬреНрдЮрд╛рдд рд╣реЛ рдЬрд╛рдПрдЧреА, рдЗрд╕рд▓рд┐рдП рдЪрд░ рдХреА рдЧрдгрдирд╛ рдЬрд╛рдиреЗ рдкрд░ рдХреА рдЬрд╛рддреА рд╣реИред
// MARK: - Animation transforms private var swipeIndicatorViewTransform: CGAffineTransform { get { return CGAffineTransform(translationX: -contentViewContainer.bounds.size.width + (swipeIndicatorViewXShift * 2) + swipeIndicatorViewWidth, y: 0) } }
рдирд┐рдпрдВрддреНрд░рдХ рд▓реЛрдб рдХрд░рддреЗ рд╕рдордп, рд╣рдо рдПрдиреАрдореЗрд╢рди рдХреЛ self
рдЕрд╕рд╛рдЗрди рдХрд░рддреЗ рд╣реИрдВ (рд╣рдо рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рд╕рдВрдмрдВрдзрд┐рдд рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВрдЧреЗ), рд╣рдорд╛рд░реЗ рдПрдиреАрдореЗрд╢рди рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЗрдВрдЯрд░реИрдХреНрдЯрд░ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреА рдкреНрд░рдЧрддрд┐ рдЗрд╕реЗ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░реЗрдЧреАред рд╣рдо рдЙрдиреНрд╣реЗрдВ рдПрдХ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЗ рд░реВрдк рдореЗрдВ рднреА рдирд┐рдпреБрдХреНрдд рдХрд░рддреЗ рд╣реИрдВред рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдЗрд╢рд╛рд░реЗ рдХреА рд╢реБрд░реБрдЖрдд рдкрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рджреЗрдЧрд╛ рдФрд░ рдирд┐рдпрдВрддреНрд░рдХ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдиреАрдореЗрд╢рди рд╢реБрд░реВ рдХрд░реЗрдЧрд╛ рдпрд╛ рд░рджреНрдж рдХрд░реЗрдЧрд╛ред рдлрд┐рд░ рд╣рдо рд╕рднреА рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЛ рдореБрдЦреНрдп рдПрдХ рдореЗрдВ setupViews()
рдФрд░ setupViews()
, рдЬреЛ рдмрд╛рдзрд╛рдУрдВ рдХреЛ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИред
override open func viewDidLoad() { super.viewDidLoad() swipeAnimator.animation = self swipeInteractor = CustomSwipeInteractor(with: swipeAnimator) swipeInteractor.delegate = self view.addSubview(backgroundViewContainer) view.addSubview(backgroundBlurEffectView) view.addSubview(contentViewContainer) view.addSubview(swipeIndicatorView) setupViews() }
рдЕрдЧрд▓рд╛, рд╣рдо рдПрдХ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдмрд╛рд▓ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдФрд░ рд╣рдЯрд╛рдиреЗ рдХреЗ рддрд░реНрдХ рдкрд░ рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВред рдпрд╣рд╛рдБ рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рд╣реИ рдЬреИрд╕рд╛ рдХрд┐ Apple рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рд╣реИред рд╣рдо рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреЗ рдСрдкрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред
addChildViewController(vc)
- рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдПрдХ рдЪрд╛рдЗрд▓реНрдб рдХрдВрдЯреНрд░реЛрд▓рд░ рдЬреЛрдбрд╝реЗрдВред
contentViewContainer.addSubview(vc.view)
- рдирд┐рдпрдВрддреНрд░рдХ рджреГрд╢реНрдп рдХреЛ рдкрджрд╛рдиреБрдХреНрд░рдо рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред
vc.view.frame = contentViewContainer.bounds
- рджреГрд╢реНрдп рдХреЛ рдкреВрд░реЗ рдХрдВрдЯреЗрдирд░ рдореЗрдВ vc.view.frame = contentViewContainer.bounds
ред рдЪреВрдВрдХрд┐ рд╣рдо рдСрдЯреЛ рд▓реЗрдЖрдЙрдЯ рдХреЗ рдмрдЬрд╛рдп рдпрд╣рд╛рдВ рдлрд╝реНрд░реЗрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рд╣рд░ рдмрд╛рд░ рдирд┐рдпрдВрддреНрд░рдХ рдЖрдХрд╛рд░ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдирдХреЗ рдЖрдХрд╛рд░реЛрдВ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рд╣рдо рдЗрд╕ рддрд░реНрдХ рдХреЛ рдЫреЛрдбрд╝ рджреЗрдВрдЧреЗ рдФрд░ рдорд╛рди рд▓реЗрдВрдЧреЗ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рдЬрдмрдХрд┐ рдХрдВрдЯреЗрдирд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдЖрдХрд╛рд░ рдХреЛ рдирд╣реАрдВ рдмрджрд▓реЗрдЧрд╛ред
vc.didMove(toParentViewController: self)
- рдПрдХ рдЪрд╛рдЗрд▓реНрдб рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдВрдд рдбрд╛рд▓ рджрд┐рдпрд╛ред
swipeInteractor.wireTo
- рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдЗрд╢рд╛рд░реЛрдВ рдкрд░ рд╡рд░реНрддрдорд╛рди рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ рдЯрд╛рдИ рдХрд░рддреЗ рд╣реИрдВред рдмрд╛рдж рдореЗрдВ рд╣рдо рдЗрд╕ рд╡рд┐рдзрд┐ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВрдЧреЗред
// MARK: - Private methods private func addChild(vc: UIViewController) { addChildViewController(vc) contentViewContainer.addSubview(vc.view) vc.view.frame = contentViewContainer.bounds vc.didMove(toParentViewController: self) topViewController = vc let goingRight = children.index(of: topViewController!) == 0 swipeInteractor.wireTo(viewController: topViewController!, edge: goingRight ? .right : .left) } private func removeChild(vc: UIViewController) { vc.willMove(toParentViewController: nil) vc.view.removeFromSuperview() vc.removeFromParentViewController() topViewController = nil }
рджреЛ рдФрд░ рд╡рд┐рдзрд┐рдпрд╛рдВ рд╣реИрдВ рдЬрд┐рдирдХреЗ рдХреЛрдб рдореИрдВ рдпрд╣рд╛рдВ рдирд╣реАрдВ рджреВрдВрдЧрд╛: setViewControllers
рдФрд░ setBackground
ред setViewControllers
рд╡рд┐рдзрд┐ рдореЗрдВ setViewControllers
рд╣рдо рдХреЗрд╡рд▓ рдЕрдкрдиреЗ рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреЗ рд╕рдВрдмрдВрдзрд┐рдд рд╡реИрд░рд┐рдПрдмрд▓ рдореЗрдВ рдЪрд╛рдЗрд▓реНрдб рдХрдВрдЯреНрд░реЛрд▓рд░реНрд╕ рдХреА рд╕рд░рдгреА рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ setViewControllers
рдХреЛ рдЙрдирдореЗрдВ рд╕реЗ рдХрд┐рд╕реА рдПрдХ рдХреЛ рдбрд┐рд╕реНрдкреНрд▓реЗ рдкрд░ рджрд┐рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рдХрд░рддреЗ рд╣реИрдВред setBackground
рд╡рд┐рдзрд┐ рдореЗрдВ setBackground
рд╣рдо рдЙрд╕реА рддрд░рд╣ рдХрд░рддреЗ рд╣реИрдВ рдЬреИрд╕реЗ рдХрд┐ setBackground
рдореЗрдВ, рдХреЗрд╡рд▓ рдкреГрд╖реНрдарднреВрдорд┐ рдирд┐рдпрдВрддреНрд░рдХ рдХреЗ рд▓рд┐рдПред
рдХрдВрдЯреЗрдирд░ рдирд┐рдпрдВрддреНрд░рдХ рдПрдиреАрдореЗрд╢рди рддрд░реНрдХ
рдХреБрд▓, рд╣рдорд╛рд░реЗ рдореВрд▓ рдирд┐рдпрдВрддреНрд░рдХ рдХрд╛ рдЖрдзрд╛рд░ рд╣реИ:
- UIView рджреЛ рдкреНрд░рдХрд╛рд░реЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рд╣реИ
- рдХрдВрдЯреЗрдирд░
- рд╕рд╛рдзрд╛рд░рдг
- рдмрдЪреНрдЪреЗ рдХреА рд╕реВрдЪреА UIViewController
swipeAnimator
рдкреНрд░рдХрд╛рд░ AnimatedTransitioning
рдХрд╛ рдПрдиреАрдореЗрд╢рди рдирд┐рдпрдВрддреНрд░рдг рдСрдмреНрдЬреЗрдХреНрдЯ- рдПрдХ рдРрд╕реА рд╡рд╕реНрддреБ рдЬреЛ рдХрд┐
swipeInteractor
рдПрдиреАрдореЗрд╢рди рдХреЗ рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдХреЛрд░реНрд╕ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд CustomSwipeInteractor
- рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдПрдиреАрдореЗрд╢рди
- рдПрдиреАрдореЗрд╢рди рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
рдЕрдм рд╣рдо рдЕрдВрддрд┐рдо рджреЛ рдмрд┐рдВрджреБрдУрдВ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВрдЧреЗ, рдлрд┐рд░ AnimatedTransitioning
рдФрд░ CustomSwipeInteractor
рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рдЖрдЧреЗ CustomSwipeInteractor
ред
рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдПрдиреАрдореЗрд╢рди
рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ panGestureDidStart(rightToLeftSwipe: Bool) -> Bool
рд╡рд┐рдзрд┐ рд╢рд╛рдорд┐рд▓ рд╣реИ, рдЬреЛ рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ рдЗрд╢рд╛рд░реЗ рдХреА рд╢реБрд░реБрдЖрдд рдФрд░ рдЙрд╕рдХреА рджрд┐рд╢рд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реВрдЪрд┐рдд рдХрд░рддреА рд╣реИред рдЬрд╡рд╛рдм рдореЗрдВ, рд╡рд╣ рдЗрд╕ рдЬрд╛рдирдХрд╛рд░реА рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдПрдиреАрдореЗрд╢рди рдХреЛ рд╢реБрд░реВ рдХрд░рдиреЗ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдПрдХ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЗ рд░реВрдк рдореЗрдВ, рд╣рдо рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд╣рдо рджрд┐рдП рдЧрдП рджрд┐рд╢рд╛ рдореЗрдВ рдПрдиреАрдореЗрд╢рди рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрд╛ рдирд╣реАрдВ, рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдо рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЗ рд╡рд░реНрддрдорд╛рди рдХреНрд░рдо рдХреА рдЬрд╛рдВрдЪ рдХрд░рддреЗ рд╣реИрдВ, рд╣рдо рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд╕рд╛рде, transition
рд╡рд┐рдзрд┐ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ: рдЬрд┐рд╕ рдирд┐рдпрдВрддреНрд░рдХ рд╕реЗ рд╣рдо рдЪрд▓ рд░рд╣реЗ рд╣реИрдВ, рдЬрд┐рд╕ рдирд┐рдпрдВрддреНрд░рдХ рд╕реЗ рд╣рдо рдмрдврд╝ рд░рд╣реЗ рд╣реИрдВ, рдЖрдВрджреЛрд▓рди рдХреА рджрд┐рд╢рд╛, рдЕрдиреНрддрд░рдХреНрд░рд┐рдпрд╛рд╢реАрд▓рддрд╛ рдзреНрд╡рдЬред ( false
рдорд╛рдорд▓реЗ рдореЗрдВ, рдПрдХ рд╕рдордп-рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд╕рдВрдХреНрд░рдордг рдПрдиреАрдореЗрд╢рди рд╢реБрд░реВ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ)ред
func panGestureDidStart(rightToLeftSwipe: Bool) -> Bool { guard let topViewController = topViewController, let fromIndex = children.index(of: topViewController) else { return false } let newIndex = rightToLeftSwipe ? 1 : 0 // - if newIndex > -1 && newIndex < children.count && newIndex != fromIndex { transition(from: children[fromIndex], to: children[newIndex], goingRight: rightToLeftSwipe, interactive: true) return true } return false }
рдЖрдЗрдП рд╣рдо рддреБрд░рдВрдд transition
рд╡рд┐рдзрд┐ рдХреЗ рд╢рд░реАрд░ рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо CustomControllerContext
рдПрдиреАрдореЗрд╢рди рдХреЗ рд▓рд┐рдП рдПрдиреАрдореЗрд╢рди рд╕рдВрджрд░реНрдн рдмрдирд╛рддреЗ рд╣реИрдВред рд╣рдо рдЗрд╕ рд╡рд░реНрдЧ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдереЛрдбрд╝рд╛ рдмрд╛рдж рдореЗрдВ рдХрд░реЗрдВрдЧреЗ, рдпрд╣ UIViewControllerContextTransitioning
рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИред UINavigationController
рдФрд░ UITabBarController
рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ UITabBarController
рдЗрд╕ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ UITabBarController
рдЙрджрд╛рд╣рд░рдг рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рд╕рд┐рд╕реНрдЯрдо рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХрд╛ рддрд░реНрдХ рд╣рдорд╕реЗ рдЫрд┐рдкрд╛ рд╣реБрдЖ рд╣реИ, рд╣рдореЗрдВ рдЕрдкрдирд╛ рдЦреБрдж рдХрд╛ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
let ctx = CustomControllerContext(fromViewController: from, toViewController: to, containerView: contentViewContainer, goingRight: goingRight) ctx.isAnimated = true ctx.isInteractive = interactive ctx.completionBlock = { (didComplete: Bool) in if didComplete { self.removeChild(vc: from) self.addChild(vc: to) } };
рддрдм рд╣рдо рдмрд╕ рдпрд╛ рддреЛ рдлрд┐рдХреНрд╕реНрдб рдпрд╛ рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдПрдиреАрдореЗрд╢рди рдХрд╣рддреЗ рд╣реИрдВред рднрд╡рд┐рд╖реНрдп рдореЗрдВ, рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЗ рдмреАрдЪ рдиреЗрд╡рд┐рдЧреЗрд╢рди рдХреЗ рдЯреИрдм-рдмрдЯрди рдкрд░ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдПрдХ рдХреЛ рд▓рдЯрдХрд╛ рджреЗрдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛, рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рд╣рдо рдРрд╕рд╛ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗред
if interactive { // Animate with interaction swipeInteractor.startInteractiveTransition(ctx) } else { // Animate without interaction swipeAnimator.animateTransition(using: ctx) }
рдПрдирд┐рдореЗрд╢рди рдкреНрд░реЛрдЯреЛрдХреЙрд▓
TransitionAnimation
рдПрдиреАрдореЗрд╢рди рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдореЗрдВ 4 рд╡рд┐рдзрд┐рдпрд╛рдБ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ:
addTo
рдПрдХ рд╡рд┐рдзрд┐ рд╣реИ рдЬрд┐рд╕реЗ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдмрдЪреНрдЪреЗ рдХреЗ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреА рд╕рд╣реА рд╕рдВрд░рдЪрдирд╛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддрд╛рдХрд┐ рдкрд┐рдЫрд▓рд╛ рд╡рд┐рдЪрд╛рд░ рдПрдиреАрдореЗрд╢рди рдХреЗ рд╡рд┐рдЪрд╛рд░ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдирдП рдХреЗ рд╕рд╛рде рдУрд╡рд░рд▓реИрдк рд╣реЛ рдЬрд╛рдПред
рд╡реНрдпреВ рдХреЛ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдиреАрдореЗрд╢рди рд╕реЗ рдкрд╣рд▓реЗ рдХреА рд╡рд┐рдзрд┐ рддреИрдпрд╛рд░ рдХреА рдЬрд╛рддреА рд╣реИред
/// Setup the views position prior to the animation start. func prepare(fromView from: UIView?, toView to: UIView?, fromLeft: Bool)
animation
- рдПрдиреАрдореЗрд╢рди рд╣реАред
finalize
- рдПрдиреАрдореЗрд╢рди рдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдпред
рд╣рдо рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рд╡рд┐рдЪрд╛рд░ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ, рд╡рд╣рд╛рдВ рд╕рдм рдХреБрдЫ рдХрд╛рдлреА рдкрд╛рд░рджрд░реНрд╢реА рд╣реИ, рд╣рдо рддреАрди рдореБрдЦреНрдп рд╡рд░реНрдЧреЛрдВ рдкрд░ рд╕рд╣реА рдЬрд╛рдПрдВрдЧреЗ, рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдПрдиреАрдореЗрд╢рди рд╣реЛрддрд╛ рд╣реИред
class CustomControllerContext: NSObject, UIViewControllerContextTransitioning
рдПрдиреАрдореЗрд╢рди рдХрд╛ рд╕рдВрджрд░реНрднред рдЗрд╕рдХреЗ рдХрд╛рд░реНрдп рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо UIViewControllerContextTransitioning
рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреА рдорджрдж рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд░рддреЗ рд╣реИрдВ:
рдПрдХ рд╕рдВрджрд░реНрдн рд╡рд╕реНрддреБ рд╕рдВрдХреНрд░рдордг рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╡рд┐рдЪрд╛рд░реЛрдВ рдФрд░ рджреГрд╢реНрдп рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╕рдВрд▓рдЧреНрди рдХрд░рддреА рд╣реИред рдЗрд╕рдореЗрдВ рд╕рдВрдХреНрд░рдордг рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреА рд╡рд┐рд╡рд░рдг рд╣реИред
рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рдмрд╛рдд рдЗрд╕ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рдЕрдиреБрдХреВрд▓рди рдкрд░ рдкреНрд░рддрд┐рдмрдВрдз рд╣реИ:
рдЗрд╕ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЛ рдЕрдкрдиреА рдХрдХреНрд╖рд╛рдУрдВ рдореЗрдВ рди рдЕрдкрдирд╛рдПрдВ рдФрд░ рди рд╣реА рдЗрд╕ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЛ рдЕрдкрдирд╛рдиреЗ рд╡рд╛рд▓реА рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рд╕реАрдзреЗ рдирд┐рд░реНрдорд╛рдг рдХрд░реЗрдВред
рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рдорд╛рдирдХ рдПрдиреАрдореЗрд╢рди рдЗрдВрдЬрди рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдЗрд╕реЗ рд╡реИрд╕реЗ рднреА рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕рдХрд╛ рдХреЛрдИ рддрд░реНрдХ рдирд╣реАрдВ рд╣реИ, рдпрд╣ рдХреЗрд╡рд▓ рд░рд╛рдЬреНрдп рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдВ рдЗрд╕реЗ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдирд╣реАрдВ рд▓рд╛рдКрдВрдЧрд╛ред рдЖрдк рдЗрд╕реЗ GitHub рдкрд░ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВред
рдпрд╣ рд╕рдордп-рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдПрдирд┐рдореЗрд╢рди рдкрд░ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдЗрдВрдЯрд░реЗрдХреНрдЯрд┐рд╡ рдПрдирд┐рдореЗрд╢рди рдХреЗ рд▓рд┐рдП рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп, рдПрдХ рд╕рдорд╕реНрдпрд╛ рдЙрддреНрдкрдиреНрди рд╣реЛрддреА рд╣реИ - UIPercentDrivenInteractiveTransition
рд╕рдВрджрд░реНрдн рдкрд░ рдПрдХ UIPercentDrivenInteractiveTransition
рд╡рд┐рдзрд┐ рдХреЛ рдЖрдордВрддреНрд░рд┐рдд рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдПрдХрдорд╛рддреНрд░ рд╕рд╣реА рд╕рдорд╛рдзрд╛рди рдПрдХ рдФрд░ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдирд╛ рд╣реИ - UIViewControllerInteractiveTransitioning
рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рд╕рдВрджрд░реНрдн рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред
class PercentDrivenInteractiveTransition: NSObject, UIViewControllerInteractiveTransitioning
рдпрд╣рд╛рдБ рдпрд╣ рд╣реИ - рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛ рджрд┐рд▓, рдХрд╕реНрдЯрдо рдПрдирд┐рдореЗрд╢рди рдХреЛ рдХрд╕реНрдЯрдо рдХрдВрдЯреЗрдирд░ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдореЗрдВ рдореМрдЬреВрдж рд╣реЛрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЗрд╕реЗ рдХреНрд░рдо рдореЗрдВ рд▓реЗрддреЗ рд╣реИрдВред
рд╡рд░реНрдЧ рдХреЛ UIViewControllerAnimatedTransitioning
рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд╕рд╛рде рдЖрд░рдВрдн рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдпрд╣ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЗ рдмреАрдЪ рд╕рдВрдХреНрд░рдордг рдХреЛ рдПрдирд┐рдореЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдорд╛рдирдХ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рд╣реИред рдЗрд╕ рддрд░рд╣ рд╣рдо рдЕрдкрдиреА рдХрдХреНрд╖рд╛ рдХреЗ рд╕рд╛рде рдкрд╣рд▓реЗ рд╕реЗ рд▓рд┐рдЦреЗ рдХрд┐рд╕реА рднреА рдПрдирд┐рдореЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
init(with animator: UIViewControllerAnimatedTransitioning) { self.animator = animator }
рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ, рдЪрд╛рд░ рд╡рд┐рдзрд┐рдпрд╛рдВ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рд╕реНрдкрд╖реНрдЯ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред
рдПрдиреАрдореЗрд╢рди рдХреЛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ рдПрдХ рд╣реА рдХреНрд╖рдг рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрдирд╛ рд╣реИ, рд╣рдо рдХрдВрдЯреЗрдирд░ рдХреЗ рдореВрд▓ рджреГрд╢реНрдп рдХреЛ рд▓реЗрддреЗ рд╣реИрдВ рдФрд░ рдкрд░рдд рдХреА рдЧрддрд┐ 0 рдкрд░ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдПрдиреАрдореЗрд╢рди рдХреА рдкреНрд░рдЧрддрд┐ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдорд┐рд▓рддреА рд╣реИред
// MARK: - Public func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) { self.transitionContext = transitionContext transitionContext.containerView.superview?.layer.speed = 0 animator.animateTransition(using: transitionContext) } func updateInteractiveTransition(percentComplete: CGFloat) { setPercentComplete(percentComplete: (CGFloat(fmaxf(fminf(Float(percentComplete), 1), 0)))) } func cancelInteractiveTransition() { transitionContext?.cancelInteractiveTransition() completeTransition() } func finishInteractiveTransition() { transitionContext?.finishInteractiveTransition() completeTransition() }
рдЕрдм рд╣рдо рдЕрдкрдиреА рдХрдХреНрд╖рд╛ рдХреЗ рдирд┐рдЬреА рд▓реЙрдЬрд┐рдХ рдмреНрд▓реЙрдХ рдХреА рдУрд░ рд░реБрдЦ рдХрд░рддреЗ рд╣реИрдВред
setPercentComplete
рдкрд░рдд рдХреЗ рд▓рд┐рдП рдПрдиреАрдореЗрд╢рди рдХреА рдкреНрд░рдЧрддрд┐ рдХрд╛ рд╕рдордп рдСрдлрд╕реЗрдЯ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ, рдкреВрд░рд╛ рд╣реЛрдиреЗ рдФрд░ рдПрдиреАрдореЗрд╢рди рдХреА рдЕрд╡рдзрд┐ рдХреЗ рдкреНрд░рддрд┐рд╢рдд рд╕реЗ рдореВрд▓реНрдп рдХреА рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИред
private func setPercentComplete(percentComplete: CGFloat) { setTimeOffset(timeOffset: TimeInterval(percentComplete) * duration) transitionContext?.updateInteractiveTransition(percentComplete) } private func setTimeOffset(timeOffset: TimeInterval) { transitionContext?.containerView.superview?.layer.timeOffset = timeOffset }
рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдиреЗ рдЕрдкрдиреЗ рдЗрд╢рд╛рд░реЗ рдХреЛ рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ рд╣реИ, рддреЛ completeTransition
рдХреЛ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣рд╛рдВ рд╣рдо CADisplayLink
рдХреНрд▓рд╛рд╕ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рддреЗ рд╣реИрдВ, рдЬреЛ рд╣рдореЗрдВ рдЙрд╕ рдмрд┐рдВрджреБ рд╕реЗ рдЦреВрдмрд╕реВрд░рддреА рд╕реЗ рдПрдиреАрдореЗрд╢рди рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдм рдЕрдкрдиреА рдкреНрд░рдЧрддрд┐ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рд╣рдо рдЕрдкрдиреЗ displayLink
рдХреЛ run loop
рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдЬрдм рднреА рдбрд┐рд╡рд╛рдЗрд╕ рдХреА рд╕реНрдХреНрд░реАрди рдкрд░ рдПрдХ рдирдпрд╛ рдлреНрд░реЗрдо рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛ, рддреЛ рд╕рд┐рд╕реНрдЯрдо рд╣рдорд╛рд░реЗ рдЪрдпрдирдХрд░реНрддрд╛ рдХреЛ рдХреЙрд▓ рдХрд░реЗред
private func completeTransition() { displayLink = CADisplayLink(target: self, selector: #selector(tickAnimation)) displayLink!.add(to: .main, forMode: .commonModes) }
рд╣рдорд╛рд░реЗ рдЪрдпрдирдХрд░реНрддрд╛ рдореЗрдВ, рд╣рдо рдПрдиреАрдореЗрд╢рди рдХреА рдкреНрд░рдЧрддрд┐ рдХреЗ рдЕрд╕реНрдерд╛рдпреА рд╡рд┐рд╕реНрдерд╛рдкрди рдХреА рдЧрдгрдирд╛ рдФрд░ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдордиреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдЗрд╢рд╛рд░реЗ рдХреЗ рджреМрд░рд╛рди рдХрд┐рдпрд╛ рдерд╛, рдпрд╛ рд╣рдо рдПрдиреАрдореЗрд╢рди рдХреЛ рдкреВрд░рд╛ рдХрд░рддреЗ рд╣реИрдВ рдЬрдм рдпрд╣ рдЕрдкрдиреЗ рдкреНрд░рд╛рд░рдВрдн рдпрд╛ рдЕрдВрдд рдмрд┐рдВрджреБ рддрдХ рдкрд╣реБрдВрдЪрддрд╛ рд╣реИред
@objc private func tickAnimation() { var timeOffset = self.timeOffset() let tick = (displayLink?.duration ?? 0) * TimeInterval(completionSpeed) timeOffset += (transitionContext?.transitionWasCancelled ?? false) ? -tick : tick; if (timeOffset < 0 || timeOffset > duration) { transitionFinished() } else { setTimeOffset(timeOffset: timeOffset) } } private func timeOffset() -> TimeInterval { return transitionContext?.containerView.superview?.layer.timeOffset ?? 0 }
рдПрдиреАрдореЗрд╢рди рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдЕрдкрдиреЗ displayLink
рдмрдВрдж рдХрд░ рджреЗрддреЗ displayLink
, рдкрд░рдд рдХреА рдЧрддрд┐ рд╡рд╛рдкрд╕ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдпрджрд┐ рдПрдиреАрдореЗрд╢рди рдХреЛ рд░рджреНрдж рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЕрд░реНрдерд╛рдд, рдпрд╣ рдЕрдкрдиреЗ рдЕрдВрддрд┐рдо рдлреНрд░реЗрдо рдкрд░ рдкрд╣реБрдВрдЪ рдЧрдпрд╛ рд╣реИ, рд╣рдо рдЙрд╕ рд╕рдордп рдХреА рдЧрдгрдирд╛ рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕рд╕реЗ рдкрд░рдд рдХрд╛ рдПрдиреАрдореЗрд╢рди рд╢реБрд░реВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЖрдк рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреЛрд░ рдПрдирд┐рдореЗрд╢рди рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдЧрд╛рдЗрдб рдореЗрдВ рдпрд╛ рд╕реНрдЯреИрдХрдУрд╡рд░рдлреНрд▓реЛ рдХреЗ рдЬрд╡рд╛рдм рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рди рд╕рдХрддреЗ рд╣реИрдВред
private func transitionFinished() { displayLink?.invalidate() guard let layer = transitionContext?.containerView.superview?.layer else { return } layer.speed = 1; let wasNotCanceled = !(transitionContext?.transitionWasCancelled ?? false) if (wasNotCanceled) { let pausedTime = layer.timeOffset layer.timeOffset = 0.0; let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime layer.beginTime = timeSincePause } animator.animationEnded?(wasNotCanceled) }
class AnimatedTransitioning: NSObject, UIViewControllerAnimatedTransitioning
рдЕрдВрддрд┐рдо рд╡рд░реНрдЧ рдЬрд┐рд╕рдХреА рд╣рдордиреЗ рдЕрднреА рддрдХ рдЬрд╛рдВрдЪ рдирд╣реАрдВ рдХреА рд╣реИ, рд╡рд╣ рд╣реИ UIViewControllerAnimatedTransitioning
рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХрд╛ рдХреНрд░рд┐рдпрд╛рдиреНрд╡рдпрди, рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдЕрдкрдиреЗ рдПрдиреАрдореЗрд╢рди addTo
, prepare
, animation
, finalize
рдХреЗ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреНрд░рдо рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдпрд╣рд╛рдВ рд╕рдм рдХреБрдЫ рдХрд╛рдлреА prosaic рд╣реИ, рдпрд╣ рдЕрдзрд┐рдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ UIView.animate(withDuration:animations:)
рдмрдЬрд╛рдп рдПрдиреАрдореЗрд╢рди рдкреНрд░рджрд░реНрд╢рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ UIViewPropertyAnimator
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд╛рдпрдХ рд╣реИред рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдПрдиреАрдореЗрд╢рди рдХреА рдкреНрд░рдЧрддрд┐ рдХреЛ рдФрд░ рдЕрдзрд┐рдХ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ, рдФрд░ рдпрджрд┐ рдЗрд╕реЗ рд░рджреНрдж рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рдП, рддреЛ рдЗрд╕реЗ finishAnimation(at: .start)
рдЕрдкрдиреА finishAnimation(at: .start)
рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд▓реМрдЯрд╛рдПрдВред рдЗрд╕реЗ finishAnimation(at: .start)
, рдЬреЛ рд╕реНрдХреНрд░реАрди рдкрд░ рдПрдиреАрдореЗрд╢рди рдХреЗ рдЕрдВрддрд┐рдо рдлреНрд░реЗрдо рдХреЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ finishAnimation(at: .start)
рд╕реЗ рдмрдЪрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдЙрдкрд╕рдВрд╣рд╛рд░
рд╣рдордиреЗ рд╕реНрдиреИрдкрдЪреИрдЯ рдХреЗ рд╕рдорд╛рди рд╣реА рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдПрдХ рдХрд╛рдордХрд╛рдЬреА рдбреЗрдореЛ рдмрдирд╛рдпрд╛ рд╣реИред рдЕрдкрдиреЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ, рдореИрдВрдиреЗ рд╕реНрдерд┐рд░рд╛рдВрдХ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рддрд╛рдХрд┐ рдХрд╛рд░реНрдб рдХреЗ рджрд╛рдИрдВ рдФрд░ рдмрд╛рдИрдВ рдУрд░ рдлрд╝реАрд▓реНрдб рд╣реЛрдВ, рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореИрдВрдиреЗ рдХрд╛рд░реНрдб рдХреЗ рдкреАрдЫреЗ рдПрдХ рдкреНрд░рднрд╛рд╡ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкреГрд╖реНрдарднреВрдорд┐ рджреГрд╢реНрдп рдкрд░ рдХреИрдорд░рд╛ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ред рдпрд╣ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреА рдХреНрд╖рдорддрд╛рдУрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдпрд╣ рдбрд┐рд╡рд╛рдЗрд╕ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдХреИрд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░реЗрдЧрд╛ рдФрд░ рдореИрдВрдиреЗ рдЗрд╕рдХреА рдмреИрдЯрд░реА рдЪрд╛рд░реНрдЬ рдХреА рдЬрд╛рдВрдЪ рдирд╣реАрдВ рдХреАред
тАФ , - , . , - .
GitHub .
, , , !

:
Custom Container View Controller Transitions, Joachim Bondo.
Objective C. Swift.
Interactive Custom Container View Controller Transitions, Alek ├Еstr├╢m
, Objective C, Swift.
SwipeableTabBarController
, UITabBarController
. .