iOS

[SwiftUI] Image 터치 눌렀다가 떼었을 때 변화주기(up, down event)

딩보 2024. 10. 25. 09:03

어떤 버튼을 꾸욱 눌렀을 때, 터치했을 때부터 손을 떼기까지 녹음하는 기능을 구현하고 싶었다. 그러나 SwiftUI up, down event를 구글링 해보았을 때, gesture를 활용한 터치 이벤트만 잔뜩 서치되었는데 이 친구로는 내가 원하는 기능을 구현할 수 없었다(있을 수도 있다, 내가 못 하는 것일 수도...).

처음엔 gesture를 활용해볼려고 이것저것 사용해보고 수정도 해봤지만 실패했고, 새로운 것을 찾아야 했다. 그렇게 찾은 것이 아래 본문에 작성될 것이다.

 

🔵  구현

UIView의 터치 이벤트를 overriding하면 간단하게 LongPressButton을 구현할 수 있다.

 

우선 아래처럼 custom View를 하나 만들어준다. 크게 수정할 것이 없다면 그냥 이대로 복붙해도 될 듯!

import SwiftUI

// Custom UIView 클래스
class CustomLongPressView: UIView {
    var onTouchBegan: (() -> Void)?
    var onTouchEnded: (() -> Void)?

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        onTouchBegan?() // 터치가 시작되었을 때 호출
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        onTouchEnded?() // 터치가 종료되었을 때 호출
    }
}

// UIViewRepresentable 구현
struct CustomLongPressViewRepresentable: UIViewRepresentable {
    typealias UIViewType = CustomLongPressView
    
    var onTouchBegan: () -> Void
    var onTouchEnded: () -> Void

    func makeUIView(context: Context) -> CustomLongPressView {
        let longPressView = CustomLongPressView()
        longPressView.onTouchBegan = onTouchBegan
        longPressView.onTouchEnded = onTouchEnded
        return longPressView
    }
}

 

 

 

 

위에서 만든 뷰를 사용하기 위해선 자신이 버튼을 넣고 싶은 자리에 이렇게 넣어주면 된다.

만약 버튼으로 이미지를 넣어주고 싶다면 background에 Color 대신 Image view를 넣어주면 된다.

struct TestView: View {
    @State private var color = Color.gray
    
    var body: some View {
        CustomLongPressViewRepresentable(
            onTouchBegan: {
                // 여기에 터치 시작 시 호출할 로직을 추가
                print("Touch began")
                color = Color.black
            },
            onTouchEnded: {
                // 여기에 터치 종료 시 호출할 로직을 추가
                print("Touch ended")
                color = Color.gray
            }
        )
        .frame(width: 100, height: 100) // 원하는 크기로 조정
        .background(color) // 배경 색상 설정
        //.background(Image("image_name").resizable().scaledToFit()) <- 이미지를 사용하고 싶은 경우
    }
}

 

 

 

🔵  동작 영상

이거 올릴 땐 크기 괜찮은데 올라간 건 왜 작아지지,,,

 

 

 

 

 

 

 

 

 

 

 

🔵  참고

https://devmjun.github.io/archive/UITouch_Event

 

Swift. 터치와 제스쳐를 알아보자

UItouch, Event, Gesture

devmjun.github.io

 


구버전

개발을 진행하던 중 아래 코드보다 훨씬 더 좋은 방법을 알아내서 이 아이는 버리기로 했다!

이 방식에는 문제가 많았다. 어떤 이미지를 꾹 누르는 동안 음성녹음을 하는 버튼을 만들려고 했는데 onChange가 버튼을 누르는 동안에 계속 실행이 되어 녹음되고 있던 부분이 리셋되었다. 그래서 새로운 방법을 찾아냄!

 

 

이미지를 누르고 있을 때 어두운 이미지로 바뀌고, 다시 손을 떼면 원래의 이미지로 돌아오는 클릭효과를 주고 싶었다.

이 간단한 걸 검색 키워드를 잘못 찾아 조금 헤매다가 찾아낸 결과!

import SwiftUI

struct ButtonTestView: View {
    @State private var isButtonPressed = false
    
    var body: some View {
        Image(
            isButtonPressed ? "image_pressed" : "default_image"
        )
        .resizable()
        .aspectRatio(contentMode: .fit)
        .frame(width: UIScreen.main.bounds.width / 3)
        .padding()
        .gesture(
            DragGesture(minimumDistance: 0)
            	// 버튼을 눌렀을 때
                .onChanged { _ in
                    isButtonPressed = true
                    print("Image Pressed")
                }
                // 버튼을 눌렀다가 뗐을 때
                .onEnded { _ in
                    isButtonPressed = false
                    print("Image Released")
                }
        )
    }
}

#Preview {
    ButtonTestView()
}
코드 동작본

 

 

😳 단점

버튼에는 해당 코드가 동작하지 않으며, navigationLink와도 같이 사용이 불가능하다... 방법을 찾아보고 있지만 내가 개발하고 있는 앱은 이런 클릭이벤트가 우선순위가 아니기 때문에 일단은 제쳐두었다...ㅎㅎㅎ