본문 바로가기

iOS/SwiftUI

SwiftUI 뷰의 변화 감지

오늘의 주제는 SwiftUI에서 뷰의 변화 감지를 할 수 있는 modifier에 대해 알아보겠습니다!

사실 이런 것들에 대해서 진짜 진짜 최근에 알게 되었는데 처음으로 본게 .onAppear 이거등여

근데 찾아보니까 저거랑 비슷한 역할을 하는 친구들이 몇개 더 있더라구요

아직 다 써본건 아니지만 자주 쓸거같아여 한번 정리해보려고 합니다!!~

여기서 소개하는 친구들은 뷰의 변화를 감지하고 대응하기 위한 modifier들입니다!

onChange(of:perform:) 에 대해서 알아보려고 했는데…

onChange(of:perform:) | Apple Developer Documentation

 

onChange(of:perform:) | Apple Developer Documentation

Adds an action to perform when the given value changes.

developer.apple.com

더 이상 사용하지 않는다고 하더라구요….? 저거 대신 요걸 사용한다고 합니다

onChange(of:initial:_:)

func onChange<V>(
    of value: V,
    initial: Bool = false,
    _ action: @escaping () -> Void
) -> some View where V : Equatable
  • 특정 값이 변경될 때 작업을 실행하는 친구입니다..

매개변수

value - 클로저 실행 여부를 결정할 때 확인할 값

initial - 이 보기가 처음 나타날 때 작업을 실행해야 하는지 여부

action - 값이 변경될 때 실행할 클로저

struct PlayerView: View {
    var episode: Episode
    @State private var playState: PlayState = .paused

    var body: some View {
        VStack {
            Text(episode.title)
            Text(episode.showTitle)
            PlayButton(playState: $playState)
        }
        .onChange(of: playState) {
            model.playStateDidChange(state: playState)
        }
    }
}

playState의 값이 변경될 때 클로저 안의 메소드를 실행하는 것 같습니다.

initial은 기본값으로 false이기 때문에 시작하자마자 실행되지 않구요!

그리고 value에 들어오는 값은 Equatable 프로토콜을 만족해야 합니다

→ 비교가 가능한 값이 들어와야 한다는 내용인 것 같습니다!

onAppear(perform:) , onDisappear(perform:)

func onAppear(perform action: (() -> Void)? = nil) -> some View
  • View가 표시되기 전에 호출되어 작업을 수행함.
func onDisappear(perform action: (() -> Void)? = nil) -> some View
  • View가 사라진 후 호출되어 작업 수행!

매개변수

action - 수행할 작업이 들어오며 nil 값이라면 아무 작업이 수행되지 않음

얘네들을 더 잘 이해하려면 SwiftUI의 View Life Cycle에 대해서 좀 학습을 해야할거 같음

라이프사이클에 대한 내용은 추가적인 공부를 하고 한번 작성해보도록 하겠승미다!

import SwiftUI

struct test: View {
    var body: some View {
        NavigationStack {
            NavigationLink {
                SecondView()
            } label: {
                Text("1번째 뷰")
            }
            .onAppear {
                print("1번째 뷰 onappear")
            }
            .onDisappear {
                print("1번째 뷰 disappear")
            }

        }
    }
}

struct SecondView: View {
    var body: some View {
        
        NavigationLink {
            ThirdView()
        } label: {
            Text("2번째 뷰")
        }
        .onAppear {
            print("2번째 뷰 onappear")
        }
        .onDisappear {
            print("2번째 뷰 disappear")
        }

        
    }
}

struct ThirdView: View {
    var body: some View {
        
        NavigationLink {
            //
        } label: {
            Text("3번째 뷰")
        }
        .onAppear {
            print("3번째 뷰 onappear")
        }
        .onDisappear {
            print("3번째 뷰 disappear")
        }
    }
}

struct test_Previews: PreviewProvider {
    static var previews: some View {
        test()
    }
}

/* 결과
1번째 뷰 onappear
2번째 뷰 onappear
1번째 뷰 disappear
3번째 뷰 onappear
2번째 뷰 disappear
3번째 뷰 disappear
3번째 뷰 onappear
2번째 뷰 onappear
3번째 뷰 disappear
1번째 뷰 onappear
2번째 뷰 disappear
*/

다음과 같이 NavigationLink를 타고 뷰가 변화함에 따라 onappear, disappear의 동작을 확인할 수 있습니다

 

onTapGesture(count:perform:)

func onTapGesture(
    count: Int = 1,
    perform action: @escaping () -> Void
) -> some View
  • TapGesture가 인식되었을 때 수행할 액션을 추가!
  • 대부분의 View에서느 쉽게 추가하여 사용이 가능

그럼 사실 Button의 역할이랑 비슷한데 차이점은 뭘까여?

onTapGesture는 버튼을 누를 때 동작하는 애니메이션과 같은 기본 효과들이나 커스텀 버튼 스타일 등은 사용할 수 없음!!

매개변수

count - 액션을 수행하는데 필요한 탭 또는 클릭의 수를 나타냄. 기본값은 1 입니다!

action - 수행할 액션을 나타냄

struct TapGestureExample: View {
    let colors: [Color] = [.gray, .red, .orange, .yellow,
                           .green, .blue, .purple, .pink]
    @State private var fgColor: Color = .gray

    var body: some View {
        Image(systemName: "heart.fill")
            .resizable()
            .frame(width: 200, height: 200)
            .foregroundColor(fgColor)
            .onTapGesture(count: 2) {
                fgColor = colors.randomElement()!
            }
    }
}

이미지를 두번 탭하게되면 color에 있는 요소 중 하나로 랜덤으로 색상이 변하게 됩니다.

onLongPressGesture(minimumDuration:maximumDistance:perform:onPressingChanged:)

func onLongPressGesture(
    minimumDuration: Double = 0.5,
    maximumDistance: CGFloat = 10,
    perform action: @escaping () -> Void,
    onPressingChanged: ((Bool) -> Void)? = nil
) -> some View
  • LongTapGesture가 인식되었을 때 수행할 액션을 추가!
  • TapGesture 와 차이점은 탭의 길이차이인거 같음

매개변수

minimumDuration - 제스처가 성공하기 전에 경과해야 하는 길게 누르기의 최소 시간

maximumDistance - 제스처가 실패하기 전 누르기를 수행하는 손가락이나 커서가 이동할 수 있는 최대 거리

action - 길게 누르기가 인식될 때 수행할 동작

onPressingChanged - 제스처의 누름 상태가 변경될 때 실행할 클로저로 현재 상태를 매개변수로 전달

action을 제외한 값들은 기본값이 설정되어 있기 때문에 필요한 상황이 아니라면 굳이.. 건들 필요는 없어 보이고 일반 탭과는 달리 길게 누를 경우 동작하고 싶은 액션을 추가해서 사용하면 될 것 같습니다!


여기까지 SwiftUI에서 사용되는 대표적인 뷰의 변화를 감지하는 방법을 알아보았습니다!!

롱탭 제스쳐 말고는 한번씩을 사용해봤던거 같은데… 사용법을 그렇게 어렵지는 않지만 이렇게 한번 정리하면서 찾아보니까 좋네여

(다음에 또 까먹어서 다시 찾아볼거 같긴 함)

이 외에도 더 있는데 그거는 필요할 때 찾아서 쓰면 될거 같구여

'iOS > SwiftUI' 카테고리의 다른 글

SwiftUI 내부 동작 원리  (0) 2023.12.11
SwiftUI Grid  (0) 2023.07.23
SwiftUi DataBinding  (0) 2023.06.26