SWIFTUI/Grammar

SwiftUI : #3 Understanding @Binding

서근 2021. 2. 12. 05:52
반응형

Binding에 관한 첫번째 게시글을 보시려면 여기를 클릭해주세요.

Binding에 관한 두번째 게시글을 보시려면 여기를 클릭해주세요.

 

Understanding @Binding

저희는 이전 게시물에서 Binding이 정확히 무엇인지 배워봤습니다. 이제 바인딩에 대해 다시 살펴보고 바인딩을 사용하여 애플리케이션을 만드는 방법을 살펴보도록 하겠습니다.

 

첫번째로 할것은 음악 트랙에 따라 달라지는 UI를 만들어 보겠습니다.

 

Xcode 프로젝트명을 'SwiftUI_Binding_music'으로 생성하고 새로운 그룹을 만들어서 모델 안에 새로운 Swift 파일을 만듭니다.

//Episode.swift

import Foundation

struct Epicode {
    let song: String
    let singer: String
    let track: String
}

Episode 스트럭트를 만들었으면, 이제 ContentView에 표시되도록 코드를 추가해주겠습니다.

struct ContentView: View {
    
    let epicode = Epicode(song: "Dynamite", singer: "BTS", track: "DayTime Version")
    
    var body: some View {
        
        VStack {
            Text(self.epicode.song)
                .font(.title)
            
            Text(self.epicode.track)
                .font(.footnote)
                .foregroundColor(.secondary)
            
            Text(self.epicode.singer)
                .foregroundColor(.secondary)
            
        }      
    }
}

다음 단계는 버튼을 만드는 것입니다. 버튼을 눌렀을때 어떠한 액션을 취할 수 있도록 해주겠습니다.

 

일단 버튼을 만들기위해 ContentView 내부에 PlayButton 이라는 struct를 만들고 그안에 버튼을 추가해주고 ContentView에 추가 까지 해주도록 하겠습니다.

struct ContentView: View {  
    let epicode = Epicode(song: "Dynamite", singer: "BTS", track: "DayTime Version")  
    var body: some View {
        
        VStack {
               ...
               
            PlayButton()         
            
        }
        
    }
}

struct PlayButton: View {    
    var body: some View {
        
        Button(action: {}) {
            Image(systemName: "play.fill")
            .font(.system(size: 30))
        }.padding(15)
    }
}

이제 Play 버튼을 눌렀을때, 재생중이라면 제목 부분의 색이 '파란색' 재생중이 아니라면 '검은색' 으로 나타나게 해주겠습니다. 여기서는 @State와 삼항연산자를 사용해야 합니다.

let epicode = Epicode(song: "Dynamite", singer: "BTS", track: "DayTime Version")
    
    @State private var isPlaying = false
    
    var body: some View {
        
        VStack {
            Text(self.epicode.song)
                .font(.title)
              //isPlaying이 true이면 블루, false이면 블랙 (기본값은 false로 정해놨음)
                .foregroundColor(self.isPlaying ? .blue : .black)
           
           ...
            
        }

하지만 버튼을 눌러봐도 아무런 반응을 보이지 않습니다. 그렇다면 PlayButton쪽에도 똑같이 isPlaying 타입을 넣어줘야할까요?

 

안됩니다. 지금 이 View에서 ContentViewPlayButton은 완전히 다른것이라고 생각하면 됩니다.

 

그렇다면 어떻게해야 ButtonisPlaying을 넣어줄 수 있을까요? 이때 써야 하는것이 바로 'Binding'입니다.

 

PlayButton 스트럭트에  @Binding var isPlaying: Bool 을 추가해주고, 버튼 액션쪽에도 코드를 작성합니다.

struct PlayButton: View {
    
    @Binding var isPlaying: Bool
    
    var body: some View {
        
        Button(action: {
            //isPlaying이 토글된다.
            self.isPlaying.toggle()
        }) {
            Image(systemName: "play.fill")
                .font(.system(size: 30))
                .foregroundColor(self.isPlaying ? .blue : .black)
        }.padding(15)
    }
}

하나 더 해줘야 할것은 ContentView에 실행시켜줬던 PlayButton() 입니다. 지금 보면 에러가 나있죠? 이유는 아직 바인딩 시켜주지 않았기 때문입니다. #2 에서 공부한것처럼 바인딩을 해줄때는 달러($)부호를 사용해야 합니다.

PlayButton(isPlaying: $isPlaying)

⭐️바인딩값으로 가져와서 사용하려면 기본 생성자를 설정해주는것이 중요합니다.
@Binding으로 가져왔다면, 그밑에 init으로 바인딩값을 추가해줘야 하는것이죠.
//예시 

@Binding var isActivated: Bool

//생성자
                              //true값 또는 false값을 기본설정해줌
init(isActivated: Binding<Bool> = .constant(true)) {
        _isActivated = isActivated
}

전체 코드

<hide/>

import SwiftUI

struct ContentView: View {
    
    let epicode = Epicode(song: "Dynamite", singer: "BTS", track: "DayTime Version")
    @State private var isPlaying = false
    
    var body: some View {

            VStack {
                Text(self.epicode.song)
                    .font(.title)
                    .foregroundColor(self.isPlaying ? .blue : .black)
                
                Text(self.epicode.track)
                    .font(.footnote)
                    .foregroundColor(.secondary)
                
                Text(self.epicode.singer)
                    .foregroundColor(.secondary)
                
                //isPlaying을 바인딩해서 가져옴
                PlayButton(isPlaying: $isPlaying)
                
            }
        }
        
    }

struct PlayButton: View {
    
    @Binding var isPlaying: Bool
    
    var body: some View {
        
        Button(action: {
            //isPlaying이 토글된다.
            self.isPlaying.toggle()
        }) {
            Image(systemName: "play.fill")
                .font(.system(size: 30))
                .foregroundColor(self.isPlaying ? .blue : .black)
        }.padding(15)
    }
}

 

읽어주셔서 감사합니다🤟