뒤로가기 버튼과 함께 제스쳐도 사라진 것에 대하여 in SwiftUI #90
thinkySide
started this conversation in
Idea
Replies: 1 comment 1 reply
-
|
뒤로가기 기능이 활성화되면 안될 때 생기는 문제가 더 치명적이라는 생각이 드는데 |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
안녕하세요, 3기 주니어 러너 한톨입니다! 😇
오늘은 제가 SwiftUI에서
Navigation기능을 구현할 때 자주 마주쳤었던문제 해결 과정을 간단하게 공유해 보려 합니다.
작은 내용이지만 누군가에게 도움이 되길 바람과 동시에,
더 좋은 해결 방법을 함께 고민해 봤으면 합니다!
SwiftUI의 NavigationBar 커스텀하기
SwiftUI는 기본적으로
Navigation기능을 제공합니다.NavigationStack계층 내부에NavigationLink를 넣거나,navigationDestination(for:destination:)modifier를 추가함으로써다음 화면에 대한 정의 및 기본
NavigationBar를 생성할 수 있습니다.사용하기 쉽고 모두에게 익숙한
NavigationBar가 자동으로 생성되었습니다.그와 함께 Back 버튼과 Swipe 제스처도 함께 구현되었네요.
SwiftUI가 제공하는 기본
NavigationBar는 기능상으로 큰 문제 없이 사용이 가능합니다.하지만 우리는, 다르게 사용해야 할 상황에 꽤나 자주 놓이곤 합니다.
UX/UI 디자인과 새로운 기능을 추가하는 등의 요구사항을 반영하려면,
Custom NavigationBar의 필요성을 자연스레 느끼게 되죠.저 또한
Custom NavigationBar의 필요성을 느끼게 되었고이를 프로젝트에 녹여내며 마주했던 문제를 예제 코드 + 실제 프로젝트와 함께 정리해 보겠습니다.
🙋🏻♂️ 문제 1. NavigationBar가 두개 생겼어요!
Custom NavigationBar를 구현하며 마주한첫 번째 문제를 아래 코드와 함께 살펴보겠습니다.
먼저 뒤로가기 버튼, 네비게이션 제목, 귀여운 이모지로 구성한
Custom NavigationBar예제 코드입니다.사용은 아래와 같이 가능합니다.
VStack을 사용해CustomNavigationBar를 최상단에 올려주었고,뒤로가기 액션을 실행하기 위해 closure 내부에서
dismiss환경 변수를 사용했습니다.눈치채셨겠지만 이렇게 작성하게 되면 NavigationBar가 두 개가 생겨버립니다.
NavigationBarCustomNavigationBar다행히도 SwiftUI는 이를 해결할 수 있게 modifier를 제공하고 있었습니다.
첫 번째 문제가 쉽게 해결되었습니다.
이제
CustomNavigationBar만 화면에 잘 출력되고 있네요!🙋🏻♀️ 문제 2. 뒤로가기 제스처가 안 먹혀요,,,
하지만 늘 그렇듯 문제는 여기서 끝나지 않았습니다.
UI 테스트 중 곧바로 부자연스러움을 느끼게 되었는데,
Navigation의 뒤로가기 제스처가 동작하지 않는 문제였습니다.
즉
navigationBarBackButtonHiddenmodifier는 NavigationBar와 함께,뒤로가기 제스처도 함께 비활성화하고 있었습니다.
iOS 사용자 입장에서 친숙한 뒤로가기 제스처가 동작하지 않는 것은
사용자 경험을 떨어트리기에 충분했고, 이는 꼭 해결해야 하는 문제라 판단했습니다.
그렇게 공식 문서와 인터넷을 떠돌다 찾게 된 해결 방법은 아래와 같았습니다. (from StackOverflow)
UIKit의
UINavigationController를 확장(extension)해 제스처를 활성화하는 코드입니다.위 코드 적용 시, 뒤로가기 제스처가 다시 돌아온 것을 확인할 수 있었습니다!
넘어가기 전, 위 코드의 동작 방식에 대해 명확히 이해하고 넘어가 보려 합니다.
UINavigationController확장(extension)내부에선UIKit의
UINavigationController를 관리하고 있습니다.UIGestureRecognizerDelegate프로토콜 채택@retroactive키워드의 의미 (번외!)경고를 띄워주는 역할을 수행합니다.
viewDidLoadLifeCycle override(재정의)UINavigationController가 메모리에 로드 될 때,즉 로드 후 즉시 초기 설정을 진행하기 위한 LifeCycle 메서드를 재정의합니다.
뒤로가기 제스처(PopGesture) 인식기 대리자 설정
interactivePopGestureRecognizer의 대리자(Delegate)를 설정합니다.gestureRecognizerShouldBegin(_:)Delegate 함수 구현UIGestureRecognizerDelegate프로토콜의 옵셔널 메서드입니다.Should키워드가 들어가게 되면 일반적으로Bool타입을 반환합니다.true를 반환하게 되면 뒤로가기 제스처가 활성화되고,false를 반환하게 되면 제스처가 비활성화됩니다.viewController개수에 따른 제스처 활성화 여부 결정true를 반환하더라도, 동일하게 뒤로가기 제스처가 활성화됩니다.하지만 뒤로가기 제스처가 유효한 상황은, 항상 RootView에서 특정 View로
Push된 상태여야 하기 때문에,viewController의 개수가 2개 이상이어야만 합니다.정확한 디버깅은 어렵지만, 뒤로 갈 수 없는 상태에서 제스처를 호출했을 때 문제가 발생하는 것으로 추측하고 있습니다.
🙋🏻 문제 3. 모든 View에서 뒤로가기 제스처가 필요한 건 아닌데요!
처음엔 모든
NavigationView에서 뒤로가기 제스처가 필요할 것으로 예상했습니다.하지만 예상과 다르게 특정 화면에선 뒤로가기 제스처가 필요하지 않았고,
어떤 화면에선 꼭 막아야 하는 상황도 생겨났습니다.
아카데미 러너라면 누구나 사용할 수 있는 익명 기반 커뮤니티 앱,
캐플 프로젝트를 진행하며
(기습 홍보)마주한 문제 상황은 아래와 같았습니다.다음버튼을 탭할 시, 회원가입 요청 API가 전송됩니다.시작하기버튼을 탭하고 메인 화면으로 진입하는 경우, 문제가 발생하지 않습니다.다음버튼을 탭 하면 중복 회원가입이 발생할 수 있습니다.X버튼을 탭할 시, 경고 알림 창을 통해 사용자에게 작업 내용이 소실될 수 있음을 인지시킵니다.즉, 기본적으로 NavigationView의 뒤로가기 제스처는 유지하되,
특정 View에서의 뒤로가기 제스처의 비활성 기능이 필요했습니다.
그렇게 여러 가지 방법을 시도 후 찾게 된 방법은 다음과 같습니다.
isAllowPopGesture를 선언합니다.gestureRecognizerShouldBeginDelegate 메서드에서 위 값을 사용(접근)하기 위해,Singleton객체를 생성합니다.gestureRecognizerShouldBeginDelegate 메서드 내에 뒤로가기 활성화 여부를 나타내는 조건을 추가합니다.viewController의 개수가 2개 이상일 때 뒤로가기 제스처가 가능해집니다.결과적으로, 특정 View에서 뒤로가기 제스처 비활성화에 성공했습니다!
하지만 걸리는 점이 있다면, 뒤로가기 제스처를 기본적으로 활성화할 View에서도
위
taskmodifer를 통해 매번 값을 업데이트 해주어야 한다는 것입니다.이는 개발자가 실수로 modifier 구현을 잊을 수 있다는 말이기도 합니다.
위와 같은 실수를 방지하기 위해선, 뒤로가기 제스처를 비활성화해야 하는 View에서만
사용하는 것이 바람직해 보였습니다.
해당 문제를 해결하기 위해 화면이 사라진 후 호출이 가능한
onDisappearmodifier를 사용해값을 다시 돌려놓음으로써 뒤로가기 제스처를 활성화시키는 코드를 추가했습니다.
마지막으로 일관성 및 재사용을 위해 ViewModifier 와 View 를 확장(extension) 해주었습니다.
📚 정리하기
SwiftUI는 선언형 프레임워크로
Naivgation등의 기본 기능을 쉽게 적용할 수 있습니다.하지만 기존 기능을 변경하고 싶거나 새로운 기능을 추가하고 싶을 때, UIKit을 이용해 명시적으로
여러 가지 설정을 해주어야 하는 상황에 자주 놓이게 되는 것 같습니다. (아직은 말이죠!)
더 어려운 문제를 해결하기 위해선, 두 가지 프레임워크에 대한
적정 수준의 이해도가 필요함을 다시 한번 느끼게 됩니다.
더 좋은 방법이 있거나, 개선할 수 있는 방향이 있다면 함께 논의하고 싶습니다! 감사합니다! 😃
Beta Was this translation helpful? Give feedback.
All reactions