Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - SwiftUI] SwiftUI Sample - Navigation App (About Me, TabView) 살펴보기 본문

iOS 튜토리얼 (SwiftUI)

[iOS - SwiftUI] SwiftUI Sample - Navigation App (About Me, TabView) 살펴보기

jake-kim 2024. 6. 12. 01:41

* SwiftUI Sample 앱 살펴보기 전체 목차는 여기 참고

TabView 개념

  • SwiftUI에서의 TabView는 선언적으로 매우 직관적으로 사용이 가능
    • Text 밑에 TabView를 표현하고 싶은 경우?
    • 아래 코드에 TabView 블록을 추가
struct ContentView: View {
  var body: some View {
    Text("Hello, world!")
      .padding()
  }
}

(TabView 추가)

struct ContentView: View {
  var body: some View {
    Text("Hello, world!")
      .padding()
    TabView { // <-
    }
  }
}
  • 이제 화면 A, B, C 뷰를 넣고 싶은 경우, 차례로 연달아서 넣기
struct ContentView: View {
  var body: some View {
    Text("Hello, world!")
      .padding()
    TabView {
      ViewA()
      ViewB()
      ViewC()
    }
  }
}
  • 여기서 Tab의 UI에는 icon과 title로 구성되므로 이 값을 넣어주려면 .tabItem {  }을 사용하여 넣어쥐

tab에는 tabItem안에 있는 icon과 title로 구성

struct ContentView: View {
  var body: some View {
    Text("Hello, world!")
      .padding()
    TabView {
      ViewA()
        .tabItem {
          Label("View1", systemImage: "tray.and.arrow.down.fill")
        }
      ViewB()
        .tabItem {
          Label("View2", systemImage: "tray.and.arrow.up.fill")
        }
      ViewC()
        .tabItem {
          Label("View3", systemImage: "person.crop.circle.fill")
        }
    }
  }
}
  • tab에는 우측 상단에 빨간색 알림 UI도 있는데 이것은 그냥 뷰에다가 .badge(2)를 사용하면 가능
    • 느낌표와 같은 문자를 입력해도 가능

struct ContentView: View {
  var body: some View {
    Text("Hello, world!")
      .padding()
    TabView {
      ViewA()
        .badge(2) // <-
        .tabItem {
          Label("View1", systemImage: "tray.and.arrow.down.fill")
        }
      ViewB()
        .tabItem {
          Label("View2", systemImage: "tray.and.arrow.up.fill")
        }
      ViewC()
        .badge("!") // <-
        .tabItem {
          Label("View3", systemImage: "person.crop.circle.fill")
        }
    }
  }
}

About Me 프로젝트

  • 첫 실행부인 @main인 AboutMeApp 구조체 확인
    • ContentView가 WindowGroup으로 감싸여진 상태
    • WindowGroup 이란?
      • Window라는 개념은 뷰들의 컨테이너 역할을 하면서 동시에 터치 이벤트와 같은 이벤트를 가장 먼저 수신하여 subview들에게 이벤트를 전달하는(responder chain) 기능
      • macOS와 iPadOS와 같이 그룹으로부터 여러개의 window를 띄울 수 있는 형태일때 WindowGroup을 여러개 정의하여 사용
@main
struct AboutMeApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
  • ContentView를 보면 TabView형태인 것을 확인 가능
struct ContentView: View {
    var body: some View {
        TabView {
            HomeView()
                .tabItem {
                    Label("Home", systemImage: "person")
                }

            StoryView()
                .tabItem {
                    Label("Story", systemImage: "book")
                }
            
            FavoritesView()
                .tabItem {
                    Label("Favorites", systemImage: "star")
                }
            
            FunFactsView()
                .tabItem {
                    Label("Fun Facts", systemImage: "hand.thumbsup")
                }
        }
        
    }
}

Text, Image, padding

  • 탭 화면 중 HomeView의 UI
    • 상단의 Text, 중앙에 Image, 하단의 Text

struct HomeView: View {
    
    var body: some View {
        VStack {
            Text("All About")
            Image(information.image)
            Text(information.name)
        }
    }
    
}
  • 상단의 Text는 폰트가 크고 bold체인 형태이므로 속성 추가
Text("All About")
    .font(.largeTitle)
    .fontWeight(.bold)
  • 하단의 텍스트도 font를 입력해주고 추가
Text(information.name)
    .font(.title)
  • 중앙의 이미지에도 cornerRadius를 적용하여 추가
Image(information.image)
    .cornerRadius(10)

결과) 

  • 현재 이미지의 contentMode는 scallToFill형태가 되어 공간에 맞게 이미지가 늘어나서 비율이 맞지 않은 상태
    • 공간에 맞게 이미지를 resize해야하고, contentMode를 fit으로하여 너비에 이미지 크기를 맞추도록 설정

  • 여기서 Image와 위, 아래의 Text, 좌우 패딩을 주고 싶을땐 padding()사용
Image(information.image)
    .resizable()
    .aspectRatio(contentMode: .fit)
    .cornerRadius(10)
    .padding(40) // <-

  • padding 인터페이스 확인해보면 edges, length가 있고 length만 입력하면 상하좌우 방향으로 패딩이 적용되는 것
@inlinable public func padding(_ edges: Edge.Set = .all, _ length: CGFloat? = nil) -> some View
@inlinable public func padding(_ length: CGFloat) -> some View
  • 아무것도 파라미터로 넘기지 않는 padding()을 사용하면, 아래 설명과 같이 플랫폼에 따라 알맞게 시스템에서 계산해서 padding을 넣어줌
/// You can omit either or both of the parameters. If you omit the `length`,
/// SwiftUI uses a default amount of padding. If you
/// omit the `edges`, SwiftUI applies the padding to all edges. Omit both
/// to add a default padding all the way around a view. SwiftUI chooses a
/// default amount of padding that's appropriate for the platform and
/// the presentation context.

ScrollView

  • 두번째 탭 My Story를 보면 스크롤이 있는 UI

  • StoryView를 보면 ScrollView로 Text를 단순히 감싼 형태
struct StoryView: View {
    var body: some View {
        VStack {
            Text("My Story")
                .font(.largeTitle)
                .fontWeight(.bold)
                .padding()
            
            ScrollView { // <-
                Text(information.story)
                    .font(.body)
                    .padding()
            }
        }
        .padding([.top, .bottom], 50)
    }
}

ForEach, HStack

  • 3번째 탭인 FavoritesView를 보면 수평으로 나열된 UI가 존재

  • 이렇게 나열된 형태의 UI는 HStack으로 ForEach를 감싸면 구현이 가능
HStack {
    ForEach(information.hobbies, id: \.self) { hobby in
        Image(systemName: hobby)
            .resizable()
            .frame(maxWidth: 80, maxHeight: 60)
        
    }
    .padding()
}
.padding()
  • 만약 아이템의 개수가 3개가 아닌 4개인 경우는 알아서 줄어드는 UI로 변화

  • (4번째 탭은 특별한 UI는 없으므로 스킵)

* 이 밖의 SwiftUI Sample 앱 살펴보기 전체 목차는 여기 참고

 

* 참고

- https://developer.apple.com/tutorials/sample-apps/aboutme

Comments