관리 메뉴

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

[iOS - SwiftUI] 튜토리얼 - 19. iOS앱 프로젝트에 macOS 맥북 앱 UI 구현 방법, 다양한 플랫폼 UI 구현 방법 (3) 본문

iOS 튜토리얼 (SwiftUI)

[iOS - SwiftUI] 튜토리얼 - 19. iOS앱 프로젝트에 macOS 맥북 앱 UI 구현 방법, 다양한 플랫폼 UI 구현 방법 (3)

jake-kim 2022. 7. 22. 23:04

* 프로젝트 파일은 애플 튜토리얼 사이트나 이전 포스팅 글 참고

macOS UI 구현

  • LandmarkList.swift 
    • .frame(minWidth)값을 주어서 뷰의 크기를 크게 설정
    • (단, 다양한 플랫폼을 제공하려면 watchOS에서 minWidth를 사용하면 화면이 이상하게 될것이므로 이것은 아래에서 수정 예정)
수정 전 수정 후
struct LandmarkList: View {
  @EnvironmentObject var modelData: ModelData
  @State private var showFavoritesOnly = false
  
  var filteredLandmarks: [Landmark] {
    modelData.landmarks.filter { landmark in
      (!showFavoritesOnly || landmark.isFavorite)
    }
  }
  
  var body: some View {
    NavigationView {
      List {
        Toggle(isOn: $showFavoritesOnly) {
          Text("Favorites only")
        }
        
        ForEach(filteredLandmarks) { landmark in
          NavigationLink {
            LandmarkDetail(landmark: landmark)
          } label: {
            LandmarkRow(landmark: landmark)
          }
        }
      }
      .navigationTitle("Landmarks")
      .frame(minWidth: 300) // <-
    }
  }
}
  • 현재는 row에 title만 있지만, description도 추가
    • VStack을 추가하고, description을 적용할 Text 추가
수정 전 수정 후
struct LandmarkRow: View {
  var landmark: Landmark
  
  var body: some View {
    HStack {
      landmark.image
        .resizable()
        .frame(width: 50, height: 50)
        .cornerRadius(5)
      
      VStack(alignment: .leading) { // <-
        Text(landmark.name)
          .bold()
        
        Text(landmark.park) // <-
          .font(.caption)
          .foregroundColor(.secondary)
      }
      
      Spacer()
      
      if landmark.isFavorite {
        Image(systemName: "star.fill")
          .foregroundColor(.yellow)
      }
    }
  }
}
  • Row에 여백 주기
    • row에 .padding(.vertical, 4) 사용
수정 전 수정 후
 
  var body: some View {
    HStack {
      landmark.image
        .resizable()
        .frame(width: 50, height: 50)
        .cornerRadius(5)
      
      VStack(alignment: .leading) {
        Text(landmark.name)
          .bold()
        
        Text(landmark.park)
          .font(.caption)
          .foregroundColor(.secondary)
      }
      
      Spacer()
      
      if landmark.isFavorite {
        Image(systemName: "star.fill")
          .foregroundColor(.yellow)
      }
    }
    .padding(.vertical, 4) // <-
  }

플랫폼 고려하며 UI 구현하기

  • 가장 작은 화면인 watchOS먼저 체크
    • WatchLandmarks Extension하위에 ContentView 선택

  • Scheme도 watchOS로 변경

  • Preview 확인
    • 위에서 설정한 LandmarkRow의 frame(minWidth:)설정이 부적절하여, 화면이 잘리는 현상이 발생

  • WatchLandmarks Extension 타겟으로 하는 LandmarkList파일을 생성

  • iOS 쪽에서 Watch 타겟을 추가했던 부분 해제

  • iOS에서 구현되었던 LandmarkList.swift 내용을 복붙하고 frame(minWidth:) 부분을 삭제
수정 전 수정 후

struct LandmarkList: View {
  @EnvironmentObject var modelData: ModelData
  @State private var showFavoritesOnly = false
  
  var filteredLandmarks: [Landmark] {
    modelData.landmarks.filter { landmark in
      (!showFavoritesOnly || landmark.isFavorite)
    }
  }
  
  var body: some View {
    NavigationView {
      List {
        Toggle(isOn: $showFavoritesOnly) {
          Text("Favorites only")
        }
        
        ForEach(filteredLandmarks) { landmark in
          NavigationLink {
            LandmarkDetail(landmark: landmark)
          } label: {
            LandmarkRow(landmark: landmark)
          }
        }
      }
      .navigationTitle("Landmarks")
//      .frame(minWidth: 300) // <-
    }
  }
}
  • 조건부 컴파일을 통해 watchOS에서는 description이 안보이게 하기
    • 조건부 컴파일은 런타임에 적용되기 때문에, preview로는 확인이 불가능하여 시뮬레이터를 실행하여 확인
수정 전 수정 후
  • iOS 타겟 쪽에 있는 LandmarkRow 파일 수정
struct LandmarkRow: View {
  var landmark: Landmark
  
  var body: some View {
    HStack {
      landmark.image
        .resizable()
        .frame(width: 50, height: 50)
        .cornerRadius(5)
      
      VStack(alignment: .leading) {
        Text(landmark.name)
          .bold()
        
        #if !os(watchOS) // <-
        Text(landmark.park)
          .font(.caption)
          .foregroundColor(.secondary)
        #endif
      }
      
      Spacer()
      
      if landmark.isFavorite {
        Image(systemName: "star.fill")
          .foregroundColor(.yellow)
      }
    }
    .padding(.vertical, 4)
  }
}

* macOS 나머지 UI 구현 방법 이어서, 다음 포스팅 글 참고

* 참고

https://developer.apple.com/tutorials/swiftui/creating-a-macos-app

Comments