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__);
}
生命周期方法执行顺序
viewDidLoad
viewWillAppear
viewWillLayoutSubviews
viewDidLayoutSubviews
viewDidAppear
viewWillDisappear
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
将来的你会感谢今天如此努力的你!
版权声明:本文为博主原创文章,未经博主允许不得转载。