使用Xcode13进行Swift开发2
使用Xcode13进行Swift开发https://blog.csdn.net/gavinliu266/article/details/126407896
Monterey错误已在本博客中修正
1.应用功能
快捷键与SFsymbols请看文首链接。
1.1 UIScreen与systemName
为了方便演示,我将新建一个swift文件
选择一个swift文件,右键-New File-SwiftUI View,命名CardView,并将Targets中的Test_WidgetExtension钩上
创建一个简单的卡片
struct CardView: View {
var body: some View {
ZStack {
Image("Monterey")
.resizable()
.frame(width:200,height:200)
.cornerRadius(20)
.shadow(color: Color.black.opacity(0.4), radius: 30, x: 0, y: 30)
VStack {
Text("Macos12 Monterey")
.font(.title)
.fontWeight(.bold)
.frame(width:200)
.foregroundColor(.white)
Image(systemName: "person.2")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width:100,height: 100)
.foregroundColor(.white)
}
}
}
}
这里width我们暂时设置200
systemName:
在SFsymbols中找到想要的图标,但是如果在右边栏中显示的系统ios版本比你的Xcode所支持的版本要高,那么你也不能使用它。例如我的Xcode13.4.1对于是可以支持的,但是对于由于需要iOS 16.0+,所以不能支持
接下来Command 点击ZStack,嵌入一个HStack,然后提取子视图,命名为Card
现在效果:
接下来我可以把
.frame(width:200,height:200)
替换成
.frame(width:UIScreen.main.bounds.width / 1.5,height:200)
并且把
.frame(width:100,height: 100)
替换成
.frame(width:UIScreen.main.bounds.width / 3,height: 100)
还有
.frame(width:200)
替换成
.frame(width:UIScreen.main.bounds.width / 1.5)
当然还有更好的方法,但是我们先用这个
1.2 struct,ScrollView,padding,ForEach和创建列表
现在我们只有一个,那么如果有多个的话,我不想创建多个Card程序,所以我需要把一些值用参数传进来
在Card中
var body: some View{...}
之前,我们添加
var image: String
var text: String
var systemImage: String
然后将两个图像和一个文本用参数代替
struct Card: View {
var image: String
var text: String
var systemImage: String
var body: some View {
ZStack {
Image(image)
.resizable()
.frame(width:UIScreen.main.bounds.width / 1.5,height:200)
.cornerRadius(20)
.shadow(color: Color.black.opacity(0.4), radius: 30, x: 0, y: 30)
VStack {
Text(text)
.font(.title)
.fontWeight(.bold)
.frame(width:UIScreen.main.bounds.width / 1.5)
.foregroundColor(.white)
Image(systemName: systemImage)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width:UIScreen.main.bounds.width / 3,height: 100)
.foregroundColor(.white)
}
}
}
}
然后在调用的地方改成
Card(image: "Monterey", text: "Macos12 Monterey", systemImage: "person.2")
然后在HStack前面加上
ScrollView:滚动视图,
.horizontal:横向滚动,
.showIndicators: false:不显示滚动条
.padding默认给全方位添加默认值填充,第一个参数用于设置填充方向,第二个参数用于设置填充大小
ScrollView(.horizontal ,showsIndicators: false) {
后面补上
.padding(.horizontal,20)
.padding(.bottom,80)
}
全选,Ctrl + I调整缩进
好了,让我们开始创建一个结构体
然后创建一个列表
var CardViewList = [
CardList(image: "Monterey", text: "Macos12 Monterey", systemName: "person.3"),
CardList(image: "BigSur", text: "Macos11 Big Sur", systemName: "person.2"),
CardList(image: "Catalina", text: "Macos10.15 Catalina", systemName: "person")
]
回到Card中,删掉var image等三个,换成
var cardviewlist: CardList
将以下代码
Image(image)
换成
Image(cardviewlist.image)
将以下代码
Text(text)
换成
Text(cardviewlist.text)
将以下代码
Image(systemName: systemImage)
换成
Image(systemName: cardviewlist.systemName)
到Card(…),Command+单击,选择Repeat
改以下代码
ForEach(0 ..< 5)
为
ForEach:循环
ForEach(CardViewList.indices,id: \.self)
并将以下代码
Card(image: "Monterey", text: "Macos12 Monterey", systemImage: "person.2")
换成
Card(cardviewlist: CardViewList[index])
然后给HStack加一个间距
现在是
ScrollView(.horizontal ,showsIndicators: false) {
HStack(spacing:70) {
ForEach(CardViewList.indices,id: \.self) { index in
Card(cardviewlist: CardViewList[index])
}
}
.padding(.horizontal,20)
.padding(.bottom,80)
}
很好
1.3 GeometryReader
关于UIScreen.main.bounds不是最好的解决方案上文提到过了,如下,当改变了屏幕的宽度或高度时,它不会自动调整
所以这个时候我们就需要用到GeometryReader了
首先,将HStack嵌入几何阅读器,并添加bounds in
然后在Card里面添加一个变量
var bounds: GeometryProxy
就可以替换以下代码了
UIScreen.main.bound
换成
bounds.size
并且在调用时添加变量
Card(
cardviewlist: CardViewList[index],
bounds: bounds)
完美
由于UIScreen是静态的,所以没有办法在变更时对其值进行更改,但GeometryReader是动态的,所以当我们变换布局时,它的值也会变动,因此卡片的大小也就跟着变动了
1.4 list,combine
当我们使用app时,经常会看见列表
图片来源于网络
首先要想要实现的话,我们首先要创建列表
创建一个swiftUI类型的文件,命名为MacosList,
然后在创建一个swiftUI类型文件,命名为MacosListStore
进入MacosListStore,删除全部代码,然后粘贴以下代码用于编辑
import SwiftUI
import Combine
class ListStore : ObservableObject {
@Published var list : [CardList] = CardViewList
}
接着在MacosList中的var body: some View {…}之前加入
@ObservedObject var store = ListStore()
func addList(){
store.lists.append(CardList(image: "Monterey", text: "Macos12 Monterey", systemName: "person.3"))
}
然后var body: some View中加入
GeometryReader { bounds in
NavigationView{
List {
ForEach(store.lists.indices,id: \.self) { index in
NavigationLink(destination: Card(cardviewlist: store.lists[index], bounds: bounds)) {
HStack {
Image(store.lists[index].image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 80, height: 80)
.background(Color.black)
.cornerRadius(20)
.padding(.trailing,4)
VStack(alignment: .leading, spacing: 8.0) {
Text(store.lists[index].text)
.font(.headline)
.fontWeight(.bold)
.lineLimit(2)
.foregroundColor(Color.black)
Image(systemName: store.lists[index].systemName)
.foregroundColor(.black)
}
}
.padding(.vertical,8)
}
}
.onDelete{ index in
self.store.lists.remove(at: index.first!)
}
.onMove{(source: IndexSet,destination: Int) in
self.store.lists.move(fromOffsets: source,
toOffset: destination)
}
}
.navigationBarTitle(Text("Updates"))
.navigationBarItems(leading: Button(action: addList) {
Text("Add Update")
} ,trailing: EditButton())
}
}
上面的代码由于比较多,所以我就不一一解释了,就是把列表中的静态数据转换成动态数据,然后输出。通过onDelete和onMove来进行移动和删除操作。
另外名字之所以取为MacosList而不去为List,是因为如果取为List的话会报错,因为与List同名
最后回到ContentView,删除<-50的判断,然后在sheet里面换成MacosList
效果很好