前言html
后续这个SwiftUI分类的文章所有都是针对SwiftUI的平常学习和理解写的,本身利用Swift写的第二个项目也顺利上线后续的需求也不是特着急,最近正好有空就利用这段时间补一下本身对SwiftUI的理解,这个过程中正好把整个学习过程记录下来,方便本身查阅,也但愿能给须要的同窗一点点的帮助。因为本身还欠着RxSwift的账,此次也是想着先放弃别的帐务(欠的的确挺多的)先全心全意的把这两块的账给补补,但愿补上这笔帐以后本身对Swift的理解也能上一个台阶,对Siwft的理解自认为仍是感受欠缺的,不算是真的深刻的掌握,我对SwiftUI也是在学习当中,如今能查阅的关于SwiftUI的资料不少是须要收费的,遇到问题只能想办法努力解决,有写的不钟意的地方,但愿多加指正!git
这两张图相信看过苹果官方SwiftUI介绍文档而且跟着写了一遍代码的同窗应该不陌生,固然咱们的目的不是说这两篇的代码,这个具体的能够到下面链接去查看,我本身跟着写了一遍以后对SwiftUI也是有了一个基本的认识。咱们在后面遇到的一些问题也会回到这个官方文档进行一些验证。github
SwiftUIswift
在进入项目搭建先说说我本身对SwiftUI的一个基本的认知:session
SwiftUI我以为对iOSer来讲最大的是开发UI模式的优化,针对一个需求或者是一个新的项目咱们基本上都是从写UI开始的,根据设计图再编造一些假数据来作,只是在写的过程当中它的及时效果也都是脑补!SwiftUI我以为能改变的痛点就是这点,能让咱们实时预览本身写的UI效果,保持咱们代码和界面的同步性!app
声明式UI:关于它的理解往细了说,的确能专门写一篇文章出来,下面这篇文章能很好的帮助理解咱们如今使用的命令式和SwiftUI采用的声明式UI之间的区别。ide
跨平台: 在最新的swiftUI 5.1中,咱们建立一个MultilPlatform App有了下面这些区别:学习
·Before
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). // Create the SwiftUI view that provides the window contents. let contentView = BaseTabbarView() // Use a UIHostingController as window root view controller. if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: contentView) self.window = window window.makeKeyAndVisible() } }
·After
import SwiftUI @main struct MultiPlatformApp: App { var body: some Scene { WindowGroup { ContentView() } } }
SwiftUI 将整个原有的苹果平台差别部分抽象为 App 和 Scene 部分,能够看到Swift5.1以后在彻底无需引入UIKit 的状况下咱们就建立了一个多平台的App工程,代码也从本来的基于 UI/NS HostViewController 变成了基于 App的声明式描述。这意味着咱们后续在UI布局系统上能够逐渐摆脱对传统命令式 UI 编程的依赖。达到真正的平台无关!
下面开始咱们最多见的项目场景的搭建,一点点的学习一下SwiftUI里面的一些知识。
实时预览:
这个画布的显示控制是在下图标注的地方,固然当你建立一个SwiftUIView的时候它是默认建立展现的,要是不见了就在下面去找:
画布的代码控制是在你每一个View 的最后面的遵循了PreviewProvider协议的结构体里面的,就像下面咱们要说的基本的Tab的预览:
struct BaseTabbarView_Previews: PreviewProvider { /// 预览视图,你试着在这里多添加两个看看效果呀 static var previews: some View { BaseTabbarView() } }
从最多见的场景搭建开始
在咱们的平常开发中,标签(TabBar)+ 导航(Na)形式的模式是随处可见的,咱们此次的目的是利用SwiftUI搭建这样一个场景构建一个基本的应用,包括登陆和数据处理以及iOS常见控件在SwiftUI中的一些具体的使用,这个项目会随着学习进度慢慢的把全部的内容都基本的补齐,下面是最基本的导航+标签的git效果。
View
我本身以为,要想从UIKit转换到SwiftUI,须要咱们最早转变的概念就是 Controller -> View 的一个改变,在使用SiwftUI写UI的过程当中,基本上是不在须要咱们向UIkit那样去建立Controller来管理View,在SwiftUI中最多见的就是View。
在UIKit中咱们的导航、标签都是经过控制器来管理,可是在SwiftUI中他们分别是经过NavigationView+TabView管理的,咱们得在认识上有一个基本的转变,从Controller到View的认识转变。
认识一下NavigationView,先看看下面的代码:
NavigationView{ NavigationLink.init( destination: Text("Destination"), label: { Text("Navigate") }) .navigationTitle(title) /// 留意下这个显示模式 displayMode 分三种,具体的能够点进去看看 /// inline 就是咱们常见的模式 /// .navigationBarTitle(title,displayMode: .inline) }
大概解析一下上面代码的 NavigationLink,它是用来控制View之间的跳转的:
destination:是跳转的目标View,咱们在作一些数据传递的时候通常都是在这里说明的。
label:对它的理解简单点就是下个View的内容
再认识一下TabView,下面代码是SwiftUI对它的基本定义和描述:
/// A view that switches between multiple child views using interactive user /// interface elements. /// /// To create a user interface with tabs, place views in a `TabView` and apply /// the ``View/tabItem(_:)`` modifier to the contents of each tab. The following /// creates a tab view with three tabs: /// /// TabView { /// Text("The First Tab") /// .tabItem { /// Image(systemName: "1.square.fill") /// Text("First") /// } /// Text("Another Tab") /// .tabItem { /// Image(systemName: "2.square.fill") /// Text("Second") /// } /// Text("The Last Tab") /// .tabItem { /// Image(systemName: "3.square.fill") /// Text("Third") /// } /// } /// .font(.headline) /// /// Tab views only support tab items of type ``Text``, ``Image``, or an image /// followed by text. Passing any other type of view results in a visible but /// empty tab item. @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) public struct TabView<SelectionValue, Content> : View where SelectionValue : Hashable, Content : View { /// Creates an instance that selects from content associated with /// `Selection` values. public init(selection: Binding<SelectionValue>?, @ViewBuilder content: () -> Content) /// The content and behavior of the view. public var body: some View { get } /// The type of view representing the body of this view. /// /// When you create a custom view, Swift infers this type from your /// implementation of the required `body` property. public typealias Body = some View }
关于这个TabView在定义的上面苹果是给出了一个使用的基本的示例的,要和咱们项目中常用的模式要绑定在一块儿的的话就是结合他的初始化方法绑定一个@State变量使用的,具体的咱们会在后面的代码中说的,关于这个@State我在项目Demo中有具体的解释,包括像@bind类型或者是@EnvironmentObject这些关键字咱们确定是得须要学习的,就像咱们从OC转到Swift同样。
简单看看Na+Tb的代码
从SceneDelegate开始, 根控制器就是 UIHostingController,咱们须要作的第一步就是设置它的根视图 rootView
// Create the SwiftUI view that provides the window contents. let contentView = BaseTabbarView() // Use a UIHostingController as window root view controller. if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: contentView) self.window = window window.makeKeyAndVisible() }
接下来是TabView的代码,须要注意的是咱们点击item的时候视图切换的绑定状态,基本上在代码注释中我说的比较清楚了,应该能理解的。
import SwiftUI struct BaseTabbarView: View { /// 理解State这个属性 https://www.cnblogs.com/xiaoniuzai/p/11417123.html /* 经过使用 @State 修饰器咱们能够关联出 View 的状态. SwiftUI 将会把使用过 @State 修饰器的属性存储到一个特殊的内存区域,而且这个区域和 View struct 是隔离的. 当 @State 装饰过的属性发生了变化,SwiftUI 会根据新的属性值从新建立视图 */ @State private var selectedTab = 0 var body: some View { /// public init(selection: Binding<SelectionValue>?, @ViewBuilder content: () -> Content) TabView(selection: $selectedTab){ HomeView(title: "首页") .tabItem { Image(selectedTab == 0 ? "icon_home_selected" : "icon_home") Text("首页") } .onTapGesture { selectedTab = 0 } .tag(0) ServiceView(title: "周边") .tabItem { Image(selectedTab == 1 ? "icon_around_selected" : "icon_around") Text("周边") } .onTapGesture { selectedTab = 1 } .tag(1) AroundView(title: "服务") .tabItem { Image(selectedTab == 2 ? "icon_service_selected" : "icon_service") Text("服务") } .onTapGesture { selectedTab = 2 } .tag(2) MineView(title: "个人").environmentObject(NavigationAction()) .tabItem { Image(selectedTab == 3 ? "icon_mine_selected" : "icon_mine") Text("个人") } .onTapGesture { selectedTab = 3 } .tag(3) /// 这个着重颜色设置能够设置tabbaritem字体的颜色 }.accentColor(.blue) } } struct BaseTabbarView_Previews: PreviewProvider { /// 预览视图,你试着在这里多添加两个看看效果呀 static var previews: some View { BaseTabbarView() } }
在上面的代码中,点击的切换咱们是经过View的onTapGesture方法经过改变selectedTab 来进行控制的,而后item具体是要显示那种风格的图片也是经过selectedTab通过三目运算符控制,具体得咱们这里很少解释了废话了,看代码我相信都能理解。
下面的参考文章相信能帮助咱们更好的理解一下,SwiftUI!
参考文章: