programing

UINavigation Controller에서 보기를 팝업하고 한 번의 작업으로 다른 보기로 바꾸려면 어떻게 해야 합니까?

itmemos 2023. 8. 15. 10:48
반응형

UINavigation Controller에서 보기를 팝업하고 한 번의 작업으로 다른 보기로 바꾸려면 어떻게 해야 합니까?

UINavigation Controller 스택에서 보기 하나를 제거하고 다른 보기로 바꿔야 하는 응용 프로그램이 있습니다.이 경우 첫 번째 보기는 편집 가능한 항목을 만든 다음 항목의 편집기로 대체됩니다.첫 번째 보기 내에서 명확한 솔루션을 수행할 때:

MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

[self retain];
[self.navigationController popViewControllerAnimated: NO];
[self.navigationController pushViewController: mevc animated: YES];
[self release];

저는 매우 이상한 행동을 합니다.일반적으로 편집기 보기가 나타나지만, 내비게이션 바의 뒤로 버튼을 사용하려고 하면 추가 화면이 나오고, 일부 화면이 공백이 되고, 일부 화면이 엉망이 됩니다.제목도 랜덤이 됩니다.내비게이션 스택이 완전히 호스트된 것과 같습니다.

이 문제에 대한 더 나은 접근법은 무엇입니까?

고마워, 매트

수동으로 문제를 해결할 필요가 없다는 것을 알게 되었습니다.viewControllers에는 두 이 있습니다.기본적으로 이것에는 두 가지 까다로운 점이 있습니다.

  1. self.navigationController돌아올 것입니다nil한다면self가 현재 내비게이션 컨트롤러의 스택에 없습니다.따라서 액세스 권한을 잃기 전에 로컬 변수에 저장합니다.
  2. 당신은 해야 한다.retain 적절하게)release)self그렇지 않으면 사용자가 있는 메소드를 소유한 개체의 할당이 취소되어 이상한 현상이 발생합니다.

일단 그 준비를 하고 나면, 그냥 펑 하고 정상적으로 밀어요.이 코드는 즉시 상단 컨트롤러를 다른 컨트롤러로 교체합니다.

// locally store the navigation controller since
// self.navigationController will be nil once we are popped
UINavigationController *navController = self.navigationController;

// retain ourselves so that the controller will still exist once it's popped off
[[self retain] autorelease];

// Pop this controller and replace with another
[navController popViewControllerAnimated:NO];
[navController pushViewController:someViewController animated:NO];

만약 당신이 그것을 바꾼다면 그 마지막 줄에서.animatedYES그러면 새 화면이 실제로 애니메이션으로 표시되고 방금 팝업한 컨트롤러가 애니메이션으로 표시됩니다.꽤 좋아 보이네요!

다음과 같은 접근 방식이 더 좋은 것으로 보이며 ARC와도 잘 작동합니다.

UIViewController *newVC = [[UIViewController alloc] init];
// Replace the current view controller
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
[viewControllers removeLastObject];
[viewControllers addObject:newVC];
[[self navigationController] setViewControllers:viewControllers animated:YES];

경험에 비추어 볼 때, 당신은 UIN 내비게이션 컨트롤러를 만지작거려야 할 것입니다.viewControllers입니다.다음과 같은 방법이 사용될 것입니다.

MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

[[self retain] autorelease];
NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];
[controllers removeLastObject];
self.navigationController.viewControllers = controllers;
[self.navigationController pushViewController:mevc animated: YES];

참고: 일반적으로 보다 견고하기 때문에 유지/해제를 유지/해제로 변경했습니다. 유지/해제 사이에 예외가 발생하면 자체 누출이 발생하지만 자동 해제가 이를 처리합니다.

많은 노력 끝에 (그리고 Kevin의 코드를 수정한 후), 저는 마침내 스택에서 팝업되는 뷰 컨트롤러에서 이 작업을 수행하는 방법을 알아냈습니다.문제는 컨트롤러 배열에서 마지막 개체를 제거한 후 self.navigationController가 0으로 반환되었다는 것입니다.인스턴스 메서드 navigationController의 UIViewController 설명서에 있는 이 행 때문인 것 같습니다. "ViewController가 스택에 있는 경우에만 탐색 컨트롤러를 반환합니다."

현재 뷰 컨트롤러가 스택에서 제거되면 navigationController 메서드가 0으로 반환될 것이라고 생각합니다.

작동하는 조정된 코드는 다음과 같습니다.

UINavigationController *navController = self.navigationController;
MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];
[controllers removeLastObject];
navController.viewControllers = controllers;
[navController pushViewController:mevc animated: YES];

감사합니다, 이것이 바로 제가 필요로 하는 것이었습니다.나는 또한 페이지 컬을 얻기 위해 이것을 애니메이션에 넣었습니다.

        MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

    UINavigationController *navController = self.navigationController;      
    [[self retain] autorelease];

    [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration: 0.7];
    [UIView setAnimationTransition:<#UIViewAnimationTransitionCurlDown#> forView:navController.view cache:NO];

    [navController popViewControllerAnimated:NO];
    [navController pushViewController:mevc animated:NO];

    [UIView commitAnimations];

0.6 지속 시간은 빠르고, 3GS 및 더 새로운 버전에 적합하며, 0.8은 여전히 3G에 약간 빠릅니다.

요한

다른 보기 컨트롤러를 popToRootViewController로 표시하려면 다음 작업을 수행해야 합니다.

         UIViewController *newVC = [[WelcomeScreenVC alloc] initWithNibName:@"WelcomeScreenVC" bundle:[NSBundle mainBundle]];
            NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
            [viewControllers removeAllObjects];
            [viewControllers addObject:newVC];
            [[self navigationController] setViewControllers:viewControllers animated:NO];

이제 이전 스택이 모두 제거되고 필요한 rootViewController를 사용하여 새 스택이 생성됩니다.

저는 최근에 비슷한 일을 해야 했고 마이클스의 답변을 기반으로 해결책을 마련했습니다.이 경우 탐색 스택에서 두 개의 View 컨트롤러를 제거한 다음 새 View 컨트롤러를 추가해야 했습니다.부르기

[컨트롤러가 LastObject 제거];
twice, worked fine in my case.

UINavigationController *navController = self.navigationController;

// retain ourselves so that the controller will still exist once it's popped off
[[self retain] autorelease];

searchViewController = [[SearchViewController alloc] init];    
NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];

[controllers removeLastObject];
// In my case I want to go up two, then push one..
[controllers removeLastObject];
navController.viewControllers = controllers;

NSLog(@"controllers: %@",controllers);
controllers = nil;

[navController pushViewController:searchViewController animated: NO];

것이.UINavigationController인스턴스 메서드가 작동할 수 있습니다...

지정된 뷰 컨트롤러가 최상위 뷰 컨트롤러가 될 때까지 뷰 컨트롤러를 팝업한 다음 디스플레이를 업데이트합니다.

- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated

다음은 viewControllers 배열을 직접 조작할 필요가 없는 또 다른 접근 방식입니다.컨트롤러가 아직 팝업되지 않았는지 확인하고, 컨트롤러를 누릅니다.

TasksViewController *taskViewController = [[TasksViewController alloc] initWithNibName:nil bundle:nil];

if ([navigationController.viewControllers indexOfObject:taskViewController] == NSNotFound)
{
    [navigationController pushViewController:taskViewController animated:animated];
}
else
{
    [navigationController popToViewController:taskViewController animated:animated];
}
NSMutableArray *controllers = [self.navigationController.viewControllers mutableCopy];
    for(int i=0;i<controllers.count;i++){
       [controllers removeLastObject];
    }
 self.navigationController.viewControllers = controllers;

제가 가장 좋아하는 방법은 UI 내비게이션 컨트롤러의 범주를 사용하는 것입니다.다음이 작동해야 합니다.

UI 내비게이션 컨트롤러+helpers.h #가져오기

@interface UINavigationController (Helpers)

- (UIViewController*) replaceTopViewControllerWithViewController: (UIViewController*) controller;

@end

UI 내비게이션 컨트롤러+도우미
"UINavigationController+"UINavigationController+"도우미들.h"

@implementation UINavigationController (Helpers)

- (UIViewController*) replaceTopViewControllerWithViewController: (UIViewController*) controller {
    UIViewController* topController = self.viewControllers.lastObject;
    [[topController retain] autorelease];
    UIViewController* poppedViewController = [self popViewControllerAnimated:NO];
    [self pushViewController:controller animated:NO];
    return poppedViewController;
}

@end

그런 다음 보기 컨트롤러에서 다음과 같이 위쪽 보기를 새 보기로 바꿀 수 있습니다.

[self.navigationController replaceTopViewControllerWithViewController: newController];

탐색 스택에 추가한 모든 보기 컨트롤러를 제공하는 탐색 보기 컨트롤러 배열을 확인할 수 있습니다.이 배열을 사용하면 특정 보기 컨트롤러로 다시 이동할 수 있습니다.

모노터치 / xamarin IOS의 경우:

UISplitViewController 클래스 내부;

UINavigationController mainNav = this._navController; 
//List<UIViewController> controllers = mainNav.ViewControllers.ToList();
mainNav.ViewControllers = new UIViewController[] { }; 
mainNav.PushViewController(detail, true);//to have the animation

대신에,

사용할 수 있습니다.category해서를 self.navigationController되려고nil나고끝 popViewControllerAnimated

push 냥그툭치밀어, 이기쉬니우, 다할필없습니가요접근툭고에 접속할 필요가 .viewControllers....

// UINavigationController+Helper.h
@interface UINavigationController (Helper)

- (UIViewController*) popThenPushViewController:(UIViewController *)viewController animated:(BOOL)animated;

@end


// UINavigationController+Helper.m
@implementation UINavigationController (Helper)

- (UIViewController*) popThenPushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    UIViewController *v =[self popViewControllerAnimated:NO];

    [self pushViewController:viewController animated:animated];

    return v;
}
@end

View 컨트롤러에서

// #import "UINavigationController+Helper.h"
// invoke in your code
UIViewController *v= [[MyNewViewController alloc] init];

[self.navigationController popThenPushViewController:v animated:YES];

RELEASE_SAFELY(v);

정답은 아니지만 일부 시나리오(예: 내 시나리오)에서는 도움이 될 수 있습니다.

만약 당신이 뷰 컨트롤러 C를 Pop하고 A 대신 B(Out of Stack)로 가야 한다면, C 앞에 B를 푸시할 수 있으며, 3개 모두 스택에 있습니다.B 푸시를 보이지 않게 유지하고 C 또는 C와 B만 함께 팝업할지 여부를 선택하여 동일한 효과를 얻을 수 있습니다.

초기 문제 A -> C (나는 C를 터뜨리고 B를 보여주고 싶다, 스택에서 벗어남)

가능한 해결책 A -> B (보이지 않는 것을 누름) -> C (C를 팝할 때, 나는 B를 보여주거나 또한 팝할 것을 선택함)

이 솔루션을 사용하여 애니메이션을 유지합니다.

[self.navigationController pushViewController:controller animated:YES];
NSMutableArray *newControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
[newControllers removeObject:newControllers[newControllers.count - 2]];
[self.navigationController setViewControllers:newControllers];

언급URL : https://stackoverflow.com/questions/410471/how-can-i-pop-a-view-from-a-uinavigationcontroller-and-replace-it-with-another-i

반응형