Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigation 뒤로가기 시, LoginDialog가 바로 사라지지 않는 문제 #178

Open
withseon opened this issue Apr 22, 2024 · 2 comments · Fixed by #179
Open

Navigation 뒤로가기 시, LoginDialog가 바로 사라지지 않는 문제 #178

withseon opened this issue Apr 22, 2024 · 2 comments · Fixed by #179
Assignees
Labels
🐯 인선 디자인 화면을 그리는 UI 작업 수정 코드 리팩토링 수행

Comments

@withseon
Copy link
Contributor

withseon commented Apr 22, 2024

비그로인 중, 로그인 다이얼로그가 나타나는 상황

  1. 메인 뷰에서 인기 술상의 PostListCell을 눌렀을 때
  2. 술장 뷰에서 DrinkGridCell과 DrinkListCell의 하트(좋아요)를 눌렀을 때
  3. 술 디테일 뷰에서 하트(좋아요)를 눌렀을 때
  4. 술 디테일 뷰에서 태그된 인기 술상의 PostListCell을 눌렀을 때
  5. 술상 뷰에서 PostCell을 눌렀을 때
  6. (술 디테일 뷰에서 '태그된 게시물'을 누르거나 검색 결과를 통해 이동한) NavigationPostsView에서 하트(좋아요)를 눌렀을 때
  7. (술 디테일 뷰에서 '태그된 게시물'을 누르거나 검색 결과를 통해 이동한) NavigationPostsView에서 PostCell을 눌렀을 때



현재 구현한 코드의 내용

특정 상황에서 로그인 다이얼로그를 띄우기 위해 AuthViewModel에 isShowLoginDialog 프로퍼티를 생성
앞서 언급한 뷰의 특정한 상황이 발생되었을 때, AuthViewModel의 signInStatus의 값을 판별하여 그에 따라 isShowLoginDialog의 값을 변경해줌

각각의 뷰에서는 isShowLoginDialog의 값에 따라 CustomDialog를 띄워줌

CustomDialog 내 오른쪽 버튼에 navigationLink를 사용하는 코드를 추가

    // MARK: - 버튼 두개 + navigationLink (왼쪽 버튼 gray01, 오른쪽 버튼 mainAccent03)
    @ViewBuilder
    private func buildNavigationDialog(message: String,
                                      leftButtonLabel: String, leftButtonAction: @escaping () -> Void,
                                       rightButtonLabel: String, navigationLinkValue: Route) -> some View {
        Group {
            // 메세지 텍스트
            Text(message)
                .font(.medium16)
                .multilineTextAlignment(.center)
                .lineSpacing(10)
            //
            CustomDivider()
            HStack(spacing: 0) {
                // 왼쪽 버튼
                Button {
                    leftButtonAction()
                } label: {
                    Text(leftButtonLabel)
                        .font(.medium16)
                        .foregroundColor(.gray01)
                }
                .frame(width: 115)
                // 오른쪽 버튼
                NavigationLink(value: navigationLinkValue) {
                    Text(rightButtonLabel)
                        .font(.medium16)
                        .foregroundColor(.mainAccent03)
                        .frame(width: 115)
                }
            }
            .padding(.horizontal, 20)
        }
    }
  • 처음에는 NavigationLink의 label에 Button을 사용하여 isShowLoginDialog의 값을 false로 바꾸어주는 action을 주었으나, 이런 경우에는 버튼의 영역을 클릭하였을 때, 버튼의 액션이 우선적으로 이루어져서 NavigationLink가 동작하기 전에 다이얼로그가 닫혀버림
  • NavigationLink의 label을 Text로 바꾸고, 로그인 다이얼로그를 사용하는 뷰에서 CustomDialog의 Disappear 시, isShowLoginDialog의 값을 false로 변경해줌



여기서 발생한 문제

로그인 다이얼로그가 뷰에 띄워진 상태에서 Navigation을 Back버튼을 누르거나 제스쳐를 통한 Back 이 이루어졌을 경우,
Disappear에서 isShowDialog를 false로 바꿔주기 전에 이전 화면이 나타나게 되면서 이전 화면에도 로그인 다이얼로그가 나타나는 현상이 발생



@withseon withseon self-assigned this Apr 22, 2024
@withseon withseon added 수정 코드 리팩토링 수행 🐯 인선 디자인 화면을 그리는 UI 작업 labels Apr 22, 2024
withseon added a commit that referenced this issue Apr 23, 2024
- LoginDialog가 나타날 때, toolbar Button disable 처리
- CustomDialog가 나타날 때, 제스쳐를 이용한 Back 못하게 처리
@withseon
Copy link
Contributor Author

withseon commented Apr 23, 2024

LoginDialog를 띄웠을 때, ToolBarItem 클릭 막기

ToolBarItem으로 특정 동작(navigation back나 shareLink)을 하는 View 위에 로그인 다이얼로그가 띄워지는 경우가 있다.

  1. DrinkDetailView (navigation back, shareLink)
  2. NavigationPostsView (navigation back)

해당 동작을 disabled 처리 해줌으로써, 로그인 다이얼로그가 띄워졌을 때 동작에 제한을 주었다.

// DrinkDetailView
.toolbar {
	ToolbarItem(placement: .topBarLeading) {
		Button {
			navigationRouter.back()
		} label: {
			Image(systemName: "chevron.backward")
		}
		.disabled(authViewModel.isShowLoginDialog)
	}
	ToolbarItem(placement: .topBarTrailing) {
	// 공유하기
	ShareLink(item: drink.drinkField.name,
			...
		) {
			Image(systemName: "square.and.arrow.up")
		}
		.disabled(authViewModel.isShowLoginDialog)
	}
}
.tint(.mainBlack)



Dialog를 띄웠을 때, 제스쳐를 통한 navigation back 막기

제스쳐를 통하여 navigation back을 할 수 있게 하는 코드

// UINavigationController +
extension UINavigationController: UIGestureRecognizerDelegate {
	override open func viewDidLoad() {
		super.viewDidLoad()
		interactivePopGestureRecognizer?.delegate = **self**
	}
	public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
		return viewControllers.count > 1
	}
}



첫번째 시도

처음에는 gestureRecognizerShouldBegin에서 제스쳐가 이루어지는 뷰의 정보를 파악하고 이를 이용하여 return값을 변경해주면 되지 않을까...? 라는 생각을 했다.

그래서 일단 gestureRecognizer.view의 타입을 출력해보았다.

어느 뷰에 가서 제스쳐를 동작해봐도 동일하게 UILayoutContainerView가 출력된다.
UILayoutContainerView 보다 더 내려가서 뷰의 정보를 얻고 싶은데...

그러면 UILayoutContainerView의 하위 계층을 계속 탐색해서 뷰의 정보를 얻어와야 하나...?
제스쳐가 한 번 이루어질 때마다 이런 식으로 하위 계층을 탐색하면 안되지 않을까?

뷰의 정보를 얻을 수 있는 다른 방법을 찾아보자.



두번째 시도

뷰의 정보를 얻는 다른 방법을 찾던 중에...
제스쳐가 어느 뷰에서 이루어졌는지를 파악해서 제스쳐를 막는 방법 말고 다른 게 없을까 라는 생각을 해봤다.
그래서 생각난 게

UINavigationController에 타입 프로퍼티를 생성하여 제스쳐를 막는 방법

// UINavigationController +
extension UINavigationController: UIGestureRecognizerDelegate {
	static var allowSwipeBack: Bool = true // 제스쳐 동작 가능 여부를 판별하는 타입 프로퍼티
	
	override open func viewDidLoad() {
		super.viewDidLoad()
		interactivePopGestureRecognizer?.delegate = **self**
	}
	public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
		if allowSwipeBack { // 제스쳐 동작이 가능할 때
			return viewControllers.count > 1
		}
		return false // 제스쳐 동작 불가능할 때 false 리턴으로 navigation back 막기
	}
}
// CustomDialog
struct CustomDialog: View {
	let type: CustomDialogType

	var body: some View {
		ZStack {
			...
		}
		.onAppear {
			UINavigationController.allowSwipeBack = false
		}
		.onDisappear {
			UINavigationController.allowSwipeBack = true
		}
	}
}
  • 타입 프로퍼티 allowSwipeBack을 생성한 뒤 초기값을 true로 설정
  • CustomDialog가 appear될 때 해당 프로퍼티의 값을 false로 변경하여 제스쳐 동작 시 navigation back 동작을 막음
  • CustomDialog가 disappear될 때 다시 해당 프로퍼티의 값을 true로 변경함으로써 제스쳐의 navigation back이 이루어질 수 있게 구현



결과

CustomDialog가 띄워졌을 때, 제스쳐를 통한 navigation back을 불가능하게 하였다.
이로써 LoginDialog가 닫힌 후 뷰를 이동할 수 있게 되었고 기존에 LoginDialog의 Disappear 시 isShowLoginDialog의 값이 false로 변경되면서 이전 뷰에서 LoginDialog가 남아있는 문제 또한 해결되었다.



코드 수정작업이 더 필요

해당 작업으로 LoginDialog 뿐만 아니라 모든 CustomDialog가 나타날 때, 제스쳐 동작을 막는 기능을 구현하면서 이전에 작업했던 CustomDialog를 띄워주는 프로퍼티들의 값 변경이 제 때 이뤄지지 않는 문제를 발견하였다.
ex) SearchDrinkTag에서 RatingDialog를 띄운 후 sheet를 내렸을 때, Dialog가 사라지지 않음.

CustomDialog가 사용되는 부분을 훑으며 코드 보완 예정



withseon added a commit that referenced this issue Apr 23, 2024
[Refactoring] NavigationPostsView 탭뷰, LoginDialog(CustomDialog) 오류 해결 #178
withseon added a commit that referenced this issue May 3, 2024
…178

*문제 및 원인*
RecordViewModel 내에 isShowRatingDialog 프로퍼티를 AddTagView, SearchTagView에서 사용함으로 발생한 문제
- AddTagView와 SearchTagView 각각 isSowRatingDialog를 따로 가지고 있게 코드 수정
@withseon
Copy link
Contributor Author

withseon commented May 7, 2024

추가

1. CustomDialog 쓰는 부분에서의 ToolBarItem disabled 처리

2. SearchTagView가 sheet 형식이라, 닫힐 때 AddTagView에서도 CustomDialog(Rating)이 뜨는 문제

문제 및 원인

AddTagView의 CustomDialog와 SearchTagView CustomDialog 처리를 RecordViewMdoel의 isShowRatingDialog 상태 프로퍼티로 해줬음. (CustomDialog가 disappear 될 때, isShowRatingDialog의 값이 false가 되는 형태)

AddTagView 위에 SearchTagView가 올라오는데, sheet이다보니까 제스쳐로 SearchTagView를 disappear 시킬 수 있는 상황.
SearchTagView가 disappear되는 시점보다 AddTagView의 appear 시점이 더 빠르기 때문에
AddTagView에 CustomDialog가 띄워지게 되는 문제 발생

해결 방법

기존 RecordViewModel의 isShowRatingDialog 상태 프로퍼티를 없애고
AddTagView와 SearchTagView에
각각 isShowRatingDialog 상태 변수를 가지고 있게 변경

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐯 인선 디자인 화면을 그리는 UI 작업 수정 코드 리팩토링 수행
Projects
None yet
1 participant