从用SwiftUI搭建项目说起
前言
后续这个SwiftUI分类的文章全部都是针对SwiftUI的日常学习和理解写的,自己利用Swift写的第二个项目也顺利上线后续的需求也不是特着急,最近正好有空就利用这段时间补一下自己对SwiftUI的理解,这个过程当中正好把整个学习过程记录下来,方便自己查阅,也希望能给需要的同学一点点的帮助。由于自己还欠着RxSwift的帐,这次也是想着先放弃别的账务(欠的的确挺多的)先全心全意的把这两块的帐给补补,希望补上这笔账之后自己对Swift的理解也能上一个台阶,对Siwft的理解自认为还是感觉欠缺的,不算是真的深入的掌握,我对SwiftUI也是在学习当中,现在能查阅的关于SwiftUI的资料很多是需要收费的,遇到问题只能想办法努力解决,有写的不钟意的地方,希望多加指正!

这两张图相信看过苹果官方SwiftUI介绍文档并且跟着写了一遍代码的同学应该不陌生,当然我们的目的不是说这两篇的代码,这个具体的可以到下面连接去查看,我自己跟着写了一遍之后对SwiftUI也是有了一个基本的认识。我们在后面遇到的一些问题也会回到这个官方文档进行一些验证。
SwiftUI
在进入项目搭建先说说我自己对SwiftUI的一个基本的认知:
SwiftUI我觉得对iOSer来说最大的是开发UI模式的优化,针对一个需求或者是一个新的项目我们基本上都是从写UI开始的,根据设计图再编造一些假数据来做,只是在写的过程中它的及时效果也都是脑补!SwiftUI我觉得能改变的痛点就是这点,能让我们实时预览自己写的UI效果,保持我们代码和界面的同步性!
声明式UI:关于它的理解往细了说,的确能专门写一篇文章出来,下面这篇文章能很好的帮助理解我们现在使用的命令式和SwiftUI采用的声明式UI之间的区别。
跨平台: 在最新的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!
参考文章:
从用SwiftUI搭建项目说起的更多相关文章
- ASP.NET MVC搭建项目后台UI框架—1、后台主框架
目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...
- ASP.NET MVC搭建项目后台UI框架—11、自动加载下拉框查询
ASP.NET MVC搭建项目后台UI框架—1.后台主框架 需求:在查询记录的时候,输入第一个字,就自动把以这个字开头的相关记录查找出来,输入2个字就过滤以这两个子开头的记录,依次类推. 突然要用到这 ...
- ASP.NET MVC搭建项目后台UI框架—2、菜单特效
目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...
- ASP.NET MVC搭建项目后台UI框架—3、面板折叠和展开
目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...
- ASP.NET MVC搭建项目后台UI框架—4、tab多页签支持
目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...
- ASP.NET MVC搭建项目后台UI框架—5、Demo演示Controller和View的交互
目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...
- ASP.NET MVC搭建项目后台UI框架—6、客户管理(添加、修改、查询、分页)
目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...
- ASP.NET MVC搭建项目后台UI框架—7、统计报表
ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NET M ...
- ASP.NET MVC搭建项目后台UI框架—8、将View中选择的数据行中的部分数据传入到Controller中
目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...
随机推荐
- Python基础数据类型与for循环
数据类型:int,bool,str,list, tuple元组,dict字典. 1.数字:12,3,4 在使用print打印数字时,在终端界面中无法判断出打印的是什么类型,当我们需要知道一个值是什么类 ...
- Elementary OS 使用fcitx安装搜狗词库、搜狗输入法(Linux通用)
刚开始接触Linux的小伙伴可能比较懵逼,我要使用ibus输入法还是fcitx(小企鹅)输入法,其实这两种都不能说是输入法,Linux中输入法的使用是依赖于输入法框架的,其中搜狗输入法和百度输入法都是 ...
- python-基础入门-序
安装,直接百度Python就行,我是2.7的版本. 我的资料先是<笨办法学Python>,作为简单的入门它写的很有趣. 我有简单的c语言的基础,把它过完后上核心编程,当然,一切都是为了ct ...
- 对数组进行排序成最小的,相当于自己实现了一次String的compareTo函数,不过是另类的。
题目描述 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. //一气呵成 ...
- Python JSON存储数据
前言: 很多程序都要求用户输入某种信息,如让用户存储游戏首选项或提供要可视化的数据.不管专注的是什么,程序都把用户提供的信息存储在列表和字典等数据结构中.用户关闭 程序时,你几乎总是要保存他们提供的信 ...
- Java命令行启动jar包更改默认端口以及配置文件的几种方式
Java命令行启动jar包更改默认端口以及配置文件的几种方式 java -jar xxx.jar --server.port=8081 默认如果jar包没有启动文件,可以采用这种方式进行启动 java ...
- 精尽MyBatis源码分析 - MyBatis-Spring 源码分析
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- Alpha冲刺-第七次冲刺笔记
Alpha冲刺-冲刺笔记 这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzzcxy/2018SE2 这个作业要求在哪里 https://edu.cnblogs. ...
- python将对象写入文件,以及从文件中读取对象
原文地址: http://www.voidcn.com/article/p-fqtqpwxp-wo.html 写入文件代码: >>> import sys, shelve >& ...
- springboot补充
springboot中的日志: 在默认的spring-boot-starter中,会引入spring-boot-starter-logging, 而springboot-starte-longing中 ...