iOS控制器间跳转

iOS控制器间跳转一:UINavigationController

  • 为了便于管理控制器,iOS提供了2个比较特殊的控制器

    • UINavigationController
    • UITabBarController
  • 简单实用

UIWindow显示根导航控制器,跳转到第一个控制器oneViewController

1
2
3
4
5
6
7
8
9
10
11
12
13
UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

self.window = window;

// 创建导航控制器
// 创建登陆控制器
AMLoginViewController *loginVc = [[AMLoginViewController alloc] initWithNibName:NSStringFromClass([AMLoginViewController class]) bundle:[NSBundle mainBundle]];

UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:loginVc];

window.rootViewController = nav;

[window makeKeyAndVisible];

由第一个控制器跳转到第二个控制器TwoViewController

1
2
3
如果导航控制器调用 push,就会把 vc 添加为导航控制器的子控制器
TwoViewController *vc = [[TwoViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];

由第二个控制器跳转到第三个控制器ThreeViewController

1
2
ThreeViewController *vc = [[ThreeViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];

由第三个控制器直接跳转到根控制器,或者返回上一个控制器

1
2
3
4
5
// 返回到根控制器
[self.navigationController popToViewController:self.navigationController.childViewControllers[0] animated:YES];

// 返回到上一个控制器
[self.navigationController popViewControllerAnimated:YES];

只有栈顶控制器的界面才会显示出来,UINavigationController 有个属性是 topViewController 表示栈顶控制器


UINavigationController的子控制器管理

  • UINavigationController以栈的形式保存子控制器
1
2
@property(nonatomic,copy) NSArray *viewControllers;
@property(nonatomic,readonly) NSArray *childViewControllers;
  • 使用push方法能将某个控制器压入栈
1
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
  • 使用pop方法将栈顶的控制器移除
1
- (UIViewController *)popViewControllerAnimated:(BOOL)animated;
  • 回到指定的子控制器
1
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
  • 回到根控制器(栈底控制器)
1
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated;

注意:pop方法不是马上将栈顶子控制器拿出栈(销毁),而是在动画完成的时候才会销毁

控制器间跳转二:Modal

除了push之外,还有另一种控制器的切换方式,就是modal。任何控制器都可以通过modal形式展示出来

modal的默认效果:新的控制器从屏幕最底部往上钻,知道覆盖全部控制器位置。

以Modal的形式展示控制器代码如下:

1
2

self presentViewController:(UIViewController *) animated:(BOOL) completion:^(void)completion

关闭当初Modal出来的控制器

1
2
3
[self dismissViewControllerAnimated:(BOOL) completion:^{
code
}]

注意点

  • Modal出来的控制器是直接添加到窗口上
  • Modal出来控制器后,虽然加到窗口上,但是窗口的跟控制器一直没被销毁
  • Modal出来的控制器需要被强引用,不然会被销毁,无法监听控制器事件
  • Modal出来的控制器被上一个控制器的presentedViewController属性强引用。
  • Modal的常见用法:Modal出导航控制器

Modal的dismiss原理:

  • 控制器被dismiss后,会被销毁
  • 谁Modal也有权dismiss
  • 被modal出来的控制器都可以dissmiss
  • 导航控制器上的按钮modal,跳转到带导航控制器的控制器上。dismiss的时候会判断当前控制器有没有导航控制器,有也可以把导航控制器dismiss。

控制器之间的值传递

第一种方法可以用代理,不过比较麻烦,
这里推荐用 block 可以将要传递的值作为参数

在第一个控制器中拿到要跳转的控制器的 block 属性赋值,然后在跳转的控制器中执行 block 代码即可。

例子:将Vc1 控制器接收传值 ,Vc2控制器发送传值消息,为了便于区别和代理传值的 使用 , 将两者放到 一起其中Vc1控制器里 两个UITextField一个接收代理传值的使用,一个接收block 的使用 。
Vc1 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

#import "ViewController.h"
#import "SecondViewController.h"
@interface ViewController ()<secondViewControllerDelegate>
- (IBAction)gengxin;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UITextField *secTextField;
@property (nonatomic,strong) SecondViewController *secVc;
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
SecondViewController *secondVc = [[SecondViewController alloc] init];
[secondVc returnText:^(NSString *showText) {
NSLog(@"---------%@------------",showText);
self.secTextField.text = showText;
}];
self.secVc = secondVc;
self.secVc.delegate = self;

}
- (IBAction)gengxin {
[self presentViewController:self.secVc animated:YES completion:nil];
}
#pragma mark - secondViewControllerDelegate
- (void)setTextfield:(NSString *)text{
self.textField.text = text;
NSLog(@"%@",text);
}
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Vc2 :
#import "ViewController.h"
@protocol secondViewControllerDelegate
@optional - (void)setTextfield:(NSString *)text;
@end

typedef void(^returnBlock)(NSString *showText);
@interface SecondViewController : ViewController
@property (nonatomic,strong) id delegate;
//声明block 属性
@property (nonatomic,strong)returnBlock returnTextBlock;
//声明 调用方法
- (void) returnText: (returnBlock)block;
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

#import "SecondViewController.h"

@interface SecondViewController ()
@property (nonatomic,weak) UITextField *textField;
@property (nonatomic,weak) UIButton *saveButton;
@end

@implementation SecondViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor grayColor];
UITextField *textField =[[UITextField alloc] init];
[self.view addSubview:textField];
[textField setBorderStyle:UITextBorderStyleRoundedRect];
self.textField = textField;
self.textField.frame = CGRectMake(100, 100, 100, 100);
UIButton *save = [[UIButton alloc] init];
[self.view addSubview:save];
self.saveButton = save;
self.saveButton.frame = CGRectMake(200, 200, 100, 70);
[self.saveButton setTitle:@"确定" forState:UIControlStateNormal];
self.saveButton.titleLabel.textColor = [UIColor blackColor];
[self.saveButton addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];

}
- (void) buttonClick:(id)sender{
if ([self.delegate respondsToSelector:@selector(setTextField:)]) {
NSString *text =self.textField.text;
[self.delegate setTextfield:text];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.

}
- (void) returnText:(returnBlock)block
{
self.returnTextBlock = block;
}
- (void)viewDidDisappear:(BOOL)animated
{
//即将消失的时候
if (self.returnTextBlock !=nil) {
self.returnTextBlock(self.textField.text);
}
NSLog(@"======%@=======",self.returnTextBlock);
}

@end

两者之间的理解方式相同 ,在Vc1传值的里面,将 returenText:方法里的 block值传入 Vc2 控制器里,在控制器 Vc2 跳转的时候,可以判断属性里有值,然后再重新加载 Vc1 的时候,就可以将值写入控制器里的 secTextField 里了

文章作者: Ammar
文章链接: http://lizhaoloveit.cn/2014/04/18/iOS%E6%8E%A7%E5%88%B6%E5%99%A8%E9%97%B4%E8%B7%B3%E8%BD%AC/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ammar's Blog
打赏
  • 微信
  • 支付宝

评论