iOS开发基础27-导航控制器入栈与出栈机制及微博个人详情页

本文将详细介绍iOS中导航控制器的入栈与出栈机制、导航条内容设置、控制器的生命周期等知识点,并通过封装实现微博个人详情页效果。

一、导航控制器的入栈与出栈

1. initWithRootViewController的本质

initWithRootViewController方法用于创建一个导航控制器并设置其根控制器(Root View Controller)。其底层实现实质上是调用了pushViewController:animated:方法,将根控制器压入导航控制器的栈中。

UIViewController *vc = [[OneViewController alloc] init];
// 创建导航控制器,设置根控制器
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
// 相当于调用了push方法
// [nav pushViewController:vc animated:YES];

当一个控制器被压入栈中时,其视图会被添加到导航控制器的视图层次结构中。

2. 导航控制器的出栈操作

返回到上一个控制器

- (IBAction)back2Pre:(id)sender {
    // 从当前导航控制器的栈中弹出栈顶控制器
    [self.navigationController popViewControllerAnimated:YES];
    // 当前控制器不会立即销毁,只是从视图层次结构中移除
}

返回到根控制器

- (IBAction)back2Root:(id)sender {
    // 从当前导航控制器的栈中弹出所有控制器,直到回到根控制器
    [self.navigationController popToRootViewControllerAnimated:YES];
    
    // 也可以指定返回到某个控制器
    // [self.navigationController popToViewController:self.navigationController.childViewControllers[0] animated:YES];
}

二、设置导航条内容

在iOS中,导航条内容由UINavigationItem控制,其具体元素(如按钮)由UIBarButtonItem决定。

设置导航条标题和按钮

- (void)setupNavigationBar {
    // 设置导航条标题
    self.navigationItem.title = @"标题";
    self.navigationItem.titleView = [UIButton buttonWithType:UIButtonTypeContactAdd];
    
    // 设置导航条左侧按钮
    UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStyleDone target:self action:@selector(leftButtonClick)];
    self.navigationItem.leftBarButtonItem = leftItem;
    
    // 设置导航条右侧按钮
    UIImage *image = [[UIImage imageNamed:@"icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStyleDone target:nil action:nil];
    self.navigationItem.rightBarButtonItem = rightItem;
}

三、控制器的视图生命周期

控制器的视图生命周期方法以view开头,根据视图的加载、显示、消失等状态分别进行回调。

视图生命周期方法及其顺序

// 控制器的视图加载完成
- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"%s", __func__);
}

// 控制器的视图即将显示
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    NSLog(@"%s", __func__);
}

// 控制器的视图完全显示
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSLog(@"%s", __func__);
}

// 控制器的视图即将消失
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    NSLog(@"%s", __func__);
}

// 控制器的视图完全消失
- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    NSLog(@"%s", __func__);
}

// 视图即将布局子视图
- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    NSLog(@"%s", __func__);
}

// 视图已布局子视图
- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    NSLog(@"%s", __func__);
}

生命周期方法执行顺序

  1. viewDidLoad
  2. viewWillAppear
  3. viewWillLayoutSubviews
  4. viewDidLayoutSubviews
  5. viewDidAppear
  6. viewWillDisappear
  7. viewDidDisappear

四、封装实现微博个人详情页效果

实现微博个人详情页效果,包括导航条和文字的透明度随滚动变化,头像图片缩放等。

1. 项目框架搭建

首先,拖一个Navigation Controller设置其根控制器为View Controller。在View Controller中,添加必要的视图结构。

2. 具体实现代码

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *headHCons;
@end

ViewController.m

#import "ViewController.h"
#import "UIImage+Image.h"

#define HeaderHeight 200
#define MinHeaderHeight 64
#define TabBarHeight 44

@interface ViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, assign) CGFloat originalOffsetY;
@property (nonatomic, weak) UILabel *titleLabel;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 去除自动调节ScrollView的Insets
    self.automaticallyAdjustsScrollViewInsets = NO;
    
    // 设置初始偏移量
    _originalOffsetY = -(HeaderHeight + TabBarHeight);
    
    // 设置TableView的contentInset
    self.tableView.contentInset = UIEdgeInsetsMake(HeaderHeight + TabBarHeight, 0, 0, 0);
    
    // 清空导航栏的背景图片和阴影图片
    [self.navigationController.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
    [self.navigationController.navigationBar setShadowImage:[[UIImage alloc] init]];
    
    // 设置导航栏标题
    UILabel *titleLabel = [[UILabel alloc] init];
    titleLabel.textColor = [UIColor colorWithWhite:0 alpha:0];
    titleLabel.text = @"个人主页";
    [titleLabel sizeToFit];
    self.navigationItem.titleView = titleLabel;
    self.titleLabel = titleLabel;
}

#pragma mark - UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"第%ld行", indexPath.row];
    return cell;
}

#pragma mark - UITableViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    // 获取当前偏移量
    CGFloat offsetY = scrollView.contentOffset.y;
    
    // 计算偏移量差值
    CGFloat delta = offsetY - _originalOffsetY;
    
    // 计算头部视图的新高度
    CGFloat newHeaderHeight = HeaderHeight - delta;
    if (newHeaderHeight < MinHeaderHeight) {
        newHeaderHeight = MinHeaderHeight;
    }
    self.headHCons.constant = newHeaderHeight;
    
    // 计算导航栏背景透明度
    CGFloat alpha = delta / (HeaderHeight - MinHeaderHeight);
    if (alpha > 1) alpha = 0.99;
    UIColor *color = [UIColor colorWithWhite:1 alpha:alpha];
    [self.navigationController.navigationBar setBackgroundImage:[UIImage imageWithColor:color] forBarMetrics:UIBarMetricsDefault];
    
    // 设置标题透明度
    self.titleLabel.textColor = [UIColor colorWithWhite:0 alpha:alpha];
}

@end

3. 根据颜色生成图片的扩展类

为了能够根据颜色生成图片,实现一个UIImage的类别。

UIImage+Image.h

#import <UIKit/UIKit.h>

@interface UIImage (Image)
// 根据颜色生成一张1x1的图片
+ (UIImage *)imageWithColor:(UIColor *)color;
@end

UIImage+Image.m

#import "UIImage+Image.h"

@implementation UIImage (Image)

+ (UIImage *)imageWithColor:(UIColor *)color {
    // 创建1x1的矩形
    CGRect rect = CGRectMake(0, 0, 1, 1);
    
    // 开启图形上下文
    UIGraphicsBeginImageContext(rect.size);
    
    // 获取上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 填充颜色
    CGContextSetFillColorWithColor(context, [color CGColor]);
    
    // 渲染上下文
    CGContextFillRect(context, rect);
    
    // 获取图片
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
    // 结束上下文
    UIGraphicsEndImageContext();
    
    return image;
}

@end
posted @ 2015-07-30 22:48  Mr.陳  阅读(587)  评论(0编辑  收藏  举报