Dynamic List
이번에는 List
를 사용하여 Dynamic List View
를 만들어 보도록 하겠습니다.
위처럼 포켓몬의 이름에 따른 타입과 그에 맞는 컬러를 매치시키시고 오른쪽 상단에 있는 navigationBarItems
을 누를 때마다 랜덤 하게 포켓몬의 이름이 생성되도록 하는 것이 목표입니다.
우선 간단하게 아래와 같이 작성해보도록 하겠습니다. 우선 pokemon
의 모델을 struct
로 하나 만들어 주겠습니다.
struct pokemonModel {
let name: String
let type: String
let color: Color
let imagename: String
}
그리고 @State
변수로 name
과 type
그리고 color
를 배열시켜 주도록 합니다.
struct Pokemon: View {
@State var pokemonList = [
pokemonModel(name: "피카츄", type: "전기 포켓몬", color: .yellow, imagename: "bolt.fill"),
pokemonModel(name: "파이리", type: "불 포켓몬", color: .red, imagename: "flame.fill"),
pokemonModel(name: "이상해씨", type: "풀 포켓몬", color: .green, imagename: "leaf.fill"),
pokemonModel(name: "꼬북이", type: "물 포켓몬", color: .blue, imagename: "tortoise.fill")
]
var body: some View {
}
}
이제 pokemonList
를 body
안에서 호출해주려면 List
를 사용해야 합니다.
var body: some View {
List(pokemonList, id: \.name) { pokemon in
HStack {
Image(systemName: pokemon.imagename)
.frame(width: 30)
.foregroundColor(pokemon.color)
.padding(.trailing, 10)
Text(pokemon.name)
Spacer()
Text(pokemon.type).foregroundColor(pokemon.color)
}
}
}
이렇게 화면을 구성했습니다.
Identifiable
우리는PokemonModel
에 직접 identifiable
프로토콜을 사용하지 않고 List
에서 id: \.name
으로 이름을 통해 식별되게 했으며 각각은 고유 식별자를 가지게 됐습니다. 하지만 한 가지 큰 문제가 있습니다. 만약 pokemonList
에서 "파이리"를 "피카츄"로 바꾸면 어떻게 될까요?
Xcode는 이렇게 인식합니다.
"그래, 피카츄는 전기 타입이야!"
하지만 우리는 두 번째 항목에서 피카추는 불 타입이라고 정해줬었죠. SwiftUI
에서 자동으로 피카추를 전기 타입으로 입력한 이유는 우리가 id
를 name
식별자로 넣어줬기 때문입니다. 이것을 방지하려면 identifiable
과 함께 id
변수를 추가해줘야 합니다.
struct pokemonModel: Identifiable {
let id: Int
let name: String
let type: String
let color: Color
let imagename: String
}
그리고 pokemonList
부분도 수정해줘야 합니다.
struct Pokemon: View {
@State var pokemonList = [
pokemonModel(id: 0, name: "피카츄", type: "전기 포켓몬", color: .yellow, imagename: "bolt.fill"),
pokemonModel(id: 1, name: "피카츄", type: "불 포켓몬", color: .red, imagename: "flame.fill"),
pokemonModel(id: 2, name: "이상해씨", type: "풀 포켓몬", color: .green, imagename: "leaf.fill"),
pokemonModel(id: 3, name: "꼬북이", type: "물 포켓몬", color: .blue, imagename: "tortoise.fill")
]
이렇게 각각에 고유한 id
가 생성되었고, List
의 id: \.name
을 지워주고 프리뷰를 실행 주겠습니다. 프리뷰를 실행해보면 아래와 같이 피카추는 불 포켓몬이라고 나오게 됩니다.
NavigationView 및 Button 추가
List
를 NavigationView
로 감싸고 NavigationBarItems
을 사용하여 버튼을 클릭하면 랜덤으로 포켓몬 리스트가 추가되도록 구현해보겠습니다.
var body: some View {
NavigationView {
List(pokemonList) { pokemon in
HStack {
Image(systemName: pokemon.imagename)
.frame(width: 30)
.foregroundColor(pokemon.color)
.padding(.trailing, 10)
Text(pokemon.name)
Spacer()
Text(pokemon.type).foregroundColor(pokemon.color)
}
}
.navigationBarTitle("포켓몬")
.navigationBarItems(trailing:
Button("추가") {
//some action
}
)
}
}
이렇게 NavigationView
/ NavigationBarTitle
/ NavigationBarItems
까지 성공적으로 구현했습니다. 하지만 한 가지 걸리는 것이 있습니다. 아래 이미지를 보면 NavigationBarItems
을 사용한 것과 NavigationBarItems
주석처리 한 화면이 다른 것을 확인할 수 있습니다.
이것을 방지하려면 listStyle
을 PlainListStyle
로 설정해주면 됩니다. .listStyle(PlainListStyle())
var body: some View {
NavigationView {
List(pokemonList) { pokemon in
...
}
.listStyle(PlainListStyle())
.navigationBarTitle("포켓몬")
.navigationBarItems(trailing:
Button("추가") {
//some action
}
)
}
}
Button Action 추가
이제 버튼에 action
을 만들어 주겠습니다. func
에 addPokemon()
이라고 함수를 만들고 lf let
을 사용하여 랜덤으로 아이템이 추가되도록 하겠습니다.
func addPokemon() {
if let randomPokemon = pokemonList.randomElement() {
pokemonList.append(randomPokemon)
}
}
그리고 버튼의 action
에서 함수를 호출해줍니다.
Button("추가") {
addPokemon()
}
한 가지 문제가 있습니다. 저희는 model
에 id
부여해줬는데 저런 식으로 추가를 해주면 오류가 생기게 됩니다. 그렇기 때문에 리스트가 추가될 때마다 새로운 Id
를 부여해주도록 해줘야 합니다.
if let
-> if var
로 바꿔주고 model
쪽은 let id: Int
-> var id: Int
func addPokemon() {
if var randomPokemon = pokemonList.randomElement() {
let newid = pokemonList.count
randomPokemon.id = newid
pokemonList.append(randomPokemon)
}
}
전체 코드
import SwiftUI
struct pokemonModel: Identifiable {
var id: Int
let name: String
let type: String
let color: Color
let imagename: String
}
struct Pokemon: View {
@State var pokemonList = [
pokemonModel(id: 0, name: "피카츄", type: "전기 포켓몬", color: .yellow, imagename: "bolt.fill"),
pokemonModel(id: 1, name: "피카츄", type: "불 포켓몬", color: .red, imagename: "flame.fill"),
pokemonModel(id: 2, name: "이상해씨", type: "풀 포켓몬", color: .green, imagename: "leaf.fill"),
pokemonModel(id: 3, name: "꼬북이", type: "물 포켓몬", color: .blue, imagename: "tortoise.fill")
]
var body: some View {
NavigationView {
List(pokemonList) { pokemon in
HStack {
Image(systemName: pokemon.imagename)
.frame(width: 30)
.foregroundColor(pokemon.color)
.padding(.trailing, 10)
Text(pokemon.name)
Spacer()
Text(pokemon.type).foregroundColor(pokemon.color)
}
}
.listStyle(PlainListStyle())
.navigationBarTitle("포켓몬")
.navigationBarItems(trailing:
Button("추가") {
addPokemon()
}
)
}
}
func addPokemon() {
if var randomPokemon = pokemonList.randomElement() {
let newid = pokemonList.count
randomPokemon.id = newid
pokemonList.append(randomPokemon)
}
}
}
struct Pokemon_Previews: PreviewProvider {
static var previews: some View {
Pokemon()
}
}
읽어주셔서 감사합니다🤟
본 게시글의 전체 코드 GitHub 👇🏻
'SWIFTUI > Controls' 카테고리의 다른 글
SwiftUI : TextField (hideKeyboard 코드) (0) | 2021.05.12 |
---|---|
SwiftUI : Text (0) | 2021.04.29 |
SwiftUI : Toggle Switch (toggleStyle) (0) | 2021.03.18 |
SwiftUI : Alert (알림 메세지) (0) | 2021.01.23 |
SwiftUI : EditButton [onDelete, OnMove] (1) | 2021.01.23 |