궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
PROJECT/Simple

SwiftUI Project1 : Extension으로 정보가져오기

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

Project 1

1. Extentsion 생성하기

ExtensionList를 사용하여 Swift에서 간단하게 화면을 구성하고 정보를 가져오는 방법에 대해서 알아보도록 하겠습니다.

 

일단 Xcode를 열어 프로젝트를 하나 생성 해주고, SwiftUI 파일을 하나 더 생성해주겠습니다. 파일 이름은 임의로 'Person'이라고 정해줄게요.

Extension값을 정해줘야 하는데 코드는 아래와 같이 만들어 주겠습니다.

import Foundation

struct Person {
    
    let name: String
    let age: Int
    let imageURL: String
    let height: Double
    let weight: Float
}

extension Person {
    static func all() -> [Person] {
        
        return [
            Person(name: "하울", age: 26, imageURL: "하울", height: 180.543, weight: 72.5),
            Person(name: "포뇨", age: 7, imageURL: "포뇨", height: 120.242, weight: 20),
            Person(name: "소피아", age: 18, imageURL: "소피아", height: 165.232, weight: 43)
        ]
    }
}

위와 같이 함수를 정해주고 딕셔너리로 정보를 저장해줬습니다. Assets 파일에 imageURL에 넣어줬던 각각의 파일을 넣어주겠습니다.

ContentView로 돌아가서 이 정보를 화면에 표시해보도록 하겠습니다.

struct ContentView: View {
    
    let people = Person.all()
    
    var body: some View {
        List(self.people, id: \.name) { person in
            HStack {
                Image(person.imageURL)
                    .renderingMode(.original)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(width: 100, height: 100)
                    .cornerRadius(20)
                Text(person.name)
            }
        }
    }
}

ImageframecornerRadius값을 줘서 화면에 맞게 설정해줍니다.

자동으로 설정해준 이미지와 이름이 화면에 구성된 것을 확인할 수 있죠? :)

 

만약 body 부분이 너무 길어져서 간단하게 하고 싶으면 HStack 부분을 + 클릭해서 Extract Subview로 묶어줍니다.

그럼 List 밑에 ExtractedView()가 생성되고 Previews 밑에 Struct가 생성됩니다.

struct ExtractedView: View {
    var body: some View {
        HStack {
            Image(person.imageURL)
                .renderingMode(.original)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: 100, height: 100)
                .cornerRadius(20)
            Text(person.name)
        }
    }
}

ImageText 쪽에 오류가 났습니다. ExtractedViewperson값을 넣어주고 이름도 바꿔보도록 하겠습니다.

struct Characters: View {
    let person: Person
    var body: some View {
        HStack {
            Image(person.imageURL)
                .renderingMode(.original)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: 100, height: 100)
                .cornerRadius(20)
            Text(person.name)
        }
    }
}

Characters 뷰에서는 오류가 사라졌지만 여전히 ContentViewCharacters()에는 오류가 납니다..

Characters에 매개변수를 추가해줘 보도록 하겠습니다. 일단 person in을 해줬으니 그것을 넣고, Characters에 let person: Person을 넣어줬으니 이것을 매개변수 타입으로 넣어주면 되겠죠?

    var body: some View {
        List(self.people, id: \.name) { person in
            Characters(person: person)
        }
    }

런 해보면 제대로 작동합니다! ☺️ 

 

이제 캐릭터 이름 밑에 각각의 정보를 표시해주도록 하겠습니다.

나이를 표시하고 싶다고 해서 위와 같이 작성하게 되면 '이니셜 라이저 호출에 정확히 일치하는 항목이 없습니다.' 라며 컴파일 오류가 납니다. 이럴 때는 다음과 같이 작성하면 됩니다. 쉽죠? :)

Text("나이 : \(person.age)세")

이름과 나이를 보기 좋게 VStack으로 나열하고 왼쪽 정렬(leading) 해주겠습니다.

            VStack(alignment:.leading) {
                Text("이름 : \(person.name)")
                Text("나이 : \(person.age)세")
                //String(format: "%.2f", ...)) = 소수점2자리부터 자른다.
                Text(String(format: "%.2f", person.height))
            }

String(format: "%.2f", person.height))

위에 코드를 사용하면 앞에 텍스트를 어떻게 넣는지 궁금한데, 그럴 때는 아래 코드처럼 작성해야 합니다.

//오류
Text("키 : String(format: "%.2f", person.height)cm")

//정상작동
Text("키 : \(String(format: "%.2f", person.height))cm")

자, 각 캐릭터 리스트를 클릭하면 상세정보를 볼 수 있도록 NavigationViewNavigationLink를 사용해보도록 하겠습니다.

    //1.네비게이션뷰 생성
      NavigationView {
            List(self.people, id: \.name) { person in
                //3.네비게이션링크 생성
                NavigationLink(destination: Text("Character Selected")) {
                    Characters(person: person)
                }
            }
            //2.네비게이션타이틀 생성
            .navigationBarTitle("지브리 스튜디오")
            .padding(.top, 20)
        }

NavigationLinkText에 "Character Selected"라고 설정해주면 내비게이션 링크로 Push 했을 때 "Character Selected"라는 화면을 볼 수 있습니다. 하지만 Text부분에 다음과 같이 코드를 적어주면 캐릭터에 맞는 정보를 표현할 수 있습니다.

                NavigationLink(destination: Text(person.name)) {
                    Characters(person: person)
                }

2. 내비게이션 링크 디테일뷰 생성

내비게이션 링크에 디테일한 뷰를 생성해 주기 위해 새로운 SwiftUI View를 생성 해고 뷰 네임은 CharacterDetail이라고 정해주겠습니다. 그리고 아래 코드와 같이 꾸며줍니다.

struct CharacterDetail: View {
    
    let person: Person
    
    var body: some View {
        VStack(alignment: .center) {
            Image(person.imageURL)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: 340, height: 340)
                .cornerRadius(30)
            
            VStack {
                HStack {
                    Image(systemName: "star.square.fill")
                        .font(.title)
                    Text("캐릭터 정보")
                        .fontWeight(.bold)
                        .font(.system(size: 30))
                        .padding(EdgeInsets(top: 20, leading: 0, bottom: 20, trailing: 0))
                }
                VStack(alignment: .leading) {
                    
                    Text("이름 : \(person.name)")
                    Text("나이 : \(person.age)세")
                    Text("키 : \(String(format: "%.1f", person.height))cm")
                    Text("몸무게 : \(String(format: "%.1f", person.weight))kg")
                    
                } .padding(.leading, 30)
                .font(.system(size: 23))
            }
        }
    }
}

캐릭터의 디테일뷰를 꾸며주었으니, ContentView에서 NavigationLink 부분을 CharaterDeatil 뷰로 연결시켜 주도록 하겠습니다.

//ContentView
        NavigationView {
            List(self.people, id: \.name) { person in
                NavigationLink(destination: CharacterDetail(person:person)) {
                    Characters(person: person)
                }
            }

3. 이미지에 애니메이션 효과 추가

디테일뷰 이미지에 제스처를 추가하여 택할 때마다 이미지 크기가 커지고 다시 탭 하면 작아지는 탭 제스처를 넣어주겠습니다.

 

 

struct CharacterDetail: View {
    
    let person: Person
    @State private var zoomed: Bool = false
    @State private var animationAmount = 0.0
    
    var body: some View {
        VStack(alignment: .center) {
                  ...
                  
                //zoomed가 true이면 170, false이면 10
                .cornerRadius(self.zoomed ? 170 : 10)
                //클릭시 주는 효과
                .onTapGesture {
                    withAnimation(.interpolatingSpring(stiffness: 100, damping: 50)) {  
                        self.zoomed.toggle()
                        self.animationAmount += 360
                    }
                }
                .rotation3DEffect(
                    .degrees(animationAmount),
                    axis: (x: 0.0, y: 1.0, z: 0.0))

4. 디테일뷰 내비게이션 이름 추가

navigationBarTitle을 사용할 때 person.name처럼 사용하려고 할 때는 반드시 Text 매개변수가 와야 합니다.

//CharaterDetail View
var body: some View {
        VStack(alignment: .center)  
        
        { ... }
        //네비게이션타이틀을 사용할때 (person.name)을 사용하려면 항상 text매개변수가 와야한다.
        .navigationBarTitle("지브리 스튜디오 '\(person.name)'")

만약 내비게이션 타이틀이 너무 커서 이것을 작은 사이즈로 바꾸고 싶다면 아래와 같이 수정해주면 됩니다.

//CharaterDetail View
var body: some View {
        VStack(alignment: .center)  
        
        { ... }
        //네비게이션타이틀을 사용할때 (person.name)을 사용하려면 항상 text매개변수가 와야한다.
        .navigationBarTitle("지브리 스튜디오 '\(person.name)'",displayMode: .inline)

최종 화면

읽어주셔서 감사합니다🤟

 

본 게시글의 전체 코드 GitHub 👇🏻

 

Seogun95/SwiftUI_Project1

SwiftUI에서 List를 사용하여 간단한 프로젝트를 만들어봅시다. Contribute to Seogun95/SwiftUI_Project1 development by creating an account on GitHub.

github.com

 

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.