[SwiftUI] Image 터치 눌렀다가 떼었을 때 변화주기(up, down event)
어떤 버튼을 꾸욱 눌렀을 때, 터치했을 때부터 손을 떼기까지 녹음하는 기능을 구현하고 싶었다. 그러나 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와도 같이 사용이 불가능하다... 방법을 찾아보고 있지만 내가 개발하고 있는 앱은 이런 클릭이벤트가 우선순위가 아니기 때문에 일단은 제쳐두었다...ㅎㅎㅎ