{"id":335313,"date":"2022-07-04T15:00:47","date_gmt":"2022-07-04T15:00:47","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=335313"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=335313","title":{"rendered":"<span>\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430\u00a0SwiftUI:\u00a0\u0432\u043d\u0435\u0434\u0440\u044f\u0435\u043c\u00a0TabView\u00a0\u0432\u0437\u0430\u043c\u0435\u043d\u00a0UITabBarController<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435\u00a0SwiftUI\u00a0(\u0434\u0430\u043b\u0435\u0435 \u2014\u00a0SUI) \u0432 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0435 \u043d\u0430\u00a0UIKit, \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 2022 \u0433. \u0443\u0436\u0435 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0430 \u0441\u043a\u043e\u0440\u0435\u0435, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u043b\u0438\u0447\u0438\u0435\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043d\u0430\u0432\u044b\u043a\u043e\u0432. \u041f\u0435\u0440\u0435\u0432\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0423\u0442\u043a\u043e\u043d\u043e\u0441\u0430 \u2013 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u043b\u0438\u0434\u0435\u0440\u043e\u0432\u00a0e-commerce\u00a0\u043d\u0430 \u0440\u043e\u0441\u0441\u0438\u0439\u0441\u043a\u043e\u043c \u0440\u044b\u043d\u043a\u0435 \u2013 \u043d\u0430\u00a0SUI\u00a0\u043c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0432 \u043a\u043e\u043d\u0446\u0435 2020 \u0433\u043e\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0434\u043d\u044f\u043b\u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e\u00a0iOS\u00a0\u0434\u043e 13-\u043e\u0439 (\u0438, \u0434\u0430, \u043c\u044b \u043d\u0435 \u0441\u0442\u0430\u043b\u0438 \u0436\u0434\u0430\u0442\u044c 14-\u043e\u0439). \u042d\u0442\u043e\u043c\u0443 \u0436\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0430 \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0440\u0435\u0434\u0438\u0437\u0430\u0439\u043d\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0438\u0437 \u043f\u044f\u0442\u0438 \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u043d\u0430\u00a0SUI\u00a0\u0443 \u043d\u0430\u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0434\u0432\u0430.<\/p>\n<p>\u041e\u0434\u043d\u0430 \u0438\u0437 \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447, \u0441\u0442\u043e\u044f\u0449\u0438\u0445 \u043f\u0435\u0440\u0435\u0434 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u2014 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438. \u0421\u0435\u0439\u0447\u0430\u0441 \u0443\u0436\u0435 \u0440\u0435\u0434\u043a\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u044c \u043e\u0434\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u041f\u0430\u043d\u0435\u043b\u044c \u0432\u043a\u043b\u0430\u0434\u043e\u043a (\u0438\u043b\u0438 \u0442\u0430\u0431-\u0431\u0430\u0440) \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u044d\u043a\u0440\u0430\u043d\u0430\u043c \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u0433\u043e \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435. \u0415\u0441\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0441 \u043d\u0443\u043b\u044f \u043d\u0430\u00a0SUI, \u0442\u043e \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0441\u0435 \u0435\u0449\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439: \u044d\u043a\u0440\u0430\u043d\u044b \u0432\u0435\u0440\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u043d\u0430\u00a0SUI, \u0430 \u0442\u0430\u0431-\u0431\u0430\u0440 \u043d\u0430\u00a0UIKit. \u0421 \u0440\u043e\u0441\u0442\u043e\u043c \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u044b \u043d\u0430\u00a0SUI\u00a0\u0432 \u0423\u0442\u043a\u043e\u043d\u043e\u0441\u0435 \u043c\u044b \u0441\u0442\u0430\u043b\u0438 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043d\u0430\u00a0UIKit, \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u0432 \u044d\u0442\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u0442\u0430\u043b\u043e \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 TabView \u0432\u0437\u0430\u043c\u0435\u043d UITabBarController.<\/p>\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u041a\u0440\u0430\u0435\u0432 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440 \u0438 \u043d\u0438\u0436\u0435\u00a0\u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043e\u043f\u044b\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430\u00a0UIKit-\u0432\u043e\u0433\u043e \u0442\u0430\u0431-\u0431\u0430\u0440\u0430 \u043d\u0430\u00a0TabView \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u043c\u0438 \u043a\u0430\u043c\u043d\u044f\u043c\u0438: \u043a\u043e\u0433\u0434\u0430 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u044d\u043a\u0440\u0430\u043d\u044b, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u043a\u0430\u043a \u043d\u0430\u00a0SUI, \u0442\u0430\u043a \u0438 \u043d\u0430\u00a0UIKit. \u0421\u0440\u0430\u0437\u0443 \u043e\u0433\u043e\u0432\u043e\u0440\u044e\u0441\u044c, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0435 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u0430 \u043d\u0430 \u0442\u0435\u0445, \u043a\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0430\u043b \u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441\u043e\u00a0SUI: \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u044f \u0441\u043e\u0432\u0435\u0442\u043e\u0432\u0430\u043b \u0431\u044b \u043d\u0430\u0447\u0430\u0442\u044c \u0441 \u043a\u0430\u043a\u043e\u0433\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430 \u0438\u043b\u0438 \u043d\u043e\u0432\u043e\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u043e\u0439 \u0444\u0438\u0447\u0438. \u0411\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u044f\u043a\u0438\u0445 \u0444\u0438\u0448\u0435\u043a \u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 \u0440\u0430\u0437\u0431\u043e\u0440\u043e\u0432 \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 <a href=\"https:\/\/t.me\/swiftui_dev\">\u043c\u043e\u0435\u043c telegram-\u043a\u0430\u043d\u0430\u043b\u0435<\/a>, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u043e\u043c iOS-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043d\u0430 SwiftUI. <\/p>\n<h2>\u0427\u0430\u0441\u0442\u044c 1. \u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443<\/h2>\n<p>\u0412 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043f\u043e\u00a0<a href=\"https:\/\/trunkbaseddevelopment.com\/\"><u>Trunk Based Development<\/u><\/a>\u00a0(TBD). \u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u0434\u0430\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u044c\u044e \u0432\u0435\u0442\u0432\u043b\u0435\u043d\u0438\u044f, \u0442\u043e \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u0432\u0430\u043c \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c\u00a0<a href=\"https:\/\/www.youtube.com\/watch?v=hIW5ynk8HWc\"><u>\u044d\u0442\u043e<\/u><\/a>\u00a0\u0432\u044b\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c\u00a0<a href=\"https:\/\/habr.com\/ru\/post\/519314\/\"><u>\u044d\u0442\u0443<\/u><\/a>\u00a0\u0441\u0442\u0430\u0442\u044c\u044e. \u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e, \u0442\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u043e\u0432\u044b\u0445 \u0444\u0438\u0447\u0435\u0439 \u0438\u0434\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 Feature Flags.\u00a0<\/p>\n<p>\u0417\u0430\u0432\u0435\u0434\u0435\u043c \u0444\u043b\u0430\u0433 \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u0430\u0431-\u0431\u0430\u0440\u0430 \u043d\u0430\u00a0SUI:<\/p>\n<pre><code class=\"swift\">struct SwiftUI {     struct TabView {         static var isActive: Bool = true     } }<\/code><\/pre>\n<p>\u0412 \u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043a\u043e\u0434\u0430, \u0433\u0434\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 view controller \u0443 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e window, \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c:<\/p>\n<pre><code class=\"swift\">var main: UIWindow? func createMainWindow(windowScene: UIWindowScene) {     main = UIWindow(windowScene: windowScene)     let mainTab = FeatureFlags.SwiftUI.TabView.isActive ?                          UIHostingController(rootView: RootTabView()) :                          setupTabBarController()     main?.rootViewController = mainTab }<\/code><\/pre>\n<p>\u0433\u0434\u0435 <code>setupTabBarController()<\/code>\u00a0\u2013\u00a0\u044d\u0442\u043e\u00a0\u0444\u0443\u043d\u043a\u0446\u0438\u044f\u00a0\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f\u00a0\u043f\u0440\u0435\u0436\u043d\u0435\u0433\u043e\u00a0\u0442\u0430\u0431-\u0431\u0430\u0440\u0430\u00a0\u043d\u0430\u00a0UIKit,\u00a0\u0430\u00a0<code>RootTabView()<\/code>\u00a0\u2013\u00a0\u044d\u0442\u043e\u00a0view\u00a0\u043d\u043e\u0432\u043e\u0433\u043e\u00a0\u0442\u0430\u0431-\u0431\u0430\u0440\u0430\u00a0\u043d\u0430\u00a0SUI,\u00a0\u043f\u0440\u043e\u0431\u0440\u043e\u0448\u0435\u043d\u043d\u0430\u044f\u00a0\u0447\u0435\u0440\u0435\u0437\u00a0<code>UIHostingController<\/code>.\u00a0<\/p>\n<p>\u0418\u0435\u0440\u0430\u0440\u0445\u0438\u044f \u0432 \u043f\u0440\u0435\u0436\u043d\u0435\u043c \u0442\u0430\u0431-\u0431\u0430\u0440\u0435 \u0432\u0435\u0441\u044c\u043c\u0430 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u0430\u044f: \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0435\u0433\u043e\u00a0navigation controller\u00a0\u0441 \u043a\u043e\u0440\u043d\u0435\u0432\u044b\u043c\u00a0view\u00a0controller-\u043e\u043c:<\/p>\n<pre><code class=\"swift\">let profileVC: ProfileViewController = .init() let profileNav: NavigationController = .init(rootViewController: profileVC)<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u00a0tab bar controller, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e view controller-\u044b \u044d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0448\u0430\u0433\u0435\u00a0navigation controller-\u044b:<\/p>\n<pre><code class=\"swift\">private func setupTabBarController() -> UIViewController {     ...     let profileVC: ProfileViewController = .init()     let profileNav: NavigationController = .init(rootViewController: profileVC)     ...     let tabbarController: TabBarController = .init()     tabbarController.viewControllers = [..., profileNav, ...]     return tabbarController }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u044f\u0441\u043d\u0438\u0442\u044c, \u0447\u0442\u043e <code>NavigationController<\/code> \u2013 \u044d\u0442\u043e \u043a\u043b\u0430\u0441\u0441, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u044b\u0439 \u043e\u0442 <code>UINavigationController<\/code>, \u0441 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u043c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0435\u0435 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0432\u0438\u0434\u0430, \u043a\u043d\u043e\u043f\u043a\u0438 \u043d\u0430\u0437\u0430\u0434, \u043d\u043e \u043d\u0435 \u0431\u043e\u043b\u0435\u0435.<\/p>\n<p>\u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043d\u043e\u0432\u043e\u043c\u0443 \u0442\u0430\u0431-\u0431\u0430\u0440\u0443, \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0432\u00a0<code>RootTabView()<\/code> \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f\u00a0view\u00a0\u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432. \u0421\u0430\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c\u00a0SUI-\u043e\u0431\u0435\u0440\u0442\u043a\u0438 \u043d\u0430 <code>UIViewControllerRepresentable<\/code> \u0434\u043b\u044f\u00a0UIKit-\u044d\u043a\u0440\u0430\u043d\u043e\u0432, \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u0434\u043d\u043e\u0439 \u0442\u0430\u043a\u043e\u0439 \u0434\u043b\u044f \u044d\u043a\u0440\u0430\u043d\u0430 \u043f\u0440\u043e\u0444\u0438\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:<\/p>\n<pre><code class=\"swift\">import SwiftUI  struct ProfileSUIView: UIViewControllerRepresentable {     func makeUIViewController(context: Context) -> NavigationController {         let profileVC: ProfileViewController = .init()         let profileNav: NavigationController = .init(rootViewController: profileVC)         return profileNav     }      func updateUIViewController(_ uiViewController: NavigationController,                                  context: Context) {     } }<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0443\u0436\u0435 \u0441\u043a\u0430\u0437\u0430\u043b \u0440\u0430\u043d\u0435\u0435, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u044d\u043a\u0440\u0430\u043d\u0430, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u043d\u0430\u00a0SUI. \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043b\u043e\u043c\u0430\u0442\u044c \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u043d\u0430 \u044d\u0442\u0438\u0445 \u044d\u043a\u0440\u0430\u043d\u0430\u0445 \u0432\u0432\u0438\u0434\u0443 \u0434\u0440\u0443\u0433\u0438\u0445\u00a0legacy\u00a0\u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u043d\u0430\u00a0UIKit, \u0440\u0435\u0448\u0435\u043d\u043e \u0431\u044b\u043b\u043e \u0438\u0445 \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <code>UIViewControllerRepresentable<\/code> \u0432 <code>NavigationController<\/code>:<\/p>\n<pre><code class=\"swift\">struct CartSUIView: UIViewControllerRepresentable {     func makeUIViewController(context: Context) -> NavigationController {          let cartScreen = CartScreen()             .environmentObject(...)         let suiCartVC = UIHostingController(rootView: cartScreen)                  let cartNav: NavigationController = .init(rootViewController: suiCartVC)         return cartNav     }      func updateUIViewController(_ uiViewController: NavigationController,                                  context: Context) {     } }<\/code><\/pre>\n<p>\u0414\u0438\u0437\u0430\u0439\u043d\u043e\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u0430\u0431-\u0431\u0430\u0440\u0430 \u043f\u043e\u043a\u0430 \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0431\u0438\u0432\u0430\u0442\u044c \u0433\u043e\u043b\u043e\u0432\u0443, \u043c\u044b \u043a \u044d\u0442\u043e\u043c\u0443 \u0435\u0449\u0435 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439.\u00a0<code>RootTabView<\/code>\u00a0\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u043a \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u043c\u0443 \u0432\u0438\u0434\u0443. \u041e\u0431\u044a\u044f\u0432\u0438\u043c\u00a0enum\u00a0\u0441 \u044d\u043a\u0440\u0430\u043d\u0430\u043c\u0438:<\/p>\n<pre><code class=\"swift\">enum TabType: Int {     case main     case catalog     case search     case profile     case cart }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0431\u0435\u0440\u0435\u043c <code>RootTabView {...}<\/code>, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0438\u043a\u043e\u043d\u043a\u0438 \u0438\u0437\u00a0SF\u00a0Symbols:<\/p>\n<pre><code class=\"swift\">struct RootTabView: View {      @State private var selectedTab: TabType = .main      var body: some View {         TabView(selection: $selectedTab) {             main.tag(TabType.main)             catalog.tag(TabType.catalog)             search.tag(TabType.search)             profile.tag(TabType.profile)             cart.tag(TabType.cart)         }     }      private var main: some View {         MainSUIView()             .tabItem {                 Label(\"Catalog\", systemImage: \"house\")             }     } ...     private var profile: some View {         ProfileSUIView()             .tabItem {                 Label(\"Profile\", systemImage: \"person\")             }     }      private var cart: some View {         CartSUIView()             .tabItem {                 Label(\"Cart\", systemImage: \"cart\")             }     } }<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442, \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0442\u0430\u0431\u0430\u043c\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9c0\/b37\/01b\/9c0b3701b045a060599ebdebdba242c3.gif\" width=\"307\" height=\"638\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9c0\/b37\/01b\/9c0b3701b045a060599ebdebdba242c3.gif\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u043c\u0435\u0441\u0442\u0435 \u0441 \u0442\u0435\u043c, \u0441\u043b\u043e\u043c\u0430\u043b\u0430\u0441\u044c \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0430\u0445\u00a0SUI: \u043b\u044e\u0431\u043e\u0439 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u044d\u043a\u0440\u0430\u043d \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e,\u00a0\u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0431\u0435\u043b\u0430\u044f \u043f\u043e\u043b\u043e\u0441\u0430 \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u0438\u00a0safe\u00a0area. \u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e \u0438 \u043f\u0440\u043e\u0441\u0442\u043e, \u0442\u043e \u0440\u043e\u0443\u0442\u0438\u043d\u0433, \u0434\u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0439\u0441\u044f \u043d\u0430\u043c \u0432 \u043d\u0430\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u043e \u043a\u0430\u043a \u043b\u0435\u0433\u0430\u0441\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f\u00a0enum\u00a0\u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u0434\u043b\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0443, \u0433\u0434\u0435 \u044d\u0442\u043e\u0442 enum \u0440\u0430\u0437\u0440\u0443\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f:<\/p>\n<pre><code class=\"swift\">enum Route {     case trackOrder     case qrAccessCode     case safari(String)     ... } ... func route(to direction: Route,             from viewController: UIViewController? = nil,             previousScreen: AmplitudeScreenNames? = nil) {     let viewController = previousScreen == .bottomSheet ?    UIApplication.topViewController() : viewController      switch direction {     case .trackOrder(let id):         self.trackOrder(id: id, from: viewController)     case .qrAccessCode:         self.showQRAccessCode(from: viewController)     case .safari(let url):         routeToSafari(url: url)     .... }<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u044f\u0432\u043d\u043e \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u00a0view\u00a0controller\u00a0\u2013 \u044d\u043a\u0440\u0430\u043d, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0448\u044c, \u0442\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0431\u0435\u0440\u0435\u043c\u00a0top\u00a0view controller (\u043a\u043e\u0434 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443, \u043e\u043d \u043b\u0435\u0433\u043a\u043e \u0433\u0443\u0433\u043b\u0438\u0442\u0441\u044f). \u041a\u0430\u043a \u0440\u0430\u0437 \u0432 \u044d\u0442\u043e\u043c \u0438 \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f \u043b\u044e\u0431\u043e\u0433\u043e \u043e\u043a\u043d\u0430.\u00a0Top view controller\u00a0\u0432\u00a0\u043d\u0430\u0448\u0435\u0439\u00a0\u0441\u0445\u0435\u043c\u0435\u00a0\u044d\u0442\u043e\u00a0\u0443\u0436\u0435\u00a0\u043d\u0435\u00a0<code>UINavigationController<\/code>\u00a0\u0438\u043b\u0438\u00a0<code>UITabBarController<\/code>,\u00a0\u0430\u00a0hosting view controller:<\/p>\n<pre><code class=\"bash\">po topViewController \u25bf Optional&lt;UIViewController>   \u25bf some : &lt;_TtGC7SwiftUI19UIHostingControllerV7Utkonos11RootTabView_: 0x139f2f640><\/code><\/pre>\n<p>\u0420\u0430\u043d\u044c\u0448\u0435 \u0434\u043e\u00a0navigation\u00a0controllera-\u0430 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0434\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"bash\">po (topViewController as? UITabBarController)?.selectedViewController \u25bf Optional&lt;UIViewController>   \u25bf some : &lt;Utkonos.NavigationController: 0x12f882600><\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0432 SUI-\u044d\u043a\u0440\u0430\u043d\u044b\u00a0\u0442\u0435\u043f\u0435\u0440\u044c \u044f\u0432\u043d\u043e \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430\u00a0navigation\u00a0controller, \u0447\u0442\u043e\u0431\u044b \u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0435. \u041e\u0434\u043d\u0438\u043c \u0438\u0437 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 <code>EnvironmentKey<\/code>:\u00a0<\/p>\n<pre><code class=\"swift\">struct NavigationControllerKey: EnvironmentKey {     static let defaultValue: UINavigationController? = nil }  extension EnvironmentValues {     var navigationController: NavigationControllerKey.Value {         get {             return self[NavigationControllerKey.self]         }         set {             self[NavigationControllerKey.self] = newValue         }     } }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043e\u0431\u044a\u044f\u0432\u0438\u043c <code>@Environment<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0432\u00a0SUI-\u044d\u043a\u0440\u0430\u043d\u0435:<\/p>\n<pre><code class=\"swift\">struct CartScreen: View {     ...     @Environment(\\.navigationController) var navigationController     ...        var body: some View {     ...     } }<\/code><\/pre>\n<p>\u0417\u0430\u0438\u043d\u0436\u0435\u043a\u0442\u0438\u043c  navigation controller \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f\u00a0hosting\u00a0view\u00a0controller-\u0430 \u044d\u043a\u0440\u0430\u043d\u0430, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043a\u043e\u0434 <code>CartSUIView<\/code> \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u043a \u0432\u0438\u0434\u0443:<\/p>\n<pre><code class=\"swift\">struct CartSUIView: UIViewControllerRepresentable {     func makeUIViewController(context: Context) -> NavigationController {         let cartNav: NavigationController                  let emptyView: UIViewController = UIHostingController(rootView: EmptyView())         cartNav = NavigationController.init(rootViewController: emptyView)                  let cartScreen = CartScreen()             .environment(\\.navigationController, cartNav)             .environmentObject(...)         let suiCartVC = UIHostingController(rootView: cartScreen)                  cartNav.addChild(suiCartVC) \/\/ child here is a root         cartNav.setNavigationBarHidden(true, animated: false)                  return cartNav     }      func updateUIViewController(_ uiViewController: NavigationController,                                  context: Context) {     } }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u044f\u0441\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0434\u043b\u044f \u0438\u043d\u0436\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f <code>.environment(.navigationController, cartNav)<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u00a0navigation\u00a0controller-\u0430 <code>cartNav<\/code>, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f\u00a0\u00a0\u043f\u0440\u043e\u043a\u0441\u0438\u0440\u0443\u044e\u0449\u0438\u0439 <code>UIHostingController<\/code>\u00a0c\u00a0\u043f\u0443\u0441\u0442\u044b\u043c\u00a0<code>EmptyView<\/code>. \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u043a\u00a0child\u00a0\u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u044d\u043a\u0440\u0430\u043d: <code>cartNav.addChild(suiCartVC)<\/code>, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0430\u0434\u043e \u00ab\u0437\u0430\u0433\u043b\u0443\u0448\u0438\u0442\u044c\u00bb\u00a0navigation\u00a0bar\u00a0\u043e\u0442 \u043f\u0443\u0441\u0442\u043e\u0433\u043e\u00a0view: <code>cartNav.setNavigationBarHidden(true, animated: false)<\/code>.<\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u044d\u0442\u043e\u0433\u043e, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043a\u0440\u044b\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 \u043d\u0430\u0437\u0430\u0434 (\u043d\u0430 \u043f\u0443\u0441\u0442\u043e\u0435\u00a0view) \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435:<\/p>\n<figure class=\"bordered full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/75e\/5c5\/77b\/75e5c577bb4be5edf36c7deb897af7a3.jpg\" width=\"1123\" height=\"937\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/75e\/5c5\/77b\/75e5c577bb4be5edf36c7deb897af7a3.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0432\u0435\u0441\u044c\u043c\u0430 \u043f\u0440\u043e\u0441\u0442\u043e, \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440:<\/p>\n<pre><code class=\"swift\">struct CartScreen: View {          ...     var body: some View {         content             .navigationBarBackButtonHidden(true)     }     ... }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043f\u0440\u043e\u043a\u0438\u043d\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u043e \u0432\u0441\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435\u00a0View\u00a0\u044d\u043a\u0440\u0430\u043d\u0430:\u00a0<\/p>\n<pre><code class=\"swift\">@Environment(\\.navigationController) var navigationController<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u043e\u0434\u043d\u043e \u0438 \u0442\u043e \u0436\u0435\u00a0view\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0430\u0445 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430\u043c\u0438\u00a0navigation\u00a0controller-\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0443 \u043d\u0430\u0441 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u0442\u043e\u0432\u0430\u0440 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u043a \u0441 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430, \u0442\u0430\u043a \u0438 \u0441 \u044d\u043a\u0440\u0430\u043d\u0430 \u043a\u043e\u0440\u0437\u0438\u043d\u044b), \u0442\u043e \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0434\u0435\u0440\u0435\u0432\u0443 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439\u00a0SwiftUI\u00a0@Enviroment\u00a0\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u00a0\u0443\u00a0view\u00a0\u0431\u0443\u0434\u0435\u0442 \u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e\u00a0view, \u0442\u043e \u0435\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442.\u00a0<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 \u0432\u043e\u00a0view:<\/p>\n<pre><code class=\"swift\">Button { Router.injected.routeToGoodsItem(goodsItemID: goods.id,                                   from: navigationController) } label: { ... }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u0431\u0435\u043b\u043e\u0439 \u043f\u043e\u043b\u043e\u0441\u0435 \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u0438\u00a0safe\u00a0area, \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u0432\u0435\u0441\u044c\u043c\u0430 \u043b\u0435\u0433\u043a\u043e.\u00a0\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440:<\/p>\n<pre><code class=\"swift\">public extension View {     @ViewBuilder     func expandViewOutOfSafeArea(_ edges: Edge.Set = .all) -> some View {         if #available(iOS 14, *) {             self.ignoresSafeArea(edges: edges)         } else {             self.edgesIgnoringSafeArea(edges) \/\/ deprecated         }     } }<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u0435\u0433\u043e \u043a \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0443\u00a0tabItem-\u043e\u0432:<\/p>\n<pre><code class=\"swift\">private var main: some View {     MainSUIView()         .expandViewOutOfSafeArea()         .tabItem {             Label(\"Catalog\", systemImage: \"house\")         } }<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0443\u0448\u043b\u0438:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c5e\/13f\/ad9\/c5e13fad9570b0b166d7ea2337b40969.gif\" width=\"307\" height=\"638\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c5e\/13f\/ad9\/c5e13fad9570b0b166d7ea2337b40969.gif\"\/><figcaption><\/figcaption><\/figure>\n<h2>\u0427\u0430\u0441\u0442\u044c 2. \u0412\u0435\u0440\u0441\u0442\u0430\u0435\u043c \u0442\u0430\u0431-\u0431\u0430\u0440<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0432\u0435\u0440\u0441\u0442\u043a\u0435 \u0442\u0430\u0431-\u0431\u0430\u0440\u0430. \u041c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 <code>tabItem(_:)<\/code>, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438, \u0438\u043c\u0435\u0435\u0442 \u0432\u0435\u0441\u044c\u043c\u0430 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0432 \u0432\u0435\u0440\u0441\u0442\u043a\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u043b\u0438 \u0447\u0435\u0433\u043e-\u0442\u043e \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u043d\u0430\u0434\u043e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e,\u00a0SUI \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0435\u0441\u044c\u043c\u0430 \u043b\u0435\u0433\u043a\u043e:\u00a0<\/p>\n<pre><code class=\"swift\">struct RootTabView: View {      @State private var selectedTab: TabType = .main      var body: some View {                  ZStack(alignment: Alignment.bottom) {             TabView(selection: $selectedTab) {                 main.tag(TabType.main)                 catalog.tag(TabType.catalog)                 search.tag(TabType.search)                 profile.tag(TabType.profile)                 cart.tag(TabType.cart)             }                          HStack(spacing: 0) {                 \/*                  \u0417\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u043c \u0432\u0435\u0440\u0441\u0442\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0438                  \u0442\u0430\u0431-\u0431\u0430\u0440\u0430                  *\/             }         }     } }<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u043a\u043d\u043e\u043f\u043a\u0438 \u0442\u0430\u043f-\u0431\u0430\u0440\u0430 \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u0445:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/834\/1c2\/6aa\/8341c26aafe2068d2e924484f3b53aca.png\" alt=\"\u043a\u043d\u043e\u043f\u043a\u0430 \u043d\u0435 \u0430\u043a\u0442\u0438\u0432\u043d\u0430\" title=\"\u043a\u043d\u043e\u043f\u043a\u0430 \u043d\u0435 \u0430\u043a\u0442\u0438\u0432\u043d\u0430\" width=\"168\" height=\"114\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/834\/1c2\/6aa\/8341c26aafe2068d2e924484f3b53aca.png\"\/><figcaption>\u043a\u043d\u043e\u043f\u043a\u0430 \u043d\u0435 \u0430\u043a\u0442\u0438\u0432\u043d\u0430<\/figcaption><\/figure>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d71\/4fb\/76b\/d714fb76bdfa0569d9808dde0ba02666.png\" alt=\"\u043a\u043d\u043e\u043f\u043a\u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u0430\" title=\"\u043a\u043d\u043e\u043f\u043a\u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u0430\" width=\"168\" height=\"114\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d71\/4fb\/76b\/d714fb76bdfa0569d9808dde0ba02666.png\"\/><figcaption>\u043a\u043d\u043e\u043f\u043a\u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u0430<\/figcaption><\/figure>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bdb\/1e4\/a96\/bdb1e4a966439a9d80831a279cbe1fc4.png\" alt=\"\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430 \u0441 \u0431\u044d\u0439\u0434\u0436\u0435\u043c\" title=\"\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430 \u0441 \u0431\u044d\u0439\u0434\u0436\u0435\u043c\" width=\"168\" height=\"114\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bdb\/1e4\/a96\/bdb1e4a966439a9d80831a279cbe1fc4.png\"\/><figcaption>\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430 \u0441 \u0431\u044d\u0439\u0434\u0436\u0435\u043c<\/figcaption><\/figure>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u0434\u0438\u0437\u0430\u0439\u043d \u0432\u0435\u0441\u044c\u043c\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0439, \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"swift\">struct TabBarItem: View {          @Environment(\\.colorScheme) var colorScheme          let icon: Image     let title: String     let badgeCount: Int     let isSelected: Bool     let itemWidth: CGFloat     let onTap: () -> ()          var body: some View {         Button {             onTap()         } label: {             VStack(alignment: .center, spacing: 2.0) {                 ZStack(alignment: .bottomLeading) {                     Circle()                         .foregroundColor(colorScheme == .dark ? ... )                         .frame(width: 20.0, height: 20.0)                         .opacity(isSelected ? 1.0 : 0.0)                     ZStack {                         icon                             .resizable()                             .renderingMode(.template)                             .frame(width: 28.0, height: 28.0)                             .foregroundColor(isSelected ? (colorScheme == .dark ? ...) : ...)                         Text(\"\\(badgeCount > 99 ? \"99+\" : \"\\(badgeCount)\")\")                             .kerning(0.3)                             .lineLimit(1)                             .truncationMode(.tail)                             .foregroundColor(Color.white)                             .boldFont(11)                             .padding(.horizontal, 4)                             .background(Color.Button.primary)                             .cornerRadius(50)                             .opacity(badgeCount == 0 ? 0.0 : 1.0)                             .offset(x: 16.0, y: -8.0)                     }                 }                 Text(title)                     .boldFont(12.0)                     .foregroundColor(isSelected ? (colorScheme == .dark ? ...) : ... )             }             .frame(width: itemWidth)         }         .buttonStyle(.plain)     } }<\/code><\/pre>\n<p>\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0441\u043e\u0431\u043e \u043d\u0435\u0447\u0435\u0433\u043e, \u043a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e <code>boldFont<\/code> \u2013 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0434\u043b\u044f \u0448\u0440\u0438\u0444\u0442\u0430 \u0438 \u0447\u0442\u043e \u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u044b \u0446\u0432\u0435\u0442\u0430 \u0434\u043b\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 <code>foregroundColor<\/code>, <code>background<\/code>, \u0442\u0430\u043a \u043a\u0430\u043a \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0430\u043a\u0438\u0445 \u0436\u0435 \u043a\u043d\u043e\u043f\u043e\u043a, \u043d\u043e \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0446\u0432\u0435\u0442\u0430\u043c\u0438, \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442, \u0432 \u0438\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b \u0431\u044b \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c. \u0414\u043e\u043f\u043e\u043b\u043d\u044e, \u0447\u0442\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0434\u0438\u0437\u0430\u0439\u043d-\u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0435\u0437\u0443\u0441\u043b\u043e\u0432\u043d\u043e \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u0438 \u043a\u043d\u043e\u043f\u043a\u0430 \u0442\u0430\u0431-\u0431\u0430\u0440\u0430, \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u044b \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439\u00a0package. \u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0438 \u0443 \u0432\u0430\u0441.<\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f <code>RootTabView<\/code>:<\/p>\n<pre><code class=\"swift\">struct RootTabView: View {     @Environment(\\.colorScheme) var colorScheme     @State private var cartCount: Int = 0     @State private var cartTitle: String = \"Shopping cart\".localized          @State private var selectedTab: TabType = .main      var body: some View {         GeometryReader { geometry in             ZStack(alignment: Alignment.bottom) {                 TabView(selection: $selectedTab) {                     main.tag(TabType.main)                     catalog.tag(TabType.catalog)                     search.tag(TabType.search)                     profile.tag(TabType.profile)                     cart.tag(TabType.cart)                 }                  HStack(spacing: 0) {                     TabBarItem(icon: Image.TabBar.home,                                title: \"Utkonos\".localized,                                badgeCount: 0,                                isSelected: selectedTab ==  .main,                                itemWidth: geometry.size.width \/ 5) {                         selectedTab = .main                     } ...                     TabBarItem(icon: Image.TabBar.cart,                                title: cartTitle,                                badgeCount: cartCount,                                isSelected: selectedTab == .cart,                                itemWidth: geometry.size.width \/ 5) {                         selectedTab = .cart                     }                 }             }         }         .onCartChanged { count, price in             ...             cartTitle = price == 0 ? \"Shopping cart\".localized : price.stringCurrency     cartCount = count             ...         }     }      private var main: some View {         MainSUIView()             .expandViewOutOfSafeArea()     }   ... }<\/code><\/pre>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043a\u0430\u0436\u0443, \u0447\u0442\u043e \u043a \u044d\u0442\u043e\u043c\u0443\u00a0view\u00a0\u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 <code>onCartChanged<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043b\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u0437\u0438\u043d\u044b, \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u0440\u0430\u0439\u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u0430: \u0432\u0441\u0435 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u0432\u043e\u043a\u0440\u0443\u0433 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f <code>onReceive<\/code> \u043d\u0443\u0436\u043d\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432 <code>NotificationCenter<\/code>. \u0412 \u044d\u0442\u043e\u043c \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0435 \u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0443 \u043a\u043d\u043e\u043f\u043a\u0438 \u0441 \u044d\u043a\u0440\u0430\u043d\u043e\u043c \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u0438 \u0431\u044d\u0439\u0434\u0436\u0430.<\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/db4\/68a\/efd\/db468aefd39b5e6bde247c1831457ac3.gif\" width=\"307\" height=\"638\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/db4\/68a\/efd\/db468aefd39b5e6bde247c1831457ac3.gif\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043a\u043d\u043e\u043f\u043a\u0438 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u043d\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0431\u044d\u0439\u0434\u0436\u0430 \u0438 \u0442\u0430\u0439\u0442\u043b\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u0411\u0430\u0433 \u0441 \u043f\u043e\u0434\u043d\u044f\u0442\u0438\u0435\u043c \u043a\u043d\u043e\u043f\u043e\u043a \u0442\u0430\u0431-\u0431\u0430\u0440\u0430 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u043e\u0439 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c:\u00a0<code>ignoresSafeArea(.keyboard)<\/code>:<\/p>\n<pre><code class=\"swift\">struct RootTabView: View {     ...     var body: some View {         GeometryReader { geometry in             ZStack(alignment: Alignment.bottom) {                 TabView(selection: $selectedTab) {                 ...                 }                  HStack(spacing: 0) {    ...                 }             }         }.ignoresSafeArea(.keyboard)     } }<\/code><\/pre>\n<h2>\u0427\u0430\u0441\u0442\u044c 3. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e<\/h2>\n<p>\u0420\u0435\u0434\u043a\u043e, \u043a\u043e\u0433\u0434\u0430 \u0434\u0438\u0437\u0430\u0439\u043d\u0435\u0440 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u0435\u0431\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u043e\u0439 \u043c\u0430\u043a\u0435\u0442\u043e\u0432 \u043a\u043d\u043e\u043f\u043e\u043a, \u0437\u0430\u0431\u044b\u0432 \u043e\u0431 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438. \u0418 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0432\u0435\u0434\u044c \u0443\u0434\u0430\u0447\u043d\u0430\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0434\u0435\u043b\u0430\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0438 \u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043d\u043e \u043d\u0435 \u043e\u0442\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041e\u0434\u043d\u0430 \u0438\u0437 \u0437\u0430\u0434\u0430\u0447 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u2014 \u043f\u043e\u0432\u044b\u0441\u0438\u0442\u044c \u043e\u0442\u0437\u044b\u0432\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0426\u0435\u043b\u044c \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0432 \u043d\u0430\u0448\u0435\u043c \u0442\u0430\u0431-\u0431\u0430\u0440\u0435 \u2014 \u0434\u0430\u0442\u044c \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u0444\u0438\u0434\u0431\u044d\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f \u0441\u043e\u0441\u0442\u0430\u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u0442\u043e\u0432\u0430\u0440\u043e\u0432.\u00a0<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f01\/4ea\/824\/f014ea8248b0a76446a5d8734d2ea45a.gif\" width=\"258\" height=\"202\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f01\/4ea\/824\/f014ea8248b0a76446a5d8734d2ea45a.gif\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u0435\u0441\u044c\u043c\u0430 \u0441\u0442\u0438\u043b\u044c\u043d\u043e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u2013 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0439 \u0438\u043a\u043e\u043d\u043a\u0438 \u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0438\u043d\u0434\u0435\u043a\u0441 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0432 \u044d\u0442\u043e\u043c \u043c\u0430\u0441\u0441\u0438\u0432\u0435:<\/p>\n<pre><code class=\"swift\">struct RootTabView: View {     ...     private let offsets: [CGPoint] = [.init(x: 0, y: 0),                                       .init(x: 0, y: 4),                                       .init(x: 0, y: 0)]     @State private var currentOffsetIndex: Int = 0      var body: some View {         ...     } }<\/code><\/pre>\n<p>\u0412 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u043c \u0432\u044b\u0448\u0435 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0435\u00a0<code>onCartChanged<\/code>, \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u044e\u0449\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c\u00a0<code>currentOffsetIndex<\/code>\u00a0\u0432 \u0446\u0438\u043a\u043b\u0435 \u043f\u043e \u0432\u0441\u0435\u043c\u0443 \u043c\u0430\u0441\u0441\u0438\u0432\u0443 <code>offsets<\/code>:<\/p>\n<pre><code class=\"swift\">struct RootTabView: View {     ...     private let offsets: [CGPoint] = [.init(x: 0, y: 0),                                       .init(x: 0, y: 4),                                       .init(x: 0, y: 0)]     @State private var currentOffsetIndex: Int = 0      var body: some View {         content         ...             .onCartChanged { count, price in                 ...                 withAnimation {                     for index in 1..&lt;offsets.count {                         Task.delayed(byTimeInterval: Double(index)\/10) {                             await MainActor.run {                                 currentOffsetIndex = index                                                                  if index == 1 {                                     cartCount = count                                     cartTitle = price == 0 ? \"Shopping cart\".localized : price.stringCurrency                                 }                             }                         }                     }                 }                 ...             }         ...     }     ... }<\/code><\/pre>\n<p>\u041f\u043e\u044f\u0441\u043d\u044e,\u00a0<code>Task.delayed(byTimeInterval: ..)<\/code>\u2014\u00a0\u044d\u0442\u043e\u00a0\u043f\u043e\u00a0\u0441\u0443\u0442\u0438\u00a0\u0442\u043e\u00a0\u0436\u0435,\u00a0\u0447\u0442\u043e\u00a0\u0438\u00a0<code>asyncAfter(deadline:execute:)<\/code>\u00a0\u0442\u043e\u043b\u044c\u043a\u043e\u00a0\u0432 New Concurrency Model.<\/p>\n<pre><code class=\"swift\">public extension Task where Failure == Error {     @discardableResult     public static func delayed(         byTimeInterval delayInterval: TimeInterval,         priority: TaskPriority? = nil,         operation: @escaping @Sendable () async throws -> Success     ) -> Task {         Task(priority: priority) {             let delay = UInt64(delayInterval * 1_000_000_000)             try await Task&lt;Never, Never>.sleep(nanoseconds: delay)             return try await operation()         }     } }<\/code><\/pre>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430\u00a0<code>Task.delayed\u00a0{\u2026}<\/code> \u043c\u044b \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u0432 <code>await MainActor.run {\u2026}<\/code>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a <code>@State<\/code> \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c \u043c\u043e\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437\u043d\u0443\u0442\u0440\u0438 \u0430\u043a\u0442\u043e\u0440\u0430.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u043c\u0443 \u2013 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0443 <code>.offset<\/code>\u00a0\u0432 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0438 \u0441\u00a0spring-\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439.<\/p>\n<pre><code class=\"swift\">.offset(x: offsets[currentOffsetIndex].x,          y: offsets[currentOffsetIndex].y)     .animation(.spring(response: 0.15,                         dampingFraction: 0.75,                         blendDuration: 0),                 value: currentOffsetIndex)<\/code><\/pre>\n<p>\u0413\u0434\u0435 \u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c? \u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0441\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u0430\u043c\u0430 \u0438\u043a\u043e\u043d\u043a\u0430 \u0441 \u0431\u044d\u0439\u0434\u0436\u0435\u043c, \u0442\u043e \u0435\u0441\u0442\u044c \u0432\u00a0<code>TabBarItem<\/code>:<\/p>\n<pre><code class=\"swift\">public struct TabBarItem: View {          ...          public var body: some View {         Button {             ...         } label: {             VStack(...) {                 ZStack(...) {                     ...                     ZStack {                         icon                             ...                         Text(...)                             ...                     }                     .offset(x: offsets[currentOffsetIndex].x,                             y: offsets[currentOffsetIndex].y)                     .animation(.spring(response: 0.15,                                        dampingFraction: 0.75,                                        blendDuration: 0),                                value: currentOffsetIndex)                 }                 ...             }             ...         }         ...     } }<\/code><\/pre>\n<p>\u041d\u043e \u0437\u0434\u0435\u0441\u044c \u0435\u0441\u0442\u044c \u043d\u044e\u0430\u043d\u0441, \u0430 \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u043f\u043e\u0442\u043e\u043c \u0434\u0438\u0437\u0430\u0439\u043d\u0435\u0440 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e, \u0443\u0436\u0435 \u043d\u0435 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u0443\u044e \u0441\u043e \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435\u043c. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0434\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u00a0<code>TabBarItem<\/code>, \u043e\u0431\u0435\u0440\u043d\u0435\u043c \u0432 \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a:<\/p>\n<pre><code class=\"swift\">public struct TabBarItem&lt;VModifier>: View where VModifier: ViewModifier {          ...     let animation: VModifier     ...          public init(...,          animation: VModifier,             ...) {       ...         self.animation = animation       ...     }          public var body: some View {         Button {             onTap()         } label: {             VStack(alignment: .center, spacing: 2.0) {                 ZStack(alignment: .bottomLeading) {                     ...                     ZStack {                         icon                             .resizable()                             ...                         Text(\"\\(badgeCount > 99 ? \"99+\" : \"\\(badgeCount)\")\")                             ...                     }                     .modifier(animation)                 }                 ...             }             ...         }         ...     } }<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043d\u0438\u0447\u0435\u0433\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u0432 \u043a\u043e\u0434\u0435 \u0442\u0435\u0445\u00a0tab\u00a0item-\u043e\u0432, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043d\u0430\u043f\u0438\u0448\u0435\u043c\u00a0<code>extension<\/code>:<\/p>\n<pre><code class=\"swift\">public extension TabBarItem where VModifier == EmptyModifier {     public init(icon: Image,          title: String,          badgeCount: Int,          isSelected: Bool,          itemWidth: CGFloat,          onTap: @escaping () -> ()) {         self.icon = icon         self.title = title         self.badgeCount = badgeCount         self.isSelected = isSelected         self.itemWidth = itemWidth         self.onTap = onTap         self.animation = EmptyModifier()     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440, \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043d\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0438\u0437\u0432\u043d\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0435\u0433\u043e \u043a\u0430\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432\u00a0\u00a0<code>TabBarItem<\/code>. \u0420\u0430\u043d\u044c\u0448\u0435 \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0431\u044b\u043b \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u00a0<a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/animatablemodifier\"><u>AnimatableModifier<\/u><\/a>,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 Apple, \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0432, \u043d\u0435\u043c\u043d\u043e\u0433\u0438\u043c \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0437\u0432\u0430\u043b\u0430 \u0435\u0433\u043e \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u043c, \u0432\u0437\u0430\u043c\u0435\u043d \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u00a0<a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/animatable\"><u>Animatable<\/u><\/a>:<\/p>\n<pre><code class=\"swift\">public struct OffsetAnimation&lt;V>: Animatable, ViewModifier where V: Equatable {          private var offset: CGPoint     private var value: V          public init(offset: CGPoint,                 value: V) {         self.offset = offset         self.value = value     }          public var animatableData: CGPoint {         get { offset }         set { offset = newValue }     }          public func body(content: Content) -> some View {         content             .offset(x: offset.x, y: offset.y)             .animation(.spring(response: 0.15,                                 dampingFraction: 0.75,                                 blendDuration: 0),                         value: value)     }   }<\/code><\/pre>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043f\u043e\u044f\u0441\u043d\u0438\u0442\u044c, \u0447\u0442\u043e animatableData \u2013 \u044d\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435\u00a0\u0434\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u0430\u043a \u0440\u0430\u0437\u00a0\u0442\u043e\u0447\u043a\u0430 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f. <\/p>\n<p>\u0412\u0430\u0436\u043d\u044b\u0439 \u043d\u044e\u0430\u043d\u0441, Apple \u043d\u0430\u0437\u0432\u0430\u043b\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u043c \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u00a0<a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/view\/animation(_:)-1hc0p\"><u>.animation(_:)<\/u><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0430\u0440\u0438\u043b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c<a href=\"https:\/\/t.me\/swiftui_dev\/156\"> \u043c\u043d\u043e\u0433\u043e \u0431\u0430\u0433\u043e\u0432<\/a> \u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439, \u0432\u0437\u0430\u043c\u0435\u043d \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u00a0<a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/view\/animation(_:value:)\"><u>animation(_:value:)<\/u><\/a>. \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0439 \u0441\u043c\u044b\u0441\u043b \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439\u00a0<code>value<\/code>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0448\u00a0<code>OffsetAnimation<\/code>\u00a0\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442\u00a0value, \u043a\u0430\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c\u00a0<code>RootTabView<\/code>\u00a0\u0441 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"swift\">struct RootTabView: View {     ...     private let offsets: [CGPoint] = [.init(x: 0, y: 0),                                       .init(x: 0, y: 4),                                       .init(x: 0, y: 0)]     @State private var currentOffsetIndex: Int = 0      var body: some View {         GeometryReader { geometry in             ZStack(alignment: Alignment.bottom) {                 TabView(selection: $selectedTab) {                     ...                     cart.tag(TabType.cart)                 }                                  HStack(spacing: 0) {                     ...                     TabBarItem(icon: Image.TabBar.cart,                                title: cartTitle,                                badgeCount: cartCount,                                isSelected: selectedTab == .cart,                                itemWidth: geometry.size.width \/ 5,                                animation: OffsetAnimation(offset: offsets[currentOffsetIndex],                                                           value: currentOffsetIndex)) {                         selectedTab = .cart                     }                 }             }         }         ...             .onCartChanged { count, price in                 ...                 withAnimation {                     for index in 1..&lt;offsets.count {                         Task.delayed(byTimeInterval: Double(index)\/10) {                             await MainActor.run {                                 currentOffsetIndex = index                                                                  if index == 1 {                                     cartCount = count                                     cartTitle = price == 0 ? \"Shopping cart\".localized : price.stringCurrency                                 }                             }                         }                     }                 }                 ...             }         ...     }     ... } <\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442, \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0437\u0430\u0434\u0443\u043c\u043a\u0430 \u0434\u0438\u0437\u0430\u0439\u043d\u0435\u0440\u0430 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u0435\u043d\u0430:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/56a\/5e0\/1ff\/56a5e01ffb589505d74ccabdf3e9db87.gif\" width=\"384\" height=\"683\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/56a\/5e0\/1ff\/56a5e01ffb589505d74ccabdf3e9db87.gif\"\/><figcaption><\/figcaption><\/figure>\n<h2>\u0427\u0430\u0441\u0442\u044c 4. \u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u0438\u0437\u00a0<code>RootTabView<\/code>\u00a0<code>@State<\/code> \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u00a0<code>selectedTab<\/code>\u00a0&#8212; \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430 \u043d\u0430 \u0442\u0430\u0431 \u0431\u0430\u0440\u0435:<\/p>\n<pre><code class=\"swift\">struct RootTabView: View {     ...     @State private var selectedTab : TabType = .main     ... }<\/code><\/pre>\n<p>\u0423 \u043d\u0430\u0441 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u044b \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b\u00a0MVVM-S, \u0433\u0434\u0435 \u0437\u0430 \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441, \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043c <code>selectedTab<\/code> \u0432 \u043d\u0435\u0433\u043e:<\/p>\n<pre><code class=\"swift\">final class Router : ObservableObject {     ...     @Published public var selectedTab: TabType = .main     ...          func openTabCart() {         selectedTab = .cart     }     ... }<\/code><\/pre>\n<p><code>RootTabView<\/code>\u00a0\u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u043a \u0432\u0438\u0434\u0443:<\/p>\n<pre><code class=\"swift\">struct RootTabView: View {     ...     @ObservedObject private var router: Router     ...          var body: some View {         TabView(selection: $router.selectedTab) {             ...             cart.tag(TabType.cart)         }                  ...         TabBarItem(...) {             router.openTabCart()         }         ...     } }<\/code><\/pre>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0443 \u043c\u0435\u043d\u044f \u0432\u0441\u0435, \u0441\u043f\u0430\u0441\u0438\u0431\u043e, \u0447\u0442\u043e \u0434\u043e\u0447\u0438\u0442\u0430\u043b\u0438 \u0434\u043e \u043a\u043e\u043d\u0446\u0430! <\/p>\n<p>\u041f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0439\u0442\u0435\u0441\u044c \u043d\u0430 <a href=\"https:\/\/t.me\/swiftui_dev\">\u043c\u043e\u0439 Telegram-\u043a\u0430\u043d\u0430\u043b<\/a>, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u044b\u0439 iOS-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043d\u0430 SwiftUI. <\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/lenta_utkonos_tech\/blog\/674888\/\"> https:\/\/habr.com\/ru\/company\/lenta_utkonos_tech\/blog\/674888\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435\u00a0SwiftUI\u00a0(\u0434\u0430\u043b\u0435\u0435 \u2014\u00a0SUI) \u0432 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0435 \u043d\u0430\u00a0UIKit, \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 2022 \u0433. \u0443\u0436\u0435 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0430 \u0441\u043a\u043e\u0440\u0435\u0435, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u043b\u0438\u0447\u0438\u0435\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043d\u0430\u0432\u044b\u043a\u043e\u0432. \u041f\u0435\u0440\u0435\u0432\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0423\u0442\u043a\u043e\u043d\u043e\u0441\u0430 \u2013 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u043b\u0438\u0434\u0435\u0440\u043e\u0432\u00a0e-commerce\u00a0\u043d\u0430 \u0440\u043e\u0441\u0441\u0438\u0439\u0441\u043a\u043e\u043c \u0440\u044b\u043d\u043a\u0435 \u2013 \u043d\u0430\u00a0SUI\u00a0\u043c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0432 \u043a\u043e\u043d\u0446\u0435 2020 \u0433\u043e\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0434\u043d\u044f\u043b\u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e\u00a0iOS\u00a0\u0434\u043e 13-\u043e\u0439 (\u0438, \u0434\u0430, \u043c\u044b \u043d\u0435 \u0441\u0442\u0430\u043b\u0438 \u0436\u0434\u0430\u0442\u044c 14-\u043e\u0439). \u042d\u0442\u043e\u043c\u0443 \u0436\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0430 \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0440\u0435\u0434\u0438\u0437\u0430\u0439\u043d\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0438\u0437 \u043f\u044f\u0442\u0438 \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u043d\u0430\u00a0SUI\u00a0\u0443 \u043d\u0430\u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0434\u0432\u0430.<\/p>\n<p>\u041e\u0434\u043d\u0430 \u0438\u0437 \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447, \u0441\u0442\u043e\u044f\u0449\u0438\u0445 \u043f\u0435\u0440\u0435\u0434 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u2014 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438. \u0421\u0435\u0439\u0447\u0430\u0441 \u0443\u0436\u0435 \u0440\u0435\u0434\u043a\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u044c \u043e\u0434\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u041f\u0430\u043d\u0435\u043b\u044c \u0432\u043a\u043b\u0430\u0434\u043e\u043a (\u0438\u043b\u0438 \u0442\u0430\u0431-\u0431\u0430\u0440) \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u044d\u043a\u0440\u0430\u043d\u0430\u043c \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u0433\u043e \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435. \u0415\u0441\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0441 \u043d\u0443\u043b\u044f \u043d\u0430\u00a0SUI, \u0442\u043e \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0441\u0435 \u0435\u0449\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439: \u044d\u043a\u0440\u0430\u043d\u044b \u0432\u0435\u0440\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u043d\u0430\u00a0SUI, \u0430 \u0442\u0430\u0431-\u0431\u0430\u0440 \u043d\u0430\u00a0UIKit. \u0421 \u0440\u043e\u0441\u0442\u043e\u043c \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u044b \u043d\u0430\u00a0SUI\u00a0\u0432 \u0423\u0442\u043a\u043e\u043d\u043e\u0441\u0435 \u043c\u044b \u0441\u0442\u0430\u043b\u0438 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043d\u0430\u00a0UIKit, \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u0432 \u044d\u0442\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u0442\u0430\u043b\u043e \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 TabView \u0432\u0437\u0430\u043c\u0435\u043d UITabBarController.<\/p>\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u041a\u0440\u0430\u0435\u0432 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440 \u0438 \u043d\u0438\u0436\u0435\u00a0\u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043e\u043f\u044b\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430\u00a0UIKit-\u0432\u043e\u0433\u043e \u0442\u0430\u0431-\u0431\u0430\u0440\u0430 \u043d\u0430\u00a0TabView \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u043c\u0438 \u043a\u0430\u043c\u043d\u044f\u043c\u0438: \u043a\u043e\u0433\u0434\u0430 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u044d\u043a\u0440\u0430\u043d\u044b, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u043a\u0430\u043a \u043d\u0430\u00a0SUI, \u0442\u0430\u043a \u0438 \u043d\u0430\u00a0UIKit. \u0421\u0440\u0430\u0437\u0443 \u043e\u0433\u043e\u0432\u043e\u0440\u044e\u0441\u044c, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0435 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u0430 \u043d\u0430 \u0442\u0435\u0445, \u043a\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0430\u043b \u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441\u043e\u00a0SUI: \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u044f \u0441\u043e\u0432\u0435\u0442\u043e\u0432\u0430\u043b \u0431\u044b \u043d\u0430\u0447\u0430\u0442\u044c \u0441 \u043a\u0430\u043a\u043e\u0433\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430 \u0438\u043b\u0438 \u043d\u043e\u0432\u043e\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u043e\u0439 \u0444\u0438\u0447\u0438. \u0411\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u044f\u043a\u0438\u0445 \u0444\u0438\u0448\u0435\u043a \u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 \u0440\u0430\u0437\u0431\u043e\u0440\u043e\u0432 \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 <a href=\"https:\/\/t.me\/swiftui_dev\">\u043c\u043e\u0435\u043c telegram-\u043a\u0430\u043d\u0430\u043b\u0435<\/a>, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u043e\u043c iOS-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043d\u0430 SwiftUI. <\/p>\n<h2>\u0427\u0430\u0441\u0442\u044c 1. \u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443<\/h2>\n<p>\u0412 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043f\u043e\u00a0<a href=\"https:\/\/trunkbaseddevelopment.com\/\"><u>Trunk Based Development<\/u><\/a>\u00a0(TBD). \u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u0434\u0430\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u044c\u044e \u0432\u0435\u0442\u0432\u043b\u0435\u043d\u0438\u044f, \u0442\u043e \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u0432\u0430\u043c \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c\u00a0<a href=\"https:\/\/www.youtube.com\/watch?v=hIW5ynk8HWc\"><u>\u044d\u0442\u043e<\/u><\/a>\u00a0\u0432\u044b\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c\u00a0<a href=\"https:\/\/habr.com\/ru\/post\/519314\/\"><u>\u044d\u0442\u0443<\/u><\/a>\u00a0\u0441\u0442\u0430\u0442\u044c\u044e. \u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e, \u0442\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u043e\u0432\u044b\u0445 \u0444\u0438\u0447\u0435\u0439 \u0438\u0434\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 Feature Flags.\u00a0<\/p>\n<p>\u0417\u0430\u0432\u0435\u0434\u0435\u043c \u0444\u043b\u0430\u0433 \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u0430\u0431-\u0431\u0430\u0440\u0430 \u043d\u0430\u00a0SUI:<\/p>\n<pre><code class=\"swift\">struct SwiftUI {     struct TabView {         static var isActive: Bool = true     } }<\/code><\/pre>\n<p>\u0412 \u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043a\u043e\u0434\u0430, \u0433\u0434\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 view controller \u0443 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e window, \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c:<\/p>\n<pre><code class=\"swift\">var main: UIWindow? func createMainWindow(windowScene: UIWindowScene) {     main = UIWindow(windowScene: windowScene)     let mainTab = FeatureFlags.SwiftUI.TabView.isActive ?                          UIHostingController(rootView: RootTabView()) :                          setupTabBarController()     main?.rootViewController = mainTab }<\/code><\/pre>\n<p>\u0433\u0434\u0435 <code>setupTabBarController()<\/code>\u00a0\u2013\u00a0\u044d\u0442\u043e\u00a0\u0444\u0443\u043d\u043a\u0446\u0438\u044f\u00a0\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f\u00a0\u043f\u0440\u0435\u0436\u043d\u0435\u0433\u043e\u00a0\u0442\u0430\u0431-\u0431\u0430\u0440\u0430\u00a0\u043d\u0430\u00a0UIKit,\u00a0\u0430\u00a0<code>RootTabView()<\/code>\u00a0\u2013\u00a0\u044d\u0442\u043e\u00a0view\u00a0\u043d\u043e\u0432\u043e\u0433\u043e\u00a0\u0442\u0430\u0431-\u0431\u0430\u0440\u0430\u00a0\u043d\u0430\u00a0SUI,\u00a0\u043f\u0440\u043e\u0431\u0440\u043e\u0448\u0435\u043d\u043d\u0430\u044f\u00a0\u0447\u0435\u0440\u0435\u0437\u00a0<code>UIHostingController<\/code>.\u00a0<\/p>\n<p>\u0418\u0435\u0440\u0430\u0440\u0445\u0438\u044f \u0432 \u043f\u0440\u0435\u0436\u043d\u0435\u043c \u0442\u0430\u0431-\u0431\u0430\u0440\u0435 \u0432\u0435\u0441\u044c\u043c\u0430 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u0430\u044f: \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0435\u0433\u043e\u00a0navigation controller\u00a0\u0441 \u043a\u043e\u0440\u043d\u0435\u0432\u044b\u043c\u00a0view\u00a0controller-\u043e\u043c:<\/p>\n<pre><code class=\"swift\">let profileVC: ProfileViewController = .init() let profileNav: NavigationController = .init(rootViewController: profileVC)<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u00a0tab bar controller, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e view controller-\u044b \u044d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0448\u0430\u0433\u0435\u00a0navigation controller-\u044b:<\/p>\n<pre><code class=\"swift\">private func setupTabBarController() -> UIViewController {     ...     let profileVC: ProfileViewController = .init()     let profileNav: NavigationController = .init(rootViewController: profileVC)     ...     let tabbarController: TabBarController = .init()     tabbarController.viewControllers = [..., profileNav, ...]     return tabbarController }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u044f\u0441\u043d\u0438\u0442\u044c, \u0447\u0442\u043e <code>NavigationController<\/code> \u2013 \u044d\u0442\u043e \u043a\u043b\u0430\u0441\u0441, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u044b\u0439 \u043e\u0442 <code>UINavigationController<\/code>, \u0441 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u043c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0435\u0435 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0432\u0438\u0434\u0430, \u043a\u043d\u043e\u043f\u043a\u0438 \u043d\u0430\u0437\u0430\u0434, \u043d\u043e \u043d\u0435 \u0431\u043e\u043b\u0435\u0435.<\/p>\n<p>\u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043d\u043e\u0432\u043e\u043c\u0443 \u0442\u0430\u0431-\u0431\u0430\u0440\u0443, \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0432\u00a0<code>RootTabView()<\/code> \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f\u00a0view\u00a0\u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432. \u0421\u0430\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c\u00a0SUI-\u043e\u0431\u0435\u0440\u0442\u043a\u0438 \u043d\u0430 <code>UIViewControllerRepresentable<\/code> \u0434\u043b\u044f\u00a0UIKit-\u044d\u043a\u0440\u0430\u043d\u043e\u0432, \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u0434\u043d\u043e\u0439 \u0442\u0430\u043a\u043e\u0439 \u0434\u043b\u044f \u044d\u043a\u0440\u0430\u043d\u0430 \u043f\u0440\u043e\u0444\u0438\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:<\/p>\n<pre><code class=\"swift\">import SwiftUI  struct ProfileSUIView: UIViewControllerRepresentable {     func makeUIViewController(context: Context) -> NavigationController {         let profileVC: ProfileViewController = .init()         let profileNav: NavigationController = .init(rootViewController: profileVC)         return profileNav     }      func updateUIViewController(_ uiViewController: NavigationController,                                  context: Context) {     } }<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0443\u0436\u0435 \u0441\u043a\u0430\u0437\u0430\u043b \u0440\u0430\u043d\u0435\u0435, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u044d\u043a\u0440\u0430\u043d\u0430, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u043d\u0430\u00a0SUI. \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043b\u043e\u043c\u0430\u0442\u044c \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u043d\u0430 \u044d\u0442\u0438\u0445 \u044d\u043a\u0440\u0430\u043d\u0430\u0445 \u0432\u0432\u0438\u0434\u0443 \u0434\u0440\u0443\u0433\u0438\u0445\u00a0legacy\u00a0\u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u043d\u0430\u00a0UIKit, \u0440\u0435\u0448\u0435\u043d\u043e \u0431\u044b\u043b\u043e \u0438\u0445 \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <code>UIViewControllerRepresentable<\/code> \u0432 <code>NavigationController<\/code>:<\/p>\n<pre><code class=\"swift\">struct CartSUIView: UIViewControllerRepresentable {     func makeUIViewController(context: Context) -> NavigationController {          let cartScreen = CartScreen()             .environmentObject(...)         let suiCartVC = UIHostingController(rootView: cartScreen)                  let cartNav: NavigationController = .init(rootViewController: suiCartVC)         return cartNav     }      func updateUIViewController(_ uiViewController: NavigationController,                                  context: Context) {     } }<\/code><\/pre>\n<p>\u0414\u0438\u0437\u0430\u0439\u043d\u043e\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u0430\u0431-\u0431\u0430\u0440\u0430 \u043f\u043e\u043a\u0430 \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0431\u0438\u0432\u0430\u0442\u044c \u0433\u043e\u043b\u043e\u0432\u0443, \u043c\u044b \u043a \u044d\u0442\u043e\u043c\u0443 \u0435\u0449\u0435 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439.\u00a0<code>RootTabView<\/code>\u00a0\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u043a \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u043c\u0443 \u0432\u0438\u0434\u0443. \u041e\u0431\u044a\u044f\u0432\u0438\u043c\u00a0enum\u00a0\u0441 \u044d\u043a\u0440\u0430\u043d\u0430\u043c\u0438:<\/p>\n<pre><code class=\"swift\">enum TabType: Int {     case main     case catalog     case search     case profile     case cart }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0431\u0435\u0440\u0435\u043c <code>RootTabView {...}<\/code>, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0438\u043a\u043e\u043d\u043a\u0438 \u0438\u0437\u00a0SF\u00a0Symbols:<\/p>\n<pre><code class=\"swift\">struct RootTabView: View {      @State private var selectedTab: TabType = .main      var body: some View {         TabView(selection: $selectedTab) {             main.tag(TabType.main)             catalog.tag(TabType.catalog)             search.tag(TabType.search)             profile.tag(TabType.profile)             cart.tag(TabType.cart)         }     }      private var main: some View {         MainSUIView()             .tabItem {                 Label(\"Catalog\", systemImage: \"house\")             }     } ...     private var profile: some View {         ProfileSUIView()             .tabItem {                 Label(\"Profile\", systemImage: \"person\")             }     }      private var cart: some View {         CartSUIView()             .tabItem {                 Label(\"Cart\", systemImage: \"cart\")             }     } }<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442, \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0442\u0430\u0431\u0430\u043c\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u043c\u0435\u0441\u0442\u0435 \u0441 \u0442\u0435\u043c, \u0441\u043b\u043e\u043c\u0430\u043b\u0430\u0441\u044c \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0430\u0445\u00a0SUI: \u043b\u044e\u0431\u043e\u0439 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u044d\u043a\u0440\u0430\u043d \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e,\u00a0\u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0431\u0435\u043b\u0430\u044f \u043f\u043e\u043b\u043e\u0441\u0430 \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u0438\u00a0safe\u00a0area. \u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e \u0438 \u043f\u0440\u043e\u0441\u0442\u043e, \u0442\u043e \u0440\u043e\u0443\u0442\u0438\u043d\u0433, \u0434\u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0439\u0441\u044f \u043d\u0430\u043c \u0432 \u043d\u0430\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u043e \u043a\u0430\u043a \u043b\u0435\u0433\u0430\u0441\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f\u00a0enum\u00a0\u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u0434\u043b\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0443, \u0433\u0434\u0435 \u044d\u0442\u043e\u0442 enum \u0440\u0430\u0437\u0440\u0443\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f:<\/p>\n<pre><code class=\"swift\">enum Route {     case trackOrder     case qrAccessCode     case safari(String)     ... } ... func route(to direction: Route,             from viewController: UIViewController? = nil,             previousScreen: AmplitudeScreenNames? = nil) {     let viewController = previousScreen == .bottomSheet ?    UIApplication.topViewController() : viewController      switch direction {     case .trackOrder(let id):         self.trackOrder(id: id, from: viewController)     case .qrAccessCode:         self.showQRAccessCode(from: viewController)     case .safari(let url):         routeToSafari(url: url)     .... }<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u044f\u0432\u043d\u043e \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u00a0view\u00a0controller\u00a0\u2013 \u044d\u043a\u0440\u0430\u043d, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0448\u044c, \u0442\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0431\u0435\u0440\u0435\u043c\u00a0top\u00a0view controller (\u043a\u043e\u0434 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443, \u043e\u043d \u043b\u0435\u0433\u043a\u043e \u0433\u0443\u0433\u043b\u0438\u0442\u0441\u044f). \u041a\u0430\u043a \u0440\u0430\u0437 \u0432 \u044d\u0442\u043e\u043c \u0438 \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f \u043b\u044e\u0431\u043e\u0433\u043e \u043e\u043a\u043d\u0430.\u00a0Top view controller\u00a0\u0432\u00a0\u043d\u0430\u0448\u0435\u0439\u00a0\u0441\u0445\u0435\u043c\u0435\u00a0\u044d\u0442\u043e\u00a0\u0443\u0436\u0435\u00a0\u043d\u0435\u00a0<code>UINavigationController<\/code>\u00a0\u0438\u043b\u0438\u00a0<code>UITabBarController<\/code>,\u00a0\u0430\u00a0hosting view controller:<\/p>\n<pre><code class=\"bash\">po topViewController \u25bf Optional&lt;UIViewController>   \u25bf some : &lt;_TtGC7SwiftUI19UIHostingControllerV7Utkonos11RootTabView_: 0x139f2f640><\/code><\/pre>\n<p>\u0420\u0430\u043d\u044c\u0448\u0435 \u0434\u043e\u00a0navigation\u00a0controllera-\u0430 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0434\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"bash\">po (topViewController as? UITabBarController)?.selectedViewController \u25bf Optional&lt;UIViewController>   \u25bf some : &lt;Utkonos.NavigationController: 0x12f882600><\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0432 SUI-\u044d\u043a\u0440\u0430\u043d\u044b\u00a0\u0442\u0435\u043f\u0435\u0440\u044c \u044f\u0432\u043d\u043e \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430\u00a0navigation\u00a0controller, \u0447\u0442\u043e\u0431\u044b \u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0435. \u041e\u0434\u043d\u0438\u043c \u0438\u0437 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 <code>EnvironmentKey<\/code>:\u00a0<\/p>\n<pre><code class=\"swift\">struct NavigationControllerKey: EnvironmentKey {     static let defaultValue: UINavigationController? = nil }  extension EnvironmentValues {     var navigationController: NavigationControllerKey.Value {         get {             return self[NavigationControllerKey.self]         }         set {             self[NavigationControllerKey.self] = newValue         }     } }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043e\u0431\u044a\u044f\u0432\u0438\u043c <code>@Environment<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0432\u00a0SUI-\u044d\u043a\u0440\u0430\u043d\u0435:<\/p>\n<pre><code class=\"swift\">struct CartScreen: View {     ...     @Environment(\\.navigationController) var navigationController     ...        var body: some View {     ...     } }<\/code><\/pre>\n<p>\u0417\u0430\u0438\u043d\u0436\u0435\u043a\u0442\u0438\u043c  navigation controller \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f\u00a0hosting\u00a0view\u00a0controller-\u0430 \u044d\u043a\u0440\u0430\u043d\u0430, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043a\u043e\u0434 <code>CartSUIView<\/code> \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u043a \u0432\u0438\u0434\u0443:<\/p>\n<pre><code class=\"swift\">struct CartSUIView: UIViewControllerRepresentable {     func makeUIViewController(context: Context) -> NavigationController {         let cartNav: NavigationController                  let emptyView: UIViewController = UIHostingController(rootView: EmptyView())         cartNav = NavigationController.init(rootViewController: emptyView)                  let cartScreen = CartScreen()             .environment(\\.navigationController, cartNav)             .environmentObject(...)         let suiCartVC = UIHostingController(rootView: cartScreen)                  cartNav.addChild(suiCartVC) \/\/ child here is a root         cartNav.setNavigationBarHidden(true, animated: false)                  return cartNav     }      func updateUIViewController(_ uiViewController: NavigationController,                                  context: Context) {     } }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u044f\u0441\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0434\u043b\u044f \u0438\u043d\u0436\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f <code>.environment(.navigationController, cartNav)<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u00a0navigation\u00a0controller-\u0430 <code>cartNav<\/code>,<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-335313","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/335313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=335313"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/335313\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=335313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=335313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=335313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}