在本章中,你将学会运用URLSession
和ContextMenu
构建一个ColourAtla
色卡App
。
项目布景
一直以来,关于我国传统色彩有种特别的喜爱。
而在阅读一些资讯时看到博主发布的一些色彩搭配的内容,其中就谈到了色卡的概念,经过一些了解和学习,就想着打造一款色彩搭配App。
虽然App
没有完全开发完结,但在此分享一下其中一些现已完结的功能构建办法,希望能够协助到SwiftUI
开发者们。
那么,废话少说,让咱们开始吧。
项目搭建
首要,创立一个新的SwiftUI
项目,命名为ColourAtla
。
页面搭建
咱们简略剖析下页面的组成结构,它是由一个Title
标题和一个色卡List
列表构成,然后在色卡列表中,长按单张色卡,就能够取得悬浮窗口作用。
了解完基本组成后,咱们一块一块来构建内容。
标题搭建
首要是标题部分,咱们运用OpaqueTypes
不透明类型的办法构建View
。示例:
//MARK: 标题
private var CardTitleView: some View {
Text("世界最高级的色彩")
.font(.system(size: 17))
.fontWeight(.bold)
}
上述代码中,咱们声明晰一个私有的视图CardTitleView
,然后在里面构建了咱们需求的标题Text
,并运用一些修饰符让内容看起来协调一些。
色彩扩展
标题创立完结后,咱们来构建色卡列表,在构建色卡之前,为了能运用十六进制色彩值,咱们给现有Color
色彩构建办法做一下Extension
扩展。示例:
咱们创立一个新的Swift
文件,命名为ColorHexString
。
import SwiftUI
extension Color {
static func rgb(_ red: CGFloat, green: CGFloat, blue: CGFloat) -> Color {
return Color(red: red / 255, green: green / 255, blue: blue / 255)
}
static func Hex(_ hex: UInt) -> Color {
let r: CGFloat = CGFloat((hex & 0xFF0000) >> 16)
let g: CGFloat = CGFloat((hex & 0x00FF00) >> 8)
let b: CGFloat = CGFloat(hex & 0x0000FF)
return rgb(r, green: g, blue: b)
}
}
上述代码中,咱们给Color
进行了Extension
扩展。
咱们经过接收一个UInt
十六进制色彩值,然后把它转换成RGB
色彩值,这样咱们只需求输入十六进制色彩值,Color
就能够转换为能够运用的RGB
色彩值了。
单张色卡
接下来,咱们回到ContentView
文件,先来构建单张色卡。示例:
// MARK: 卡片视图
struct CardViewExamples: View {
var body: some View {
ZStack(alignment: Alignment(horizontal: .center, vertical: .center), content: {
// 布景卡片
Rectangle()
.fill(Color.Hex(0xFF0000))
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 110)
.cornerRadius(8)
HStack {
VStack(alignment: .leading, spacing: 10) {
//色彩称号
Text("我国红")
.fontWeight(.bold)
.foregroundColor(Color.white)
.font(.system(size: 17))
// 色彩值
Text("#FF0000")
.fontWeight(.bold)
.foregroundColor(Color.white)
.font(.system(size: 14))
}
Spacer()
}.padding()
})
}
}
上述代码中,咱们运用Struct
结构体创立视图的办法构建了单张色卡的内容。
在单张色卡,咱们构建了一个Rectangle
矩形作为布景,然后填充了一个“我国红”,顺便调整了它的大小和圆角。
依此再构建了两个Text
,作为色彩称号和色彩值,最终运用ZStack
将三个元素组成一个全体。
为什么需求运用Struct
结构体的办法,而不运用OpaqueTypes
不透明类型的办法,这是因为咱们构建的色卡之后需求提取参数出来,然后在ContentView
视图中遍历多张色卡,因而运用Struct
结构体的办法创立视图。
参数抽离
接下拉,为了更加方便地遍历出多张色卡,咱们将相同的参数进行抽离替换。
在色卡列表中,咱们抽离色卡布景色、色卡色彩称号、色卡色彩值3个参数,示例:
var cardBGColor: Color
var cardColorName: String
var cardColorRBG: String
抽离出参数后,因为咱们没有给CardViewExamples
结构体中的参数赋值,因而咱们在ContentView
视图调用时需求补充参数对应的参数值。
CardViewExamples(cardBGColor: Color.Hex(0xFF0000), cardColorName: "我国红", cardColorRBG: "#FF0000")
悬浮窗口
单张色卡完结后,咱们来测验完结长按色卡引发悬浮窗口并完结复制色彩值。
在之前的章节中,咱们学习过ContextMenu
上下文菜单的运用,在这里咱们仍旧运用的是ContextMenu
上下文菜单构建悬浮窗口。示例:
// 长按复制色彩值
.contextMenu {
Button(action: {
UIPasteboard.general.string = cardColorName
}, label: {
Text("复制色彩值")
})
}
.padding(.horizontal)
上述代码中,咱们运用ContextMenu
上下文菜单创立了悬浮窗口。
当咱们长按单张色卡时,咱们就把cardColorName
卡片色彩值的内容复制到剪切板中,这样咱们就完结了经过长按复制色卡色彩值的交互。
数据模型
模型创立
完结单张色卡创立后,咱们需求根据单张色卡的内容遍历多张色卡,通用的办法是创立模型数组,再根据模型数组结合网络请求,取得放在服务端的Json数据,然后再在本地烘托。
咱们创立一个Swift
文件,命名为Model.swift
。
import SwiftUI
struct CardModel:Decodable {
var cardBGColor: UIn
var cardColorName: String
var cardColorRBG: String
}
上述代码中,咱们创立了一个结构体CardModel
,遵从Decodable
协议。
Decodable
协议,用于将JSON
目标解析为结构体或类,这样咱们就能够经过网络请求取得JSON目标
,然后经过Decodable
协议解析在本地。
因为咱们的色卡布景色彩是十六进制的色彩值,因而cardBGColor
参数需求声明为UInt
类型,其他cardColorName
、cardColorRBG
都是String
字符串类型。
咱们回到ContentView
文件中,首要咱们先取得定义好的CardModel
结构体。
@State var cardItems: [CardModel] = []
然后,咱们运用OpaqueTypes
不透明类型的办法创立一个卡片视图,咱们将CardListView
视图展现在ContentView
中展现。
// MARK: 色卡列表视图
private var CardListView: some View {
ScrollView(.vertical, showsIndicators: false, content: {
ForEach(cardItems, id: \.cardColorRBG) { item in
VStack(spacing: 20) {
CardViewExamples(cardBGColor: Color.Hex(item.cardBGColor), cardColorName: item.cardColorName, cardColorRBG: item.cardColorRBG)
}
}
})
}
这样,色卡列表视图的结构就创立好了。
可是咱们在预览时没有看到色卡,这是因为咱们的色卡列表视图仅仅搭建了结构,可是没有数据,下面咱们来完结数据部分。
Json数据
色卡结构搭建好后,咱们在云端创立好Json
数据。
[{"cardBGColor":16711680,"cardColorRBG":"#FF0000","cardColorName":"我国红"},{"cardBGColor":15226919,"cardColorRBG":"#E85827","cardColorName":"爱马仕橙"},{"cardBGColor":16439902,"cardColorRBG":"#FADA5E","cardColorName":"拿破里黄"},{"cardBGColor":35980,"cardColorRBG":"#008C8C","cardColorName":"马尔斯绿"},{"cardBGColor":3175035,"cardColorRBG":"#30727B","cardColorName":"不来梅蓝"},{"cardBGColor":6901074,"cardColorRBG":"#694D52","cardColorName":"莫兰迪色"},{"cardBGColor":5338771,"cardColorRBG":"#517693","cardColorName":"马耳他蓝"},{"cardBGColor":12199,"cardColorRBG":"#002FA7","cardColorName":"克菜因蓝"}]
上述代码中,咱们在某渠道创立了Json
数据,并且取得了能够拜访Json
数据的API
接口。
咱们将API接口地址复制,并在ContentView
中声明一个常量存储它。
let JsonURL = "https://api.npoint.io/dc5a1718e0e958613ade"
网络请求
API接口有了,本地色卡列表视图结构也建立好了,下一步咱们来完结网络请求部分。
// MARK: 网络请求
func getColors() {
let session = URLSession(configuration: .default)
session.dataTask(with: URL(string: JsonURL)!) { data, _, _ in
guard let jsonData = data else { return }
do {
let colors = try JSONDecoder().decode([CardModel].self, from: jsonData)
self.cardItems = colors
} catch {
print(error)
}
}
.resume()
}
上述代码中,咱们创立了一个网络请求的办法getColors
,咱们运用官方供给的URLSession
网络请求结构,然后取得URL
地址JsonURL
的数据,并经过JSONDecoder
解析json
数据与CardModel
数组中的参数做匹配,匹配上后将数据存储到cardItems
中。
咱们在ContentView
视图展现的时候调用getColors
办法。
.onAppear(perform: {
getColors()
})
咱们点击模拟器上的运转操作,预览下作用。
Loading加载
因为网络请求需求时间,为了让咱们ColourAtla
色卡App
的体会更好,在色卡列表视图还没有加载完结时,咱们能够添加一个Loading
视图作为缺省展现。示例:
if cardItems.isEmpty {
Spacer()
ProgressView()
Spacer()
} else {
CardListView
}
咱们最终预览下全体作用。
以上便是本章全部内容。
快来着手试试吧!
如果本专栏对你有协助,不妨点赞、评论、重视~
我正在参加技能社区创作者签约方案招募活动,点击链接报名投稿。