programing

푸시 시그 대신 뷰 컨트롤러를 교체하거나 탐색 스택에서 제거하는 방법은 무엇입니까?

goodcopy 2023. 9. 5. 21:37
반응형

푸시 시그 대신 뷰 컨트롤러를 교체하거나 탐색 스택에서 제거하는 방법은 무엇입니까?

내비게이션 컨트롤러를 사용하여 3개의 보기(전체 화면)를 표시하는 작은 iPhone 앱이 있습니다.

Xcode screenshot

먼저 소셜 네트워크(Facebook, Google+ 등) 목록을 표시합니다.

list screenshot

그런 다음 인증 정보를 묻는 OAuth 대화 상자가 표시됩니다.

login screenshot

그리고 (그 후, 같은)UIWebView) 권한:

permissions screenshot

마지막으로 사용자 세부 정보가 포함된 마지막 뷰 컨트롤러를 표시합니다(실제 앱에서는 멀티플레이어 게임을 시작할 수 있는 메뉴가 됩니다).

details screenshot

이 모든 것이 잘 작동하지만 사용자가 돌아가서 다른 소셜 네트워크를 선택하려는 경우 문제가 있습니다.

사용자가 뒤로 버튼을 누르면 첫 번째 보기가 표시되는 대신 두 번째 보기가 표시되어 OAuth 자격 증명/권한을 다시 요청합니다.

제가 여기서 뭘 할 수 있을까요?Xcode 5.0.2는 푸시, 모달(내 게임에 필요한 탐색 모음을 가리기 때문에 사용할 수 없음) 사용자 지정과 같은 segues에 대한 매우 제한된 선택을 보여줍니다.

저는 iOS 프로그래밍 초보자이지만, 이전에 Adobe AIR 모바일 앱을 개발했고, 1) 푸시 대신 뷰를 교체하고 2) 내비게이션 스택에서 불필요한 뷰를 제거하는 것이 가능했습니다.

네이티브 앱에서 동일하게 하는 방법이 무엇입니까?

위의 다양한 segue를 확장하기 위해, 이것이 저의 해결책입니다.다음과 같은 이점이 있습니다.

  • 맨 위 뷰뿐만 아니라 뷰 스택의 모든 위치에서 작동할 수 있습니다(이것이 실제로 필요한지, 기술적으로 트리거가 가능한지는 모르겠지만, 그 안에 있습니다).
  • 교체를 표시하기 전에 이전 보기 컨트롤러로 팝업 또는 전환이 발생하는 것이 아니라 새 컨트롤러가 원본 컨트롤러의 동일한 후면 탐색으로 자연스럽게 전환되어 표시됩니다.

Segue 코드:

- (void)perform {
    // Grab Variables for readability
    UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
    UIViewController *destinationController = (UIViewController*)[self destinationViewController];
    UINavigationController *navigationController = sourceViewController.navigationController;

    // Get a changeable copy of the stack
    NSMutableArray *controllerStack = [NSMutableArray arrayWithArray:navigationController.viewControllers];
    // Replace the source controller with the destination controller, wherever the source may be
    [controllerStack replaceObjectAtIndex:[controllerStack indexOfObject:sourceViewController] withObject:destinationController];

    // Assign the updated stack with animation
    [navigationController setViewControllers:controllerStack animated:YES];
}

사용자 지정 segue를 사용할 수 있습니다. 이를 위해서는 UIS storyboardSegue를 분류하는 클래스 하위 클래스를 만들어야 합니다(예: MyCustomSegue). 그런 다음 "수행"을 다음과 같은 것으로 재정의할 수 있습니다.

-(void)perform {
    UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
    UIViewController *destinationController = (UIViewController*)[self destinationViewController];
    UINavigationController *navigationController = sourceViewController.navigationController;
    // Pop to root view controller (not animated) before pushing
    [navigationController popToRootViewControllerAnimated:NO];
    [navigationController pushViewController:destinationController animated:YES];    
}

이때 Interface Builder로 이동하여 "custom" segue를 선택하고 클래스의 이름을 입력합니다(예: MyCustomSegue).

신속하게

override func perform() {
    if let navigationController = self.source.navigationController {
        navigationController.setViewControllers([self.destination], animated: true)
    }
}

스플래시 뷰 컨트롤러가 있어서 교체하려고 했기 때문에 사용자 지정 segue가 작동하지 않았습니다.목록에 뷰 컨트롤러가 하나뿐이었기 때문에popToRootViewController스플래시를 스택에 남겨두었습니다.하기 위해 다음 를 사용했습니다.

-(void)perform {
    UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
    UIViewController *destinationController = (UIViewController*)[self destinationViewController];
    UINavigationController *navigationController = sourceViewController.navigationController;
    [navigationController setViewControllers:@[destinationController] animated:YES];
}

이제 스위프트 4에서:

class ReplaceSegue: UIStoryboardSegue {

    override func perform() {
        source.navigationController?.setViewControllers([destination], animated: true)
    }
}

이제 Swift 2.0에서

class ReplaceSegue: UIStoryboardSegue {

    override func perform() {
        sourceViewController.navigationController?.setViewControllers([destinationViewController], animated: true)
    }
}

이 문제에 대한 답은 다음과 같이 단순하다고 생각합니다.

  1. Navigation Controller에서 뷰 컨트롤러 배열 가져오기
  2. 마지막 보기 컨트롤러(현재 보기 컨트롤러) 제거
  3. 마지막으로 새 항목 삽입
  4. 그런 다음 ViewControllers 배열을 아래와 같이 다시 탐색 컨트롤러로 설정합니다.

     if let navController = self.navigationController {
        let newVC = DestinationViewController(nibName: "DestinationViewController", bundle: nil)
    
        var stack = navController.viewControllers
        stack.remove(at: stack.count - 1)       // remove current VC
        stack.insert(newVC, at: stack.count) // add the new one
        navController.setViewControllers(stack, animated: true) // boom!
     }
    

Swift 3과 완벽하게 작동합니다.

새로운 사람들에게 도움이 되길 바랍니다.

건배.

ima747의 빠른 2가지 버전 답변:

override func perform() {
    let navigationController: UINavigationController = sourceViewController.navigationController!;

    var controllerStack = navigationController.viewControllers;
    let index = controllerStack.indexOf(sourceViewController);
    controllerStack[index!] = destinationViewController

    navigationController.setViewControllers(controllerStack, animated: true);
}

그가 언급한 바와 같이 다음과 같은 이점이 있습니다.

  • 맨 위 뷰뿐만 아니라 뷰 스택의 모든 위치에서 작동할 수 있습니다(이것이 실제로 필요한지, 기술적으로 트리거가 가능한지는 모르겠지만, 그 안에 있습니다).
  • 교체를 표시하기 전에 이전 보기 컨트롤러로 팝업 또는 전환이 발생하는 것이 아니라 새 컨트롤러가 원본 컨트롤러의 동일한 후면 탐색으로 자연스럽게 전환되어 표시됩니다.

이 문제에 대한 가장 적절한 해결책은 바람이 없는 segue를 사용하는 것입니다.라우로의 말에 동의합니다.

다음은 detailsViewController[또는 viewController3]에서 myAuthViewController[또는 viewController1]로 완화된 세그먼트를 설정하는 간단한 설명입니다.

이것이 기본적으로 코드를 통해 언윈드 세그를 수행하는 방법입니다.

  • 풀려는 뷰컨트롤러에서 IBAaction 메서드를 구현합니다(이 경우 뷰컨트롤러1).메서드 이름은 UIS storyboardSegue 유형의 인수가 하나 필요할 정도로 긴 것일 수 있습니다.

    @IBAction func unwindToMyAuth(segue: UIStoryboardSegue) {
    println("segue with ID: %@", segue.Identifier)
    }
    
  • 이 메서드를 연결 해제할 보기컨트롤러(3)에서 연결을(를) 연결합니다.링크하려면 보기 맨 위에 있는 종료 아이콘에서 마우스 오른쪽 단추를 클릭합니다(두 손가락 탭). 이 시점에서 '내게로 감기 해제'Auth' 메서드가 팝업 상자에 표시됩니다.이 메서드에서 첫 번째 아이콘인 viewController 아이콘(viewController 아이콘의 맨 위, 종료 아이콘과 같은 행에도 있음)을 클릭합니다.팝업되는 '수동' 옵션을 선택합니다.

  • 문서 개요에서 동일한 보기(viewController3)에 대해 방금 작성한 축소된 세그먼트를 선택합니다.특성 검사기로 이동하여 이 감김 해제된 세그먼트에 고유 식별자를 할당합니다.이제 일반적인 언윈드 세그를 사용할 준비가 되었습니다.

  • 이제 언윈드 세그는 코드의 다른 세그와 마찬가지로 수행될 수 있습니다.

    performSegueWithIdentifier("unwind.to.myauth", sender: nil)
    

이 접근 방식은 탐색 계층에서 viewController2를 제거할 필요 없이 viewController3에서 viewController1로 이동합니다.

다른 segue와 달리, 해제된 segue는 보기 컨트롤러를 인스턴스화하지 않고 탐색 계층의 기존 보기 컨트롤러로만 이동합니다.

이전 답변에서 언급했듯이 팝업이 애니메이션화되지 않은 후 애니메이션을 누르면 실제 프로세스가 표시되기 때문에 보기가 좋지 않습니다.먼저 애니메이션을 누른 다음 이전 VC를 제거하는 것이 좋습니다.이와 같은 경우:

extension UINavigationController {
    func replaceCurrentViewController(with viewController: UIViewController, animated: Bool) {
        pushViewController(viewController, animated: animated)
        let indexToRemove = viewControllers.count - 2
        if indexToRemove >= 0 {
            viewControllers.remove(at: indexToRemove)
        }
    }
}

다음은 (맨 위 스택) 보기 컨트롤러를 (애니메이션 없이) 새 보기 컨트롤러로 대체하는 사용자 지정 시퀀스를 생성하여 빠른 Swift 4/5 솔루션입니다.

class SegueNavigationReplaceTop: UIStoryboardSegue {

    override func perform () {
        guard let navigationController = source.navigationController else { return }
        navigationController.popViewController(animated: false)
        navigationController.pushViewController(destination, animated: false)
    }
}

아래 코드 마지막 보기 컨트롤러 사용 다른 버튼을 사용하거나 내가 사용한 취소 버튼 대신 자신의 버튼을 넣을 수 있습니다.

- (void)viewDidLoad
{
 [super viewDidLoad];

 [self.navigationController setNavigationBarHidden:YES];

 UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismiss:)];

self.navigationItemSetting.leftBarButtonItem = cancelButton;

}

- (IBAction)dismissSettings:(id)sender
{

// your logout code for social media selected
[self.navigationController popToRootViewControllerAnimated:YES];

}

당신이 정말로 해야 할 일은 모델을 제시하는 것입니다.UINavigationController 네트워크를 UIViewControllers의 맨 에 의뉴맨에위메▁over에위topUIViewController)UINavigationController되면 소셜 네트워크합니다.UINavigationController UIViewController한 번

swift3 하나 - - coatouch 에서 segue(스토리보드) 사용자 지정 스토리보드 클래스 - 오버라이드 수행

override func perform() {
    let sourceViewController = self.source
    let destinationController = self.destination
    let navigationController = sourceViewController.navigationController
    // Pop to root view controller (not animated) before pushing
    if self.identifier == "your identifier"{
    navigationController?.popViewController(animated: false)
    navigationController?.pushViewController(destinationController, animated: true)
    }
    }

-또한 소스 뷰 컨트롤러에서 하나의 메서드를 재정의해야 합니다.

  override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
    return false
}

여러분이 할 수 있는 일은 언윈드 뷰 컨트롤러를 사용하는 것입니다.

사실 저는 이것이 바로 당신이 필요로 하는 것이라고 생각합니다.

다음 항목 확인:언윈드 segue의 용도와 사용 방법은 무엇입니까?

이것은 Swift 3에서 저에게 효과가 있었습니다.

class ReplaceSegue: UIStoryboardSegue {
    override func perform() {
        if let navVC = source.navigationController {
            navVC.pushViewController(destination, animated: true)
        } else {
            super.perform()
        }
    }
}

이건 어때요 :) 저는 이제 오래된 질문이지만, 이것은 매력적으로 작용할 것입니다.

UIViewController *destinationController = [[UIViewController alloc] init];
UINavigationController *newNavigation = [[UINavigationController alloc] init];
[newNavigation setViewControllers:@[destinationController]];
[[[UIApplication sharedApplication] delegate] window].rootViewController = newNavigation;

언급URL : https://stackoverflow.com/questions/21414786/instead-of-push-segue-how-to-replace-view-controller-or-remove-from-navigation

반응형