Navigation View{}
로 VStack
전체를 감싸준 다음, navigationTitle("Memorize!")
로 제목을 달아줬다. 앱 하단에 서로 다른 3가지 테마의 버튼을 만들고, 매번 버튼을 누를 때마다 카드가 셔플되어 나타나도록 구현하기
ThemeButton
구조체를 만들었다. 그러나 버튼을 누름에 따라 emojis
배열을 적절하게 교체해주어야 함에도 불구하고 구조체의 경우 ContenView
내부에 선언하던 외부에 선언하던 @State var emojis
에 접근할 수 없었다.computed property
로 각 버튼을 따로 선언해서 해결했다. 아마도 좀 더 재활용이 가능한 방법이 있을 것 같은데 앞으로 배워나가겠지 싶다. 카드 셔플 메서드
의 경우 구현이 어려울 것 같아 마지막까지 남겨뒀는데 과제 가이드에서 계속 셔플은 생각보다 매우 간단할 수도 있다고 계속 힌트를 줬다. 찾아보니 shuffled()
이라는 내장 함수가 있어서 이를 이용해서 각 버튼에서 emojis
를 해당 버튼의 테마와 일치하는 이모지 배열을 셔플한 것으로 교체해줬다. @State var emojis = [//array with emojis]
...
var vehicleButton: some View {
VStack {
Button {
emojis = vehicleEmojis.shuffled() // 배열 교체
emojiCount = Int.random(in: 4...emojis.count)
} label: {
VStack {
Image(systemName: "car.fill").font(.largeTitle)
Text("Vehicles").font(.footnote)
}
}
}
}
Int.random(in: )
메서드를 활용하면 된다고 해서 원래는 없었던 @State var emojiCount: Int
를 선언했다emojis 배열
의 길이가 최대 나타날 수 있는 카드 개수가 되고, 과제 가이드에서 항상 4개 이상의 카드가 나타나도록 하라고 되어있으므로 각 버튼 내에서 emojiCount
를 Int.random(in: 4..,emojisCount)
으로 업데이트하게 했다. @State var emojiCount = // some Int
...
var vehicleButton: some View {
VStack {
Button {
emojis = vehicleEmojis.shuffled()
emojiCount = Int.random(in: 4...emojis.count) // 랜덤 숫자로 교체
} label: {
VStack {
Image(systemName: "car.fill").font(.largeTitle)
Text("Vehicles").font(.footnote)
}
}
}
}
emojiCount
가 ForEach[emojis[0..<emojiCount]
에서 subscript range
로 활용되므로 4 ~ 최대 카드 개수 사이의 랜덤한 개수의 카드가 디스플레이 된다. ...
ForEach(emojis[0..<emojiCount], id: \.self) {
CardView(content: $0).aspectRatio(2/3, contentMode: .fit)
}
func widthThatBestFits(cardCount: Int) -> CGFloat {}
형태로 구현하라고 했다minimum
값을 바꿔가면서 테스트해봤더니 아래 switch 문
과 결과가 같았다 즉, 카드 개수가 4개일 때는 minimun
이 110 ~ 167 사이일 때 스크롤하지 않으면서 카드 크기가 최대이고, 카드 개수가 5 ~ 9개 일때는 minimum
이 80 ~ 109 사이일 때 최적이었다. 그래서 사실 이렇게 구현하는 게 맞는지 모르겠는데 그냥 임의로 최대 24개인 경우까지 해서 사실상 하드코딩하다시피 구현했다 func widthThatBestFits(cardCount: Int) -> CGFloat {
switch cardCount {
case 4:
return 110
case 5...9:
return 80
case 10...16:
return 63
default:
return 62
}
}
let bestWidth = widthThatBestFits(cardCount: emojiCount)
LazyVGrid(columns: [GridItem(.adaptive(minimum: bestWidth))])
combining views
를 적절히 활용할 수 있게 되었다. scope
에서 정의하는지, 그보다 상위 scope
에서 정의하면 안되는지 궁금했는데, 스스로 실험해본 결과 너무나 당연하지만 해당 변수/상수가 사용되는 가장 상위의 scope
에서 선언하는 게 실행 속도는 물론 깔끔한 코드 작성을 위해 베스트인 것 같다.