iOS开发基础27-导航控制器入栈与出栈机制及微博个人详情页
1.iOS开发基础1-第一个iOS程序2.iOS开发基础2-基础控件3.iOS开发基础6-懒加载、Plist 文件操作、字典转模型、自定义 View 详解4.iOS开发基础5-UIButton5.iOS开发基础4-图像资源6.iOS开发基础3-UIImage7.iOS开发基础14-KVC的应用与底层逻辑8.iOS开发基础13-深入理解 UITableView(二)9.iOS开发基础12-深入理解UITableView(一)10.iOS开发基础11-屏幕适配、Autolayout及 Masonry 框架11.iOS开发基础10-UIButton内边距和图片拉伸模式12.iOS开发基础9-提示框(UIAlertController)13.iOS开发基础8-UIScrollView14.iOS开发基础7-自定义构造方法、layoutSubviews、Xib文件与自定义View15.iOS开发基础30-UITabBarController16.iOS开发基础29-触摸事件及手势识别17.iOS开发基础28-数据存储与沙盒机制
18.iOS开发基础27-导航控制器入栈与出栈机制及微博个人详情页
19.iOS开发基础26-空20.iOS开发基础25-ARC和MRC深入探析21.iOS开发基础24-UIPickerView、UITextField、KVC、UIDatePicker、控制器及导航控制器22.iOS开发基础23-iOS开发中的Info.plist、UIApplication及其Delegate、UIWindow详解23.iOS开发基础22-键盘通知在iOS开发中的应用24.iOS开发基础21-深入理解通知、代理、KVO和Block在iOS开发中的应用25.iOS开发基础20-UITableView的全局及局部刷新、左滑操作与批量删除26.iOS开发基础19-深入理解和实现不等高的 UITableViewCell27.iOS开发基础18-深入理解 Objective-C Runtime 机制28.iOS开发基础16-使用 `NSTimer` 时避免内存泄露的技巧和最佳实践29.iOS开发基础15-KVO的应用与底层逻辑30.iOS开发基础65-iPad 开发指南31.iOS开发基础64-二维码32.iOS开发基础63-AVFoundation/MediaPlayer33.iOS开发基础62-音频播放34.iOS开发基础61-通讯录35.iOS开发基础60-传感器36.iOS开发基础59-内存优化37.iOS开发基础58-支付宝集成指南38.iOS开发基础57-换肤功能与静态库开发指南39.iOS开发基础56-UIDynamic物理引擎40.iOS开发基础55-利用 UIWindow 实现快速滚动到界面顶部41.iOS开发基础54-CoreLocation42.iOS开发基础53-MapKit 框架43.iOS开发基础47-iOS键盘44.iOS开发基础46-数据安全与HTTPS保护详解45.iOS开发基础45-UIWebview46.iOS开发基础44-网络编程之NSURLSession&AFN47.iOS开发基础43-CocoaPods48.iOS开发基础42-网络编程之文件下载与处理49.iOS开发基础41-网络编程之JSON和XML50.iOS开发基础40-网络编程之NSURLConnection51.iOS开发基础39-RunLoop52.iOS开发基础38-多线程之多图片下载及缓存处理53.iOS开发基础37-多线程之NSOperation54.iOS开发基础36-多线程之GCD55.iOS开发基础35-多线程之NSThread56.iOS开发基础34-多线程57.iOS开发基础33-核心动画(二)58.iOS开发基础33-核心动画(一)59.iOS开发基础32-Quartz2D(二)60.iOS开发基础32-Quartz2D(一)61.iOS开发基础31-Modal 与 Push 详解62.iOS开发基础76-iOS 开发中的属性修饰符详解63.iOS开发基础75-iOS开发中的Block深度解析64.iOS开发基础74-Swift他来了65.iOS开发基础73-24种性能优化技巧66.iOS开发基础72-Xcode 7 升级后的问题与解决方案详解67.iOS开发基础71-应用中的 StatusBar 详解68.iOS开发基础70-TCP与UDP69.iOS开发基础69-应用开发中的 Controller 间通信模式70.iOS开发基础68-图片轮播71.iOS开发基础67-流水布局相册缩放72.iOS开发基础66-UISearchBar 控件指南73.iOS开发基础78-iOS 国际化本文将详细介绍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
将来的你会感谢今天如此努力的你!
版权声明:本文为博主原创文章,未经博主允许不得转载。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!