declarative Swift code로 만들어진 UI 프레임워크
들여쓰기 정리
File > New > Project
프로젝트를 만들 때 swiftui delegate로 만들면 scene delegate파일이 안보인다
https://flatuicolors.com/ 커스텀 색상
https://www.uicolor.io/#/hex-to-ui 16진수에서 rgb로 변경
https://developer.apple.com/design/human-interface-guidelines/sf-symbols/overview/ SFsymbols
레이블에 드래그하기
프로젝트 우클릭 > New Group > fonts > .ttf 추가
Font.custom("", size: <#T##CGFloat#>)
백그라운드 화면에 safe area 안에만 색이 입혀졌는데
그 밖에도 추가하려고 사용
Image Resizable
struct ContentView: View {
var body: some View {
ZStack {
Color(.systemTeal).edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
VStack {
Text("I Am Rich")
.font(.system(size: 40))
.fontWeight(.bold)
.foregroundColor(Color.white)
.padding()
Image("diamond")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 200, height: 200, alignment: .center)
}
}
}
}
hex코드
https://flatuicolors.com
hext코드 -> UIColor
https://www.uicolor.io/#/hex-to-ui
Fonts폴더그룹 생성하고
다운받은 파일(NotoSansKR-Regular.otf) 집어넣기
info.plist에 추가
Fonts provided by application
Item 0 Sanserif.ttf
Clip Shape
뷰 위에 뷰 추가하기
extract subview
InfoView.swift 파일을 생성하고 재사용할 수 있게 만들기
import SwiftUI
struct InfoView: View {
let text: String
let imageName: String
var body: some View {
RoundedRectangle(cornerRadius: 30)
.fill(Color.white)
.frame(height: 50)
.overlay(HStack {
Image(systemName: imageName)
.foregroundColor(Color.green)
Text(text)
})
.padding(.all)
}
}
struct InfoView_Preview: PreviewProvider {
static var previews: some View {
InfoView(text: "Hello", imageName: "phone.fill")
.previewLayout(.sizeThatFits)
}
}
// ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Color(red: 0.18, green: 0.80, blue: 0.44)
.edgesIgnoringSafeArea(.all)
VStack {
Image("angela")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 150, height: 150)
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 5))
Text("안젤라")
.font(Font.custom("NotoSansKR-Regular.otf", size: 40))
.fontWeight(.bold)
.foregroundColor(Color.white)
.padding()
Text("iOS Developer")
.font(.system(size: 25))
.foregroundColor(Color.white)
Divider()
InfoView(text: "angela@gmail.com", imageName: "evnvelope.fill")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Text Not Displaying Correctly in Dark Mode
.foregroundColor(Color("Info Color"))
주사위 던지기 게임 swiftUI로 만들기
managing state in SwiftUI
struct 안에서 property를 변경하면
old copy는 destroy되고 new copy가 대체한다
SwiftUI에서는 특별한 wrapper @State를 붙여주면
property의 변경사항을 체크해서 ContentView를 rebuild한다
// ContentView.swift
import SwiftUI
struct ContentView: View {
//variable이 변경되면 ContentView를 새로 생성
@State var leftDiceNumber = 1
@State var rightDiceNumber = 2
var body: some View {
ZStack {
Image(/*@START_MENU_TOKEN@*/"background"/*@END_MENU_TOKEN@*/)
.resizable()
.edgesIgnoringSafeArea(.all)
VStack {
Image("diceeLogo")
Spacer()
HStack {
DiceView(n: leftDiceNumber)
DiceView(n: rightDiceNumber)
}
.padding(.horizontal)
Spacer()
Button(action: {
self.leftDiceNumber = Int.random(in: 1...6)
self.rightDiceNumber = Int.random(in: 1...6)
}) {
Text("Roll")
.font(.system(size: 50))
.fontWeight(.bold)
.foregroundColor(Color.white)
.padding(.horizontal)
}
.background(Color.red)
}
}
}
}
struct DiceView: View {
let n: Int
var body: some View {
Image("dice\(n)")
.resizable()
.aspectRatio(1, contentMode: .fit)
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
id라는 String형식의 변수가 필요
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
List(posts) { post in
Text(post.title)
}
.navigationBarTitle("H4X0R NEWS")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct Post: Identifiable {
let id: String
let title: String
}
let posts = [
Post(id: "1", title: "Hello"),
Post(id: "2", title: "Bye"),
Post(id: "3", title: "Chao")
]
Observer Design Pattern + Networking
broadcast one or many of its properties to andy interested parties
@Published
var posts = Post (notify all of the listeners)
RSS 피드와 비슷하다
posts를 subscribe하면 콘텐츠가 바뀔 때 hear한다
@ObservedObject
var networkManager = NetworkManager()
set up a property as a listener (리스너 설정한다)
posts를 publish하고 업데이트가 되면 리스너에서 즉시 알아챈다
//ContentView.swift
import SwiftUI
struct ContentView: View {
@ObservedObject var networkManager = NetworkManager()
var body: some View {
NavigationView {
List(networkManager.posts) { post in
HStack {
Text(String(post.points))
Text(post.title)
}
}
.navigationBarTitle("H4X0R NEWS")
}
.onAppear(perform: {
self.networkManager.fetchData()
})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
//NetworkManager.swift
import Foundation
class NetworkManager: ObservableObject {
@Published var posts = [Post]()
func fetchData() {
if let url = URL(string: "http://hn.algolia.com/api/v1/search?tags=front_page") {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if error == nil {
let decoder = JSONDecoder()
if let safeData = data {
do {
let results = try decoder.decode(Results.self, from: safeData)
//💥주의
DispatchQueue.main.async {
self.posts = results.hits
}
} catch {
print(error.localizedDescription)
}
}
}
}
task.resume()
}
}
}
//PostData.swift
import Foundation
struct Results: Decodable {
let hits: [Post]
}
struct Post: Decodable, Identifiable {
var id: String {
return objectID
}
let objectID: String
let points: Int
let title: String
let url: String?
}
SwiftUI View 파일 생성 -> DetailView.swift
//NavigationLink로 이동 가능해진다
//ContentView.swift
NavigationView {
List(networkManager.posts) { post in
NavigationLink(destination: DetailView(url: post.url)) {
HStack {
Text(String(post.points))
Text(post.title)
}
}
}
.navigationBarTitle("H4X0R NEWS")
}
//DetailView.swift
import SwiftUI
struct DetailView: View {
let url: String?
var body: some View {
WebView(urlString: url)
}
}
struct DetailView_Previews: PreviewProvider {
static var previews: some View {
DetailView(url: "https://www.google.com")
}
}
//재사용하기 위해 분리
//SwiftUI는 아직 WebKit가 없어서 가져와서 만들어주기
//WebView.swift
import Foundation
import SwiftUI //💥
import WebKit
struct WebView: UIViewRepresentable {
let urlString: String?
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ uiView: WKWebView, context: Context) {
if let safeString = urlString {
if let url = URL(string: safeString) {
let request = URLRequest(url: url)
uiView.load(request)
}
}
}
}
Marzipan 마지팬
아이폰과 아이패드에 사용하는 앱을 맥에서 사용할 수 있게 하자
iOS 앱을 빌드하는데 사용하는 UIKit 프레임워크를 맥으로 가져오자
프로젝트 클릭 > Target > Mac 체크
Signing&Capabilities > signing
https://developer.apple.com/documentation/uikit/mac_catalyst
https://zeddios.tistory.com/239