2010-04-21 21 views
9

Tôi có hai chế độ xem cần được hiển thị một cách bình thường, cái khác. Điều này không hiệu quả nếu chúng tôi loại bỏ và hiển thị liên tiếp, như sau:Cách đúng hiển thị các phương thức liên tiếp

[rootController dismissModalViewControllerAnimated: YES]; 
[rootController presentModalViewController: psvc animated: YES]; 

Chế độ xem thứ hai đơn giản không hiển thị.

Tôi đã nhìn thấy một sửa chữa đó là một cái gì đó như thế này:

[rootController dismissModalViewControllerAnimated: YES]; 
[[UIApplication sharedApplication] beginIgnoringInteractionEvents]; 
[self performSelector: @selector(seekModal) withObject: nil afterDelay: 0.5]; 
[[UIApplication sharedApplication] endIgnoringInteractionEvents]; 

Vấn đề là điều này sẽ không làm việc tất cả các thời gian (sự chậm trễ cần thiết là cấp trên, đôi khi).

Một sửa chữa có thể sẽ là để loại bỏ các hình ảnh động:

[rootController dismissModalViewControllerAnimated: NO]; 
[rootController presentModalViewController: psvc animated: YES]; 

Nhưng tôi thực sự muốn giữ hình ảnh động, để giữ những cảm nhận rằng phương thức đầu tiên là ra khỏi đường. Bất kỳ đề xuất?

+3

Tại sao không chỉ sử dụng trên phương thức View Controller rằng những thay đổi quan điểm của mình? Hai chế độ xem bộ điều khiển theo chế độ trong một hàng sẽ hơi khó chịu. – bpapa

+0

Nếu chúng là "liên tiếp", hãy cân nhắc sử dụng điều hướng. –

+0

Bạn có chắc chắn 100% rằng việc loại bỏ chế độ xem phương thức thứ nhất và mở phiên bản thứ hai đều được thực hiện trong ngữ cảnh của chuỗi chính không? – yonel

Trả lời

17

EDIT: Cơ chế "đúng" để thực hiện việc này trong iOS5 + sẽ sử dụng phương thức – dismissViewControllerAnimated:completion: và trình bày trình điều khiển chế độ xem tuần tự từ khối hoàn thành.


Bộ điều khiển chế độ xem đang được hiển thị sẽ có phương thức viewDidDisappear: animated: đã hoàn thành.AFIK đây là nơi duy nhất bạn có thể móc để bắt đầu một hiện tại tiếp theoModalViewController: hoạt hình: cuộc gọi.

Tôi có một lớp mà tôi sử dụng để trình bày bộ kiểm soát chế độ xem và nó thực hiện logic mà bạn đang tìm kiếm thông qua một cuộc gọi lại đến trình điều khiển xem trình bày khi việc loại bỏ hoàn tất. Để sử dụng lớp này, chỉ cần phân bổ/init một cá thể và hiện tại bằng cách sử dụng presentViewController bình thường: animated: call. Thực hiện các phương pháp sau đây trên bộ điều khiển xem trình bày:

- (void) modalViewControllerDidDismiss:(UIViewController *)modalViewController 

này sẽ được gọi cùng một lúc điều khiển xem phương thức đã biến mất, và bạn có thể trình bày một bộ điều khiển xem phương thức mới vào lúc này.

Một điều thú vị nữa - vì lớp này là chuyên môn của UINavigationController, bạn có thể định cấu hình điều hướng bật/tắt theo ý mình. Lớp này cũng có logic tích hợp để hiển thị nút gạt, như bạn muốn.

Đây là định nghĩa lớp:

@protocol TSModalViewControllerDelegate 

- (void) modalViewControllerDidDismiss: (UIViewController*) modalViewController; 

@end 

@interface TSModalViewController : UINavigationController 
{ 
    UIViewController* _originalParentViewController; 
} 
@property BOOL dismissButtonHidden; 

- (id) initWithViewController: (UIViewController*) vc; 
- (id) initWithClass: (Class) c; 
- (id) initWithClass: (Class) c nibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil; 

@end 

Và việc thực hiện lớp:

@implementation TSModalViewController 
@synthesize dismissButtonHidden; 

- (id) initWithViewController: (UIViewController *)vc 
{ 
    return [super initWithRootViewController: vc]; 
} 

- (id) initWithClass:(Class)c 
{ 
    UIViewController* vc = [[[c alloc] init] autorelease]; 
    return [self initWithViewController: vc]; 
} 

- (id) initWithClass: (Class) c nibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    UIViewController* vc = [[[c alloc] initWithNibName:nibNameOrNil bundle:nibBundleOrNil] autorelease]; 
    return [self initWithViewController: vc]; 
} 

- (void) viewDidAppear: (BOOL) animated 
{ 
    [super viewDidAppear: animated]; 

    [_originalParentViewController release]; 
    _originalParentViewController = [self.parentViewController retain]; 

    if (!self.dismissButtonHidden) 
    { 
     UIBarButtonItem* dismissButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemStop 
                         target: self 
                         action: @selector(onDismiss:)] autorelease]; 

     UIViewController* rootViewController = [self.viewControllers objectAtIndex:0]; 

     rootViewController.navigationItem.leftBarButtonItem = dismissButton; 
     self.navigationBarHidden = NO; 
    } 
} 

- (void) viewDidDisappear:(BOOL)animated 
{ 
    [super viewDidDisappear: animated]; 
    if ([_originalParentViewController respondsToSelector: @selector(modalViewControllerDidDismiss:)]) 
    { 
     [_originalParentViewController performSelector: @selector(modalViewControllerDidDismiss:) withObject: self]; 
    } 
} 

- (void) dismissModalViewControllerAnimated:(BOOL)animated 
{ 
    return [self.parentViewController dismissModalViewControllerAnimated: animated]; 
} 

- (void) onDismiss: (id) sender 
{ 
    [self.parentViewController dismissModalViewControllerAnimated: YES]; 
} 

- (void) didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
} 

- (void) viewDidUnload 
{ 
    [super viewDidUnload]; 
} 

- (void)dealloc 
{ 
    [_originalParentViewController release]; 
    [super dealloc]; 
} 

@end 

và, dưới đây là cách bạn có thể sử dụng nó (trong bối cảnh của một số bộ điều khiển xem bình thường):

- (void) onShowIt:(id)sender 
{ 
    TSModalViewController* mvc = [[[TSModalViewController alloc] initWithClass: [MyModalViewController class] nibName: @"MyModalViewController" bundle:nil] autorelease]; 
    mvc.dismissButtonHidden = YES; // set to no if you don't want an "automatic" close button 

    [self presentModalViewController: mvc animated: YES]; 
} 

và, đây là phương thức gọi lại loại bỏ, trình bày một bộ điều khiển chế độ xem mới:

- (void) modalViewControllerDidDismiss:(UIViewController *)modalViewController 
{ 
    MyModalViewController* vc = [[[MyModalViewController alloc] initWithNibName: @"MyModalViewController" bundle:nil] autorelease]; 
    vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; 

    TSModalViewController* mvc = [[[TSModalViewController alloc] initWithViewController: vc] autorelease]; 

    [self presentModalViewController: mvc animated: YES]; 
} 
0

rootController có thể cho biết khi nào bộ điều khiển xem phương thức cuối cùng trên đầu trang đã biến mất vì nó sẽ nhận được một viewDidAppear :. Bạn đã thử liên kết hiện tạiModalViewController: của bộ điều khiển xem tiếp theo đó?

+0

Bạn vẫn gặp sự cố về thời gian ... viewDidAppear được gọi trước khi chế độ xem thực sự xuất hiện, rõ ràng. –

+0

Luôn luôn có 'performSelector: foo afterDelay: 0' có thể hoạt động trong viewDidAppear ... –

0

Nếu bạn thực sự muốn kết hợp nhiều hoạt ảnh xem cùng nhau, tôi thực sự khuyên bạn chỉ nên xử lý logic hoạt ảnh. Nó không quá phức tạp, và sau đó bạn có thể kiểm soát chi tiết cách hiển thị các khung nhìn. Tôi chỉ viết lên một cái gì đó tương tự cho một câu hỏi ở đây:

iOS -- how do you control the size of a modal view controller?

Bạn chỉ có thể animate view trên, animate xem ra, và khi chọn animationDidStop của bạn được gọi, hoạt hình xem thứ hai của bạn trên. Phần tốt đẹp của điều này là bạn cũng có thể chơi với độ mờ của chế độ xem và hướng hoạt ảnh cũng như quyết định chính xác thời điểm các lượt xem sẽ xuất hiện. Ví dụ: bạn có thể có chế độ xem thứ hai sẽ trượt lên trên chế độ xem đầu tiên vì chế độ xem đầu tiên bị trượt đi; không cần phải chờ cho người đầu tiên hoàn thành hoạt hình của nó.

+0

Ý tưởng thú vị. Có vẻ như điều này buộc bạn ra khỏi MVC, phải không? Giống như bạn sẽ kết thúc với hai quan điểm và một bộ điều khiển. –

+0

MVC không nhất thiết có nghĩa là một trong số đó; nó thực sự là về việc tách các thành phần đó ra khỏi nhau và cho phép mỗi thành phần của riêng họ. Nó thực sự khá phổ biến cho một bộ điều khiển xem để quản lý nhiều chế độ xem. Sau khi tất cả, nhiều/hầu hết các thành phần giao diện người dùng mà bạn thêm vào chế độ xem của trình điều khiển chế độ xem (nút, hình ảnh, v.v.) và animate chỉ là chế độ xem. Tốt hơn là nên nghĩ về từng bộ điều khiển xem như thể hiện một đoạn toàn màn hình của chương trình và bộ não đằng sau phần đó của ứng dụng. Bộ điều khiển là logic kết nối (các) mô hình và các khung nhìn với nhau. – atticus

0

Sự cố của bạn có liên quan đến "hiển thị chế độ xem phương thức trong chế độ xem phương thức" không? Tôi đã viết một câu trả lời về vấn đề này ở đây: iPhone modal view inside another modal view?

+0

Không thực sự. Đó là về việc đóng một chế độ xem và mở một chế độ xem khác. iOS dường như bị nghẹt thở khi bạn đóng và hiển thị một chế độ xem quá gần nhau. Điều này đặc biệt là một vấn đề với bộ chọn máy ảnh, bởi vì nó có thời gian tải/dỡ quá lớn. Nếu bạn muốn loại bỏ bộ chọn máy ảnh, và hiển thị một cái gì đó khác, bạn có thể chạy vào tất cả các loại hành vi lạ. –

0

Giải pháp tốt nhất mà tôi tìm thấy một cái gì đó như thế này (nếu họ là tất cả trẻ em bình đẳng của quan điểm mẹ) là để vá quan điểm của họ vào một UIScrollView với phân trang kích hoạt, (bạn có thể thêm một điều khiển trang ở phía dưới để làm cho nó rõ ràng và cho chuyển hướng) sau đó thêm các quan điểm của bộ điều khiển để xem trang khi họ đến trên màn hình, loại bỏ khi họ đi offscreen.

Bạn cũng có thể phải gọi dummy -viewWillAppear và -viewWillDisappear nếu bộ điều khiển dựa vào việc này đang được gọi. Nó có vẻ như là hack-ish khi bạn mã hóa tất cả, nhưng một khi bạn có nó hoạt động thì nó trông mịn màng và tự nhiên, và không có bất kỳ sự chờ đợi nào liên quan đến việc tạo ra một khung nhìn, sau đó làm hoạt hình tiếp theo đã biến mất.

0

Tôi thấy sử dụng -viewDidDissapear quan điểm phương thức để gọi các phương pháp trên quan điểm trình bày điều khiển công việc của rất tốt. Một lợi ích là khả năng trì hoãn deallocation trên bộ điều khiển xem phương thức. Vui lòng đăng bất kỳ cải tiến nào tôi có thể thực hiện. Cảm hứng của tôi về việc tạo giao thức này đến từ "dismissViewControllerAnimated: completion" của iOS 5, thêm vào UIViewController. Tôi muốn chức năng này trong iOS 4.3.


PresentorDelegateProtocol.h

@protocol PresentorDelegateProtocol <NSObject> 
@optional 

/* 

Extra protocol methods defined in protocol for flexibility. 
Main methods are: 
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated; 
- (void)modalViewDissapeared:(id)modalView; //used in modal view's -viewDidDissapear 

*/ 

- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated; 
- (void)modalViewDissapeared:(id)modalView; 

// use the block in this method send messages to save state, etc. This is the one I like to use. 
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated withBlock:(void(^)())block; 

// use in other classes that are not controlling dismissal of the modal view 
- (void)executeBlockOnModalDissapearance: (void(^)())block; 

@end 

PresentingViewController.h

#import "PresentorDelegateProtocol.h" 
@interface PresentingViewController : UIViewController <PresentorDelegateProtocol> 
- (void)showModalVC; 
@end 

ModalViewController.h

#import "PresentorDelegateProtocol.h" 
@interface ModalViewController : UIViewController 
@property (nonatomic, assign) id <PresentorDelegateProtocol> presentorDelegate; 
- (void)close; 
@end 

PresentingViewController.m

#import "PresentingViewController.h" 
#import "ModalViewController.h" 
@implementation PresentingModalViewController 
- (void)showModalVC 
{ 
    ModalViewController *modalVC = [[ModalViewController alloc] initWithNibName:@"ModalViewController" bundle:nil]; 
    modalVC.presentorDelegate = self; 
    [self presentModalViewController:modalVC animated:YES]; 
} 
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated 
{ 
    if ([modalView isKindOfClass:[ModalViewController class]]) { 
     NSLog(@"Can invoke based on class"); 
    } 
    [self dismissModalViewControllerAnimated:animated];  
} 
- (void)dismissPresentingModalViewController:(id)modalView animated:(BOOL)animated withBlock:(void(^)())block 
{ 
    block(); 
    /* execute block before or after calling to dismiss modal view */ 
    [self dismissPresentingModalViewController:modalView animated:animated]; 
    //block(); 
} 
- (void)modalViewDissapeared:(id)modalView 
{ 
    if ([modalView isKindOfClass:[ModalViewController class]]) { 
     NSLog(@"Do stuff based on class."); 
    } 
} 
- (void)executeBlockOnModalDissapearance: (void(^)())block 
{ 
    block(); 
    NSLog(@"This delay's dealloc on modal view until block completes"); 
} 
@end 

ModalViewController.m

#import "ModalViewController.h" 
@implementation ModalViewController 
@synthesize presentorDelegate; 

- (void)close 
{ 
    if (1 == 0 /*need to do something before dealloc*/){ 
     [self.presentorDelegate dismissPresentingModalViewController:self animated:YES withBlock:^{ 
      NSLog(@"Do stuff with block. Save, animate, etc"); 
     }]; 

    } else { 
     [self.presentorDelegate dismissPresentingModalViewController:self animated:YES]; 
    } 
} 

- (void)viewDidDisappear:(BOOL)animated 
{ 
    if (1 == 0 /*stuff to do*/){ 
     [self.presentorDelegate executeBlockOnModalDissapearance:^{ 
     // do stuff before modal view is deallocated 
     }]; 
    } 
    [self.presentorDelegate modalViewDissapeared:self]; 

    presentorDelegate = nil; 
    [super viewDidDisappear:animated]; 
} 
@end; 
0
// present modal view inside another presented modal view 

    FirstViewController *firstVC = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil]; 
    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: firstVC]; 

    // Note: you can use your viewcontroller instead self.window.rootViewController 

    [self.window.rootViewController presentViewController:navController animated:YES completion:^{ 
       //code... 
        SecondViewController *secondVC = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil]; 

        [navController presentViewController: secondVC animated:YES completion:nil]; 

       } 
      }];