본문 바로가기
2023년 이전/iOS

SwiftUI - tutorial(Creating and Combinding Views)

by JeongUPark 2020. 7. 14.
반응형

Apple에서 제공하는 SwiftUI tutorial을 공부하면서 작성한 내용입니다.

 

SwiftUI는 Apple에서 제공한 신규 UI 작성 방식으로 선언적 구문을 사용하므로 사용자 인터페이스의 기능을 명시하기만 하면 됩니다. 그래서 이전에 storyboard를 사용했을 때는 알아보거나 해석하기 힘든 xml이 아닌 swift파일에서 선언적 구문으로 UI를 작성할 수 있습니다.

 

그럼 간단한게 사용하는 방법을 확인해 보겠습니다.

프로젝트 생성

우선 project를 만듭니다. project를 만들 때 

 

위의 이미지 처럼 Single View App을 선택하고 Language는 Swift User Interface는 SwiftUI를 선택하여 프로젝트를 생성합니다.

그러면 아래와 같이 항목들을 가진 프로젝트가 생성 됩니다.

그리고 생성된 파일중 ContentView.swift의 code를 보면

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

이렇게 생성됩니다. 2개의 구문이 생성되는데 위의 ContentView: View 는 View의 Protocal을 따르고 View의 내용과 Layout을 나타냅니다. 아래 ContentView_PreViews는 미리보기를 선언합니다.

 

그리고 화면을 보면 

오른쪽에 빈 공간에 Preview가 나타나는데 안나타난다면 Resume을 누르면 Preview가 나타납니다.

기본 조절

자 그럼 ContentView의 Code를 수정하여 나타날 UI를 변경할 수 있습니다.

 

우선 PreView에 있는 Hellow, World!를 Command키를 누르고 클릭 하면 

이런게 항목들이 나타나고 Show Swift Inspector를 누르면 TextView에 대한 항목을 볼 수 있습니다.

 

그래서 Text에 문구를 수정하면 PreView의 문구도 변경되고 ContentView의 code에 문구도 변경됩니다.

Custom TextView

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("JeonguPark")
            .font(.title)
            .foregroundColor(.green)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

그리고 추가로 code에서 .froegroundColor을 하면 바로 PreView에도 적용 됩니다.

그리고 Code에서 Command 를 누르고 Text를 클릭하면 

PreView에서 했던것과 동일한 효과를 화긴 할 수 있습니다.

VStack과 HStack

그리고 Body는 하나의 View만을 반환합니다. 그래서 묶음이 필요합니다. 우선 Text를 Command 클릭하고 Embed VStack을 선택합니다.

 

그리고 Xcode 우측 상단의 plus 버튼을 눌리고 text를 드레그해서 code나 Preview의 jeongupark 밑으로 추가해줍니다.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(alignment:.leading){
            Text("JeonguPark")
                .font(.title)
                .foregroundColor(.green)
            Text("study swiftUI")
                .font(.subheadline)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

그리고 위오 같이 수정하면 추가한 Text의 글자의 크기가 줄어 듭니다. 또한 VStack에 alignment를 정하면 정렬이 정해집니다. default는 center이고 / .leading은 왼쪽 정렬 / .trailing은 우측 정렬 입니다. 

 

그리고 나서 추가한 Text를 command 클릭하여 HStack을 선택합니다. 그리고 그 HStack 안에 다음과 같이 Text를 추가하면 가로 정렬 됩니다. 즉 VStack는 세로, HStack은 가로로 View를 정렬합니다.

struct ContentView: View {
    var body: some View {
        VStack(alignment:.leading){
            Text("JeonguPark")
                .font(.title)
                .foregroundColor(.green)
            HStack {
                Text("study swiftUI")
                    .font(.subheadline)
                Text("Very Hard")
                    .font(.subheadline)
            }
        }
    }
}

Spacer와 padding

Spacer()은 View 사이의 간격을 별러주는데, 부모 뷰의 크기만큼 벌리게 됩니다.

struct ContentView: View {
    var body: some View {
        VStack(alignment:.leading){
            Text("JeonguPark")
                .font(.title)
                .foregroundColor(.green)
            HStack {
                Text("study swiftUI")
                    .font(.subheadline)
                Spacer()
            
                Text("Very Hard")
                    .font(.subheadline)
            }
        }
    }
}

그리고 VStack에 .padding()을 하면 padding이 생성 됩니다.

struct ContentView: View {
    var body: some View {
        VStack(alignment:.leading){
            Text("JeonguPark")
                .font(.title)
                .foregroundColor(.green)
            HStack {
                Text("study swiftUI")
                    .font(.subheadline)
                Spacer()
            
                Text("Very Hard")
                    .font(.subheadline)
            }
        }.padding()
    }
}

ImageVIew

추가할 이미지를 project에 Assets.xcassets등록을 해줍니다. 그리고 이미지를 만들 SwiftUI 파일을 새로 만들어 줍니다. (파일 이름은

CircleImageView)

struct CircleImageView: View {
    var body: some View {
        Image("cat")
            .clipShape(Circle())
            .overlay(
                Circle().stroke(Color.red, lineWidth: 10))
            .shadow(radius: 5)
        
    }
}

struct CircleImageView_Previews: PreviewProvider {
    static var previews: some View {
        CircleImageView()
    }
}

CircleImageView의 코드를 보면 위와같고 그 결과는 다음과 같습니다.

 

overlay는 둘레를 shadow는 그림자를 보여줍니다.

 

MapView 추가

SwiftUI는 UIKit를 지원합니다. 그래서 UIkit에서 지원하는 MapKit도 쓸 수 있습니다.

import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
    func makeUIView(context: Context) -> MKMapView {
           MKMapView(frame: .zero)
       }

       func updateUIView(_ view: MKMapView, context: Context) {
           let coordinate = CLLocationCoordinate2D(
               latitude: 34.011286, longitude: -116.166868)
           let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
           let region = MKCoordinateRegion(center: coordinate, span: span)
           view.setRegion(region, animated: true)
       }
}

struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView()
    }
}

Map을 사용할 수 있도록 import MapKit를 추가하고, MapView 의 콜론 옆에 View를  UIViewRepresentable로 변경합니다. 그럼 errorr가 발생하는데 위와같이 2개의 method를 추가하면 error가 사라집니다. 그리고 View가 아니고 UIViewRepresentable를 확장해도 문제가  없는게 makeUIView에서 View를 반환하고, updateUIView에서 위치를 지정하기 떄문입니다.

 

그리고 우측 하단의 활성화 버튼을 눌려 Preview를 활성화 시키면 map이 활성화됩니다. (안되면 resume을 눌려주세요)

 

합체!

 

지금까지 만든 뷰들을 합체보겠습니다.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            MapView().frame(height: 300).edgesIgnoringSafeArea(.top)
            CircleImageView()
                .offset(y:-100)
                .padding(.bottom,-130)

            VStack(alignment:.leading){
                Text("JeonguPark")
                    .font(.title)
                    .foregroundColor(.green)
                HStack {
                    Text("study swiftUI")
                        .font(.subheadline)
                    Spacer()
                    
                    Text("Very Hard")
                        .font(.subheadline)
                }
            }.padding()
            
            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

MapView()로 생성한 MapView를 추가하고 height로 MapView의 높이를 정해줍니다.(witdh를 정하지 않으면 부모뷰만큼 채웁니다.)

그리고 CircleImageVIew()로 CircleImageVIew를 추가하고 offset으로 위치를 -130만큼 이동하고, padding에 bottom -130만큼 줍니다. (bottm -130을 했기 떄문에 아래 VStack이 올라오게 됩니다.)

그리고 MapView에 edgesIgnoringSafeArea를 추가함으로서 상단 스테이터스 바까지 map이 채워집니다.

결과는 다음과 같습니다.

map을 보여주기 위해 활성화 버튼을 눌려야하고, 활성화 중이라도 code가 변경되면 변경된 내용이 적용 됩니다. 

 

그리고 시뮬레이터를 실행해보면 위의 View가 나타나게 되는데 그 이유는 

 

아까 프로젝트를 만들었고 생성된 파일 중 SceneDelegate 가 있는데 여기 안에 보면

scene 에 보면 

let contentView = ContentView() 로 contentView가 지정되서 입니다. 만일 

let contentView = CircleImageView()를 하면  고양이 이미지만 나올 것 입니다.

 

 

다음에 기회되면 SceneDelegate 에 대해 자세히 파보겠습니다.

 

 

반응형