[TIL/Swift] 기본 navigationbar 없이 dragGesture로 navigation back 구현

pendant.kpendant.k
2 min read

현재 진행 중인 프로젝트는 MV 패턴을 적용하고 (부분적으로 aggregate state를 활용하여 VM을 채용하기도 함)있는데, 네비게이션 스택을 전역 상태로 관리하는 상태임 .navigationBarBackButtonHidden(true) modifier를 활용해서 기본 네비게이션바를 감춰두고 커스텀 네비게이션 바를 만들어서 사용중

이때 기본으로 제공하던 left to right 스와이프 동작이 먹히지 않는 문제가 발생하게 됨. 이를 해결하기 위해 구글링을 해보며 다음의 솔루션들을 발견함

1. UINavigationController에 익스텐션 쌈@뽕하게 물리기

extension UINavigationController: UIGestureRecognizerDelegate {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }
}

이런식으로 적용해보니 동작이 아주 매끄럽게 잘됐음. 문제는 root view인 경우에 뒤로가기가 되고, 이때 빈 페이지가 뜨는 문제가 발생하게 됐음. (온전하게 네비게이션 스택 관리가 안됨) 다른 사람의 경우 appState 전역 객체에 일케절케해서 사용하는 것도 봤는데, 기능에 비해서 코드가 조금 난잡해지는 게 아닌가 하는 생각이 들었음.(아닌가?)

논쟁 중인 여러 댓글들을 참고하며 다른 답변을 조사한 결과 두번째 방법을 확인하게 됨

2. gesture()에다가 swipe 이벤트 핸들러 직접 만들어서 구현하기

사실 이전에도 커스텀 TabView를 만들면서 좌,우 swipe 이벤트 핸들러를 만들어본 적이 있어서 더 와닿는 방법이었음. 일단 임시적으로 해당 방법을 활용하여 swipe navigation back을 적용해둔 상태임

struct SecondView: View {
  @Environment(\.dismiss) var dismiss

  var body: some View{
    Text("제스처 테스트")
      .navigationBarTitle("")
      .navigationBarHidden(true)
      .gesture(
        DragGesture(minimumDistance: 20, coordinateSpace: .global)
          .onChanged { value in
            guard value.startLocation.x < 20, // 왼쪽 끝에서 시작
                  value.translation.width > 60 else { // 오른쪽으로 스와이프
            return
          }
        dismiss()
      }
    )
  }
}

사실 친근한 방법이라 따라하긴 했는데, 댓글을 파악해보니 현존하는 솔루션 중 (iOS18기준) 그나마 에러가 덜 발생하는 방법이라고 함. 접근성에 문제가 있긴 한 것 같음.

아마 다른 View 작업할 때도 틈틈히 하나하나 적용해야할 것 같으니 관련 글을 꾸준히 팔로업하는 게 좋을 것 같다.

참고자료
스택오버플로우 답변

0
Subscribe to my newsletter

Read articles from pendant.k directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

pendant.k
pendant.k

iOS / Flutter Developer