[SwiftUI] List에 필요한 Row UI 구성해보기

튜토리얼 페이지

Building Lists and Navigation

이전까지 랜드마크의 디테일한 정보를 담고 있는 DetailView를 만들었다면 이번에는 랜드마크 목록을 만들어 볼 차례다.

이번 튜토리얼을 마치고 나면 리스트로 나오는 랜드마크 목록에서 DetailView까지 진입할 수 있다. (포스팅은 여러번 나눠서 하는걸로..)

랜드마크 모델링

DetailView를 구성하는 이전 튜토리얼에서는 하드코딩으로 값을 하나하나 집어넣었지만, 표현해야 하는 랜드마크가 많아질수록 이런 방식으로 하는 건 비효율적이다. 그래서 이번 튜토리얼부터는 데이터를 관리하기 위해 Landmark Model 을 구성해서 사용한다.

landmarkData.json 파일 옮겨오기

튜토리얼 페이지에 있는 샘플 프로젝트에서 landmarkData.json 파일을 가져온다.

image

파일을 xcode 프로젝트로 끌어오면 위와 같은 화면이 나온다. 체크된 부분처럼 해서 가져온다.

image

엄청난 샘플 데이터가 들어있는 json 파일이었다…

새로운 Swift 파일 추가 (Landmark.swift)

  • 이번에는 랜드마크 모델 코드가 들어갈 Landmark.swift 파일을 생성한다. SwiftUI View가 아니라 Swift File 을 선택해야한다!
  • 생성한 파일 안에 json을 파싱해올 수 있도록 코드를 추가한다. (json 파일의 키값들로 프로퍼티를 추가)
    • Codable을 채택한 이유는 후에 json 파일로부터 데이터를 읽어오기 위함이므로 추후에 사용할 때 다시 들춰본다.
struct Landmark: Hashable, Codable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var description: String
}

샘플 이미지 가져오기 & 모델에 이미지 추가

TurtleRock 이미지를 가져왔을 때 처럼 샘플 프로젝트에서 이미지를 선택해 Assets 파일에 추가한다.

image

드래그 앤 드롭으로 가져오면 금방 가져올 수 있다.

Landmark 모델에 이미지도 함께 관리할 수 있도록 imageName과 image 프로퍼티를 추가했다.

image

SwiftUI를 import 해야 Image 클래스를 사용할 수 있으니 꼭 추가해줄 것. (imageName은 모델 내부에서만 사용하고 외부에서는 image만 사용하도록 imageName을 private으로 선언했다.)

coordinates 프로퍼티 추가하기

json 데이터를 확인해보면 아래와 같은 값들이 있다.

image

  • name, category, city, state, id, isFeatured, isFavorite, park, coordinates[longitude, latitude]

이 값들 중 coordinates는 형태가 다르다. 키 안에 값이 두개있는 상황..! 모델에서 불러올 때 coordinates는 새로운 struct로 구성한다.

coordinates는 private으로 선언하고 Mapkit에서 사용하기 좋도록 locationCoordinate 값을 공개한다. ( import CoreLocation 을 추가해야한다.)

    private var coordinates: Coordinates
    var locationCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(
            latitude: coordinates.latitude,
            longitude: coordinates.longitude)
     }

    struct Coordinates: Hashable, Codable {
        var latitude: Double
        var longitude: Double
    }

ModelData.swift 생성

json 파일로부터 데이터를 읽어와 Landmark 구조체 형식의 배열로 반환할 수 있도록 해주는 ModelData 파일을 생성한다.

image

파일 내부에는 json 데이터를 가져와 제네릭 타입으로 반환하는 load 메서드를 추가한다.

load 메서드는 반환 타입이 Codable protocol을 채택하는 형태로 반환되어야 한다. 그래서 Landmark 구조체가 Codable을 채택했던 것..!

이제 load 메서드 위에 landmark를 파싱한 결과물을 담을 landmarks: [Landmark] 를 만들어 load를 호출한다.

Row View 만들어보기

리스트에 들어가게 될 row 뷰를 구성해본다.

LandmarkRow.swift 파일 생성

이번에는 SwiftUI View 파일을 생성한다. row의 화면 구성을 위한 것이므로 LandmarkRow.swift 로 생성한다.

image

생성하면 계속 봐오던 Hello, World! 가 써있는 화면과 코드를 만날 수 있다. 이제 body위에 var landmark: Landmark 프로퍼티를 추가한다.

프로퍼티를 추가하고 나면 Preview 코드에서 에러가 난다.

image

프리뷰 코드 내부에서 LandmarkRow를 생성해서 사용하는데 우리가 방금 landmark 프로퍼티를 추가했으니 init에 landmark 내용이 들어가야 해서 생기는 에러다. landmark를 넣어주어 해결한다. (우선은 ModelData의 첫 요소를 넘겨주도록 한다.)

struct LandmarkRow_Previews: PreviewProvider {
    static var previews: some View {
        LandmarkRow(landmark: landmarks[0])
    }
}

HStack 추가

row의 UI는 보통 수평으로 컨텐츠가 놓이므로 HStack을 추가해준다.

image

  • landmark의 이미지와 이름을 순서대로 넣어준다. image의 크기는 resizable하도록 설정하고 크기는 50-50으로 설정해주었다.
  • 뒤쪽에 공간이 생기도록 Spacer()를 마지막에 넣어준다.

Customize the Row Preview

Row 프리뷰를 보면 화면 전체에 덩그러니 한줄있는 게 보인다. 이 부분은 customizing을 통해 row 사이즈로 보여지도록 수정이 가능하다.

image

.previewLayout(.fixed(width: 300, height: 70))

프리뷰 코드에서 previewLayout을 설정해주면 원하는 사이즈로 볼 수 있다. (fixed라고 써있는 걸 보니 컨테이너의 사이즈를 고정하는 용도로 보인다.)

Group을 사용해서 프리뷰에 여러개의 row를 볼 수도 있다.

image

하지만 이 코드는 프리뷰의 코드를 변경한 것이므로 실제로 실행할 때가 아니라 프리뷰 화면에서만 적용된다.

마무리

일단은 row를 구성해보았는데, 다음 포스팅에서는 list에 row들을 띄우는 작업을 하게 될 것 같다. tableView가 이렇게 쉽게 만들어지다니.. autolayout이 진짜 어려웠는데….

Leave a comment