导航控制器和导航工具栏

导航控制器

  • UINAvigationController与UIViewController的关系

UIViewController是什么?

  1. 它是一个普通的视图控制器,负责管理一个页面

UINavigationController是什么?

  1. 它是一个容器控制器,专门用来管理一组UIviewController的堆栈结构

UINavigationController是iOS中用于管理一系列视图控制器(UIViewController)的容器控制器

它提供了:

  1. 层级导航:类似于网页中的前进、后退
  2. 导航栏:顶部的标题区域,包含返回按钮、标题、右边的按钮
  3. push/pop动画

他们之间的关系

  1. UINavigationController是一个特殊的UIViewController,内部维护了一个控制器栈
  • 在创建一个UIViewController子类的时候,系统会自动声明一个只读的UINavigationController属性

导航控制器:UINavigationController

导航栏:navigationBar

导航栏引入项:UINavigationItem

导航栈:viewControllers

在导航控制器中也控制一个视图控制器,每个视图控制器中对应一个导航引入项,导航引入项就是显示在导航栏上的内容,包括leftBarButton(导航栏左侧按钮)、titleView(导航栏中间标题)、rightBarButton(导航栏右侧按钮)

继承关系:NSObject -> UIrespounder -> UIViewController -> UINavigationController
请添加图片描述

  • 管理多个视图的控制器(UIViewController)的栈式导航

  • 提供默认的返回按钮(Back Button )和导航栏 (UINavigationBar)

  • 初始化并设置根视图控制器

//创建视图控制器
VCRoot* rootVC = [[VCRoot alloc] init];
//将视图控制器赋给导航控制器
UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:rootVC];
//将导航控制器设为窗口的根视图控制器
self.window.rootViewController = nav;
  • push操作
// 在当前控制器中创建下一级控制器(例如:VCSecond)
VCSecond *secondVC = [[VCSecond alloc] init];
// 设置跳转时的过渡动画(默认 YES)
[self.navigationController pushViewController:secondVC animated:YES];
  • pop操作
    1. popViewControllerAnimated::返回上一级(当前控制器出栈)
[self.navigationController popViewControllerAnimated:YES];

​ 2. popToRootViewControllerAnimated::直接返回根控制器(栈中所有中间控制器出栈)

[self.navigationController popToRootViewControllerAnimated:YES];

​ 3. popToViewController:animated::返回指定的控制器(需传入控制器实例)

VCRoot *rootVC = [self.navigationController.viewControllers firstObject];
[self.navigationController popToViewController:rootVC animated:YES];

VCRoot:

#import <UIKit/UIKit.h>NS_ASSUME_NONNULL_BEGIN@interface VCRoot : UIViewController@endNS_ASSUME_NONNULL_END
#import "VCRoot.h"
#import "VCSecond.h"
@interface VCRoot ()@end@implementation VCRoot- (void)viewDidLoad {/*barStyle:导航栏风格颜色barTintColor:导航栏颜色tintColor:导航栏风格颜色toolbarItems:工具栏元素数组UIBarItemFlexibleSpace:自动调整按钮距离*/[super viewDidLoad];// Do any additional setup after loading the view.self.view.backgroundColor = [UIColor yellowColor];/*设置导航栏文字内容*/self.title = @"根视图";// 创建外观配置UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];// 设置背景图片UIImage *bgImage = [UIImage imageNamed:@"photo04.jpg"];appearance.backgroundImage = bgImage;// 隐藏阴影线//appearance.shadowImage = [UIImage new];//appearance.shadowColor = nil;// 应用外观配置self.navigationController.navigationBar.standardAppearance = appearance;self.navigationController.navigationBar.scrollEdgeAppearance = appearance;//appearance.backgroundColor = [UIColor yellowColor];//appearance.shadowImage = [UIImage new];//appearance.shadowColor = nil;/*设置导航元素项的标题,它和上一条的区别是如果没有设置navigationItem的title,为nil,系统会自动使用self.title作为标题如果两个都为nil则没有标题*/self.navigationItem.title = @"title";UIBarButtonItem* leftbutton = [[UIBarButtonItem alloc] initWithTitle:@"左侧" style:UIBarButtonItemStyleDone target:self action:@selector(pressleft)];self.navigationItem.leftBarButtonItem = leftbutton;/*UIBarButtonItem* rightbutton = [[UIBarButtonItem alloc] initWithTitle:@"右侧" style:UIBarButtonItemStyleDone target:self action:@selector(pressright)];*/UIBarButtonItem* rightbutton = [[UIBarButtonItem alloc] initWithTitle:@"进入下一级" style:UIBarButtonItemStyleDone target:self action:@selector(pressright)];self.navigationItem.rightBarButtonItem = rightbutton;UIImageView* imageview = [[UIImageView alloc] init];imageview.frame = [[UIScreen mainScreen] bounds];imageview.alpha = 1;imageview.image = [UIImage imageNamed:@"photo02.jpg"];[self.view insertSubview:imageview atIndex:0];UILabel* label = [[UILabel alloc] init];label.frame = CGRectMake(10, 10, 50, 40);label.text = @"test";label.textAlignment = NSTextAlignmentCenter;label.textColor = [UIColor blueColor];UIBarButtonItem* item3 = [[UIBarButtonItem alloc] initWithCustomView:label];NSArray* arrayofbutton = [NSArray arrayWithObjects:rightbutton,item3, nil];self.navigationItem.rightBarButtonItems = arrayofbutton;//隐藏导航栏的两个方法self.navigationController.navigationBar.hidden = NO;//继承与UIViewself.navigationController.navigationBarHidden = NO;//属性}- (void)pressleft {NSLog(@"leftbutton is pressed");
}- (void)pressright {NSLog(@"rightbutton is pressed");
}

在SceneDelegate中创建根视图与导航控制器

#import "SceneDelegate.h"
#import "VCRoot.h"
@interface SceneDelegate ()@end@implementation SceneDelegate- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).self.window.frame = [UIScreen mainScreen].bounds;VCRoot* root = [[VCRoot alloc] init];UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:root];self.window.rootViewController = nav;[self.window makeKeyAndVisible];}- (void)sceneDidDisconnect:(UIScene *)scene {// Called as the scene is being released by the system.// This occurs shortly after the scene enters the background, or when its session is discarded.// Release any resources associated with this scene that can be re-created the next time the scene connects.// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}- (void)sceneDidBecomeActive:(UIScene *)scene {// Called when the scene has moved from an inactive state to an active state.// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}- (void)sceneWillResignActive:(UIScene *)scene {// Called when the scene will move from an active state to an inactive state.// This may occur due to temporary interruptions (ex. an incoming phone call).
}- (void)sceneWillEnterForeground:(UIScene *)scene {// Called as the scene transitions from the background to the foreground.// Use this method to undo the changes made on entering the background.
}- (void)sceneDidEnterBackground:(UIScene *)scene {// Called as the scene transitions from the foreground to the background.// Use this method to save data, release shared resources, and store enough scene-specific state information// to restore the scene back to its current state.
}@end

导航控制器切换

  • navigationBar:导航栏对象
  • navigationItem:导航元素项对象
  • translucent:导航栏透明度
  • pushViewController:推入视图控制器
  • popViewController:弹出视图控制器

根视图:

#import "VCRoot.h"
#import "VCSecond.h"
@interface VCRoot ()@end@implementation VCRoot- (void)viewDidLoad {/*barStyle:导航栏风格颜色barTintColor:导航栏颜色tintColor:导航栏风格颜色toolbarItems:工具栏元素数组UIBarItemFlexibleSpace:自动调整按钮距离*/[super viewDidLoad];// Do any additional setup after loading the view.self.view.backgroundColor = [UIColor yellowColor];/*设置导航栏文字内容*/self.title = @"根视图";// 创建外观配置UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];// 设置背景图片UIImage *bgImage = [UIImage imageNamed:@"photo04.jpg"];appearance.backgroundImage = bgImage;// 隐藏阴影线//appearance.shadowImage = [UIImage new];//appearance.shadowColor = nil;// 应用外观配置self.navigationController.navigationBar.standardAppearance = appearance;self.navigationController.navigationBar.scrollEdgeAppearance = appearance;//appearance.backgroundColor = [UIColor yellowColor];//appearance.shadowImage = [UIImage new];//appearance.shadowColor = nil;/*设置导航元素项的标题,它和上一条的区别是如果没有设置navigationItem的title,为nil,系统会自动使用self.title作为标题如果两个都为nil则没有标题*/self.navigationItem.title = @"title";UIBarButtonItem* leftbutton = [[UIBarButtonItem alloc] initWithTitle:@"左侧" style:UIBarButtonItemStyleDone target:self action:@selector(pressleft)];self.navigationItem.leftBarButtonItem = leftbutton;/*UIBarButtonItem* rightbutton = [[UIBarButtonItem alloc] initWithTitle:@"右侧" style:UIBarButtonItemStyleDone target:self action:@selector(pressright)];*/UIBarButtonItem* rightbutton = [[UIBarButtonItem alloc] initWithTitle:@"进入下一级" style:UIBarButtonItemStyleDone target:self action:@selector(pressright)];self.navigationItem.rightBarButtonItem = rightbutton;UIImageView* imageview = [[UIImageView alloc] init];imageview.frame = [[UIScreen mainScreen] bounds];imageview.alpha = 1;imageview.image = [UIImage imageNamed:@"photo02.jpg"];[self.view insertSubview:imageview atIndex:0];UILabel* label = [[UILabel alloc] init];label.frame = CGRectMake(10, 10, 50, 40);label.text = @"test";label.textAlignment = NSTextAlignmentCenter;label.textColor = [UIColor blueColor];UIBarButtonItem* item3 = [[UIBarButtonItem alloc] initWithCustomView:label];NSArray* arrayofbutton = [NSArray arrayWithObjects:rightbutton,item3, nil];self.navigationItem.rightBarButtonItems = arrayofbutton;//隐藏导航栏的两个方法self.navigationController.navigationBar.hidden = NO;//继承与UIViewself.navigationController.navigationBarHidden = NO;//属性 
}- (void)pressleft {NSLog(@"leftbutton is pressed");
}- (void)pressright {VCSecond* vc2 = [[VCSecond alloc] init];[self.navigationController pushViewController:vc2 animated: YES];
}/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

第二个视图

#import "VCSecond.h"
#import "VCThird.h"
@interface VCSecond ()@end@implementation VCSecond- (void)viewDidLoad {[super viewDidLoad];UIImageView* imageView = [[UIImageView alloc] init];imageView.image = [UIImage imageNamed:@"photo01.jpg"];imageView.frame = [[UIScreen mainScreen] bounds];[self.view insertSubview:imageView atIndex:0];// Do any additional setup after loading the view.//默认透明度为yes:可透明的self.navigationController.navigationBar.translucent = YES;//设置导航控制栏风格,默认为Defaultself.navigationController.navigationBar.barStyle = UIBarStyleDefault;self.title = @"视图二";self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"下一个视图" style:UIBarButtonItemStylePlain target:self action:@selector(pressright)];self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"上一个视图" style:UIBarButtonItemStylePlain target:self action:@selector(pressleft)];
}- (void)pressright {VCThird* vc3 = [[VCThird alloc] init];[self.navigationController pushViewController:vc3 animated:YES];
}- (void)pressleft {[self.navigationController popViewControllerAnimated:YES];
}
/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

第三个视图

#import "VCThird.h"
#import "VCRoot.h"
#import "VCSecond.h"
@interface VCThird ()@end@implementation VCThird- (void)viewDidLoad {[super viewDidLoad];UIImageView* imageview = [UIImageView new];imageview.frame = [[UIScreen mainScreen] bounds];imageview.image = [UIImage imageNamed:@"photo05.jpg"];[self.view insertSubview:imageview atIndex:0];// Do any additional setup after loading the view.self.navigationItem.title = @"视图三";self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"上一级页面" style:UIBarButtonItemStylePlain target:self action:@selector(pressleft)];self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"回到主页面" style:UIBarButtonItemStylePlain target:self action:@selector(pressright)];}- (void)pressleft {[self.navigationController popViewControllerAnimated:YES];
}- (void)pressright {[self.navigationController popToRootViewControllerAnimated:YES];
}
/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

SceneDelegate.m:

#import "SceneDelegate.h"
#import "VCRoot.h"
@interface SceneDelegate ()@end@implementation SceneDelegate- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).self.window.frame = [UIScreen mainScreen].bounds;VCRoot* root = [[VCRoot alloc] init];UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:root];self.window.rootViewController = nav;[self.window makeKeyAndVisible];}- (void)sceneDidDisconnect:(UIScene *)scene {// Called as the scene is being released by the system.// This occurs shortly after the scene enters the background, or when its session is discarded.// Release any resources associated with this scene that can be re-created the next time the scene connects.// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}- (void)sceneDidBecomeActive:(UIScene *)scene {// Called when the scene has moved from an inactive state to an active state.// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}- (void)sceneWillResignActive:(UIScene *)scene {// Called when the scene will move from an active state to an inactive state.// This may occur due to temporary interruptions (ex. an incoming phone call).
}- (void)sceneWillEnterForeground:(UIScene *)scene {// Called as the scene transitions from the background to the foreground.// Use this method to undo the changes made on entering the background.
}- (void)sceneDidEnterBackground:(UIScene *)scene {// Called as the scene transitions from the foreground to the background.// Use this method to save data, release shared resources, and store enough scene-specific state information// to restore the scene back to its current state.
}@end

请添加图片描述

请添加图片描述

导航工具栏:

在OC中,设置导航栏的风格颜色等样式,只要通过UINavigationBar的属性或UINavigationBarAppearance来实现

  • barStyle:导航栏风格
  • barTintColor:导航栏颜色
  • tintColor:导航栏风格颜色
  • toolBarItems:工具栏元素数组
  • UIBarItemFlexibleSpace:自动调整距离按钮
  1. 设置导航栏背景颜色(通过barTintColor)
// 方式 1:直接修改当前导航栏(推荐在视图控制器中使用)
self.navigationController.navigationBar.barTintColor = [UIColor yellowColor];// 方式 2:全局设置(所有导航栏生效,推荐在 AppDelegate 中使用)
[[UINavigationBar appearance] setBarTintColor:[UIColor yellowColor]];
  1. 设置导航栏标题样式(通过titleTextAttributes配置颜色、字体等)
// 方式 1:修改当前导航栏
NSDictionary *titleAttrs = @{NSForegroundColorAttributeName: [UIColor whiteColor],  // 标题颜色NSFontAttributeName: [UIFont boldSystemFontOfSize:18]  // 标题字体
};
[self.navigationController.navigationBar setTitleTextAttributes:titleAttrs];// 方式 2:全局设置
[[UINavigationBar appearance] setTitleTextAttributes:titleAttrs];
  1. 设置导航栏按钮颜色(通过tintColor统一控制导航栏按钮的颜色
// 方式 1:修改当前导航栏
self.navigationController.navigationBar.tintColor = [UIColor blueColor];// 方式 2:全局设置
[[UINavigationBar appearance] setTintColor:[UIColor blueColor]];
  1. 隐藏导航栏底部阴影线(默认存在一条分割线)
// 方式 1:使用 shadowImage
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setShadowImage:[UIImage new]];// 方式 2:iOS 13+ 推荐用 UINavigationBarAppearance
if (@available(iOS 13.0, *)) {UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];appearance.shadowColor = nil;  // 隐藏阴影线self.navigationController.navigationBar.standardAppearance = appearance;
}
  • UINavigationBarAppearance可更细粒度控制导航栏样式,支持标准状态和滚动状态的差异化设置
  1. 全局设置(AppleDelegate中)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {if (@available(iOS 13.0, *)) {UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];// 1. 设置背景appearance.backgroundColor = [UIColor yellowColor];  // 背景色// 2. 设置标题appearance.titleTextAttributes = @{};// 3. 隐藏阴影线appearance.shadowColor = nil;// 4. 应用到所有导航栏UINavigationBar *navBar = [UINavigationBar appearance];navBar.standardAppearance = appearance;         // 标准状态navBar.scrollEdgeAppearance = appearance;       // 滚动到顶部时的状态}return YES;
}
  1. 局部配置
- (void)viewDidLoad {[super viewDidLoad];   if (@available(iOS 13.0, *)) {UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];appearance.backgroundColor = [UIColor orangeColor];appearance.titleTextAttributes = @{NSForegroundColorAttributeName: [UIColor blackColor]};// 应用到当前导航栏self.navigationController.navigationBar.standardAppearance = appearance;self.navigationController.navigationBar.scrollEdgeAppearance = appearance;}
}
  1. 自定义配置
// 在 viewDidLoad 中
UIView *customTitleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 120, 30)];// 添加标题文字
UILabel *titleLabel = [[UILabel alloc] initWithFrame:customTitleView.bounds];
titleLabel.text = @"Custom Title";
titleLabel.font = [UIFont boldSystemFontOfSize:17];
titleLabel.textAlignment = NSTextAlignmentCenter;
[customTitleView addSubview:titleLabel];// 添加标题图片
UIImageView *titleImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
titleImageView.image = [UIImage imageNamed:@"logo"];
[customTitleView addSubview:titleImageView];// 设置到导航栏
self.navigationItem.titleView = customTitleView;
  • 常见问题:

    • 导航栏颜色不生效:检查是否开启了半透明效果,需要关闭
    • 如何让导航栏延伸到状态栏?
 // 在视图控制器中self.edgesForExtendedLayout = UIRectEdgeTop;  // 视图延伸到导航栏下方self.extendedLayoutIncludesOpaqueBars = YES;  // 包含不透明的导航栏

self.edgesForExtendedLayout = UIRectEdgeTop;

  1. 控制视图控制器的根视图可以延伸到屏幕的哪些边缘
  2. 默认是全部,如果导航栏是半透明的,会看到视图与导航栏重合

self.extendedLayoutIncludesOpaqueBars = YES;

  1. 决定延伸布局是否包含不透明的导航栏与工具栏
  2. 默认NO:如果导航栏不透明,根视图会从导航栏底部开始布局
#import "VCRoot.h"
#import "SecondVC.h"@interface VCRoot ()@end@implementation VCRoot- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = [UIColor orangeColor];self.title = @"根视图";UIBarButtonItem *btn = [[UIBarButtonItem alloc] initWithTitle: @"右侧按钮" style: UIBarButtonItemStylePlain target: self action: nil];self.navigationItem.rightBarButtonItem = btn;//UIBarAppearance是iOS13后推出的一个对相应空间设置外观样式的类,可以统一配置NavigationBar、TabBar、ToolBar等的外观样式//UINavigationBarAppearance可以设置导航栏对象的外观样式//创建一个UINavigationBarAppearance对象UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];//设置该对象的背景颜色appearance.backgroundColor = [UIColor blueColor];//创建该对象的阴影图像appearance.shadowImage = [[UIImage alloc] init];//设置该对象的阴影颜色appearance.shadowColor = nil;//设置导航栏按钮的颜色self.navigationController.navigationBar.tintColor = [UIColor purpleColor];//设置普通样式导航栏self.navigationController.navigationBar.standardAppearance = appearance;//设置滚动样式导航栏self.navigationController.navigationBar.scrollEdgeAppearance = appearance;//隐藏导航栏的两个方法//1、下面这一条的hidden是继承于UIView的self.navigationController.navigationBar.hidden = NO;//2、下面这一条的navigationBarHidden是一个属性self.navigationController.navigationBarHidden = NO;//显示工具栏对象//隐藏工具栏,默认为YES:即隐藏;NO:不隐藏self.navigationController.toolbarHidden = NO;//设置工具栏是否透明,默认为YES:半透明self.navigationController.toolbar.translucent = NO;UIBarButtonItem *btn1 = [[UIBarButtonItem alloc] initWithTitle: @"left" style: UIBarButtonItemStylePlain target: nil action: nil];UIBarButtonItem *btn2 = [[UIBarButtonItem alloc] initWithTitle: @"right" style: UIBarButtonItemStylePlain target: self action: @selector(pressBack)];//设置一个自定义类型的button,使用图片创建UIButton *btnC = [UIButton buttonWithType: UIButtonTypeCustom];[btnC setImage: [UIImage imageNamed: @"btnC.jpg"] forState: UIControlStateNormal];btnC.frame = CGRectMake(0, 0, 60, 60);UIBarButtonItem *btn3 = [[UIBarButtonItem alloc] initWithCustomView: btnC];//设置一个占位按钮,放到数组中可以用来分隔开各按钮//设置宽度固定的占位按钮,注:此处方法名为UIBarButtonSystemItemFixedSpace(FixedSpace!!!!!)UIBarButtonItem *btnF1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemFixedSpace target: nil action: nil];btnF1.width = 110;//设置自动计算宽度的占位按钮,注:此处方法名为UIBarButtonSystemItemFlexibleSpace (FlexibleSpace!!!!!)UIBarButtonItem *btnF2 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemFlexibleSpace target: nil action: nil];NSArray *arrayBtn = [NSArray arrayWithObjects: btn1, btnF2, btn3, btnF2, btn2, nil];self.toolbarItems = arrayBtn;}- (void)pressBack {SecondVC *vc = [[SecondVC alloc] init];[self.navigationController pushViewController: vc animated: YES];
}/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

分栏控制器

分栏控制器是一种常用的容器视图控制器,分栏控制器可以包含多个子视图控制器,并通过底部的分栏菜单UIBar

进行切换

  1. 在sceneDelegate中创建子视图控制器,同时创建分栏控制器对象,将子视图控制器添加到分栏控制器中
#import "SceneDelegate.h"
#import "VCFirst.h"
#import "VCSecond.h"
#import "VCThird.h"
#import "VCFourth.h"
#import "VCFifth.h"
#import "VCSixth.h"
@interface SceneDelegate ()@end@implementation SceneDelegate- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {//创建三个视图控制器并更改背景颜色和标题VCFirst* vc01 = [VCFirst new];vc01.view.backgroundColor = [UIColor brownColor];vc01.title = @"视图1";VCSecond* vc02 = [VCSecond new];vc02.view.backgroundColor = [UIColor orangeColor];vc02.title = @"试图2";VCThird* vc03 = [VCThird new];vc03.view.backgroundColor = [UIColor yellowColor];vc03.title = @"视图3";VCFourth* vc04 = [VCFourth new];vc04.view.backgroundColor = [UIColor greenColor];vc04.title = @"视图4";VCFifth* vc05 = [VCFifth new];vc05.view.backgroundColor = [UIColor grayColor];vc05.title = @"视图5";VCSixth* vc06 = [VCSixth new];vc06.view.backgroundColor = [UIColor purpleColor];vc06.title = @"视图6";//创建分栏控制器对象UITabBarController* tbc = [UITabBarController new];//创建一个分栏控制器数组对象,并将所有需要被分栏控制器管理的对象添加进数组//分栏控制器的按钮的位置就取决于在数组中的存放位置NSArray* arrvc = [NSArray arrayWithObjects:vc01, vc02, vc03, nil];//将分栏控制器管理数组赋值tbc.viewControllers = arrvc;//将分栏控制器作为根视图控制哦self.window.rootViewController = tbc;//设置选中的视图控制器的索引//通过所以索引来确定打开程序的时候显示得是哪一个视图控制器tbc.selectedIndex = 2;if (tbc.selectedViewController == vc03) {NSLog(@"选中的是下标为2的视图控制器");}//设置分栏控制器透明度tbc.tabBar.translucent = NO;//设置分栏控制器背景颜色tbc.tabBar.backgroundColor = [UIColor whiteColor];//设置分栏控制器工具栏的按钮选择时的颜色tbc.tabBar.tintColor = [UIColor redColor];//注意不要忘记设置代理tbc.delegate = self;
}//以下是协议中函数的用法,其中“编辑”是指在分栏控制器中的more中通过拖动更改和交换显示和折叠的视图控制器的操作
//即将开始编辑前会调用此协议函数
- (void)tabBarController:(UITabBarController *)tabBarController willBeginCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers {NSLog(@"编辑前");
}//即将结束前调用该协议函数
- (void)tabBarController:(UITabBarController *)tabBarController willEndCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers changed:(BOOL)changed {NSLog(@"即将结束前");
}//已经结束编辑时调用该协议函数
- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers changed:(BOOL)changed {NSLog(@"%@", viewControllers);if (changed == YES) {NSLog(@"顺序发生改变");}NSLog(@"已经结束编辑");
}//选中控制器对象时调用该协议函数
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
//    if (tabBarController.viewControllers[tabBarController.selectedIndex] == viewController) {
//        NSLog(@"选中的视图索引与当前传入的视图索引相同");
//    }NSLog(@"选中控制器对象");
}- (void)sceneDidDisconnect:(UIScene *)scene {// Called as the scene is being released by the system.// This occurs shortly after the scene enters the background, or when its session is discarded.// Release any resources associated with this scene that can be re-created the next time the scene connects.// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}- (void)sceneDidBecomeActive:(UIScene *)scene {// Called when the scene has moved from an inactive state to an active state.// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}- (void)sceneWillResignActive:(UIScene *)scene {// Called when the scene will move from an active state to an inactive state.// This may occur due to temporary interruptions (ex. an incoming phone call).
}- (void)sceneWillEnterForeground:(UIScene *)scene {// Called as the scene transitions from the background to the foreground.// Use this method to undo the changes made on entering the background.
}- (void)sceneDidEnterBackground:(UIScene *)scene {// Called as the scene transitions from the foreground to the background.// Use this method to save data, release shared resources, and store enough scene-specific state information// to restore the scene back to its current state.
}@end

VCfirst.m文件中

#import "VCFirst.h"@interface VCFirst ()@end@implementation VCFirst- (void)viewDidLoad {[super viewDidLoad];//创建一个分栏按钮对象,传入三个参数//第一个参数表示标题文字内容//第二个参数表示显示图片//第三个参数表示对象的标记值UITabBarItem *tabBarItem = [[UITabBarItem alloc] initWithTitle: @"发现" image: nil tag: 101];self.tabBarItem = tabBarItem;
}/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

VCSecond.m

#import "VCSecond.h"@interface VCSecond ()@end@implementation VCSecond- (void)viewDidLoad {[super viewDidLoad];//根据系统风格设置分栏控制器按钮,传入两个参数//第一个参数指分栏控制器的按钮风格,第二个参数是分栏控件对象的标签值UITabBarItem *tabBarItem = [[UITabBarItem alloc] initWithTabBarSystemItem: UITabBarSystemItemContacts tag: 103];//为分栏按钮设置提示的标记值信息,是系统的,无法变更//按钮右上角显示的提示信息//通常用来提示未读的信息tabBarItem.badgeValue = @"22";self.tabBarItem = tabBarItem;
}/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

VCThird.m

#import "VCThird.h"@interface VCThird ()@end@implementation VCThird- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.
}/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

VCForth.m

#import "VCFourth.h"@interface VCFourth ()@end@implementation VCFourth- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.
}/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

VCFifth.m

#import "VCFifth.h"@interface VCFifth ()@end@implementation VCFifth- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.
}/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

VCSixth.m

#import "VCSixth.h"@interface VCSixth ()@end@implementation VCSixth- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.
}/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

请添加图片描述

请添加图片描述

请添加图片描述

分栏控制器协议部分的内容

< UITabBarControllerDelegate>

//以下是协议中函数的用法,其中“编辑”是指在分栏控制器中的more中通过拖动更改和交换显示和折叠的视图控制器的操作
//即将开始编辑前会调用此协议函数
- (void)tabBarController:(UITabBarController *)tabBarController willBeginCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers {NSLog(@"编辑前");
}//即将结束前调用该协议函数
- (void)tabBarController:(UITabBarController *)tabBarController willEndCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers changed:(BOOL)changed {NSLog(@"即将结束前");
}//已经结束编辑时调用该协议函数
- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers changed:(BOOL)changed {NSLog(@"%@", viewControllers);if (changed == YES) {NSLog(@"顺序发生改变");}NSLog(@"已经结束编辑");
}//选中控制器对象时调用该协议函数
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
//    if (tabBarController.viewControllers[tabBarController.selectedIndex] == viewController) {
//        NSLog(@"选中的视图索引与当前传入的视图索引相同");
//    }NSLog(@"选中控制器对象");
}

UITabelView

UITabelView是UI组件中 非常重要的一个组件,在实际开发中有非常重要的作用,这里只做简单介绍,后面笔者会单独总结一下这部分的内容

在创建UITabelView这个组件的时候,首先需要继承UITabelViewDelegate,UITabelViewSource

同时需要设置两个代理:tabelView.delegate、tabelView.dataSource

在协议中必须要实现三个协议函数

  1. -(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section(获取每组元素的个数)
  2. numberOfSectionsInTableView(设置数据视图的组数)
  3. tableView: cellForRowAtIndexPath:(创建单元格对象函数)
//
//  SceneDelegate.m
//  UITableView
//
//  Created by xiaoli pop on 2025/6/4.
//#import "SceneDelegate.h"
#import "ViewController.h"
@interface SceneDelegate ()@end@implementation SceneDelegate- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {self.window.frame = [[UIScreen mainScreen] bounds];ViewController* vc = [ViewController new];UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:vc];self.window.rootViewController = nav;[self.window makeKeyAndVisible];
}- (void)sceneDidDisconnect:(UIScene *)scene {// Called as the scene is being released by the system.// This occurs shortly after the scene enters the background, or when its session is discarded.// Release any resources associated with this scene that can be re-created the next time the scene connects.// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}- (void)sceneDidBecomeActive:(UIScene *)scene {// Called when the scene has moved from an inactive state to an active state.// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}- (void)sceneWillResignActive:(UIScene *)scene {// Called when the scene will move from an active state to an inactive state.// This may occur due to temporary interruptions (ex. an incoming phone call).
}- (void)sceneWillEnterForeground:(UIScene *)scene {// Called as the scene transitions from the background to the foreground.// Use this method to undo the changes made on entering the background.
}- (void)sceneDidEnterBackground:(UIScene *)scene {// Called as the scene transitions from the foreground to the background.// Use this method to save data, release shared resources, and store enough scene-specific state information// to restore the scene back to its current state.
}@end
//
//  ViewController.m
//  UITableView
//
//  Created by xiaoli pop on 2025/6/4.
//#import "ViewController.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];//创建数据视图,传入两个参数//参数一:数据视图的位置//参数二:数据视图的风格-UITableViewStylePlain:普通风格 、 UITableViewStyleGrouped:分组风格self.tableview = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];//自动调整子视图大小self.tableview.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;//创建数据视图的代理对象self.tableview.delegate = self;//设置数据视图的代理源对象self.tableview.dataSource = self;//数据视图的头部视图的设定self.tableview.tableHeaderView = nil;//数据视图的尾部视图的设定self.tableview.tableFooterView = nil;[self.view addSubview:self.tableview];//创建一个可变数组self.arrayData = [[NSMutableArray alloc] init];for (int i = 'A'; i <= 'Z'; i++) {//定义小数组NSMutableArray* arraySmall = [[NSMutableArray alloc] init];for (int j = 1; j <= 5; j++) {NSString* str = [NSString stringWithFormat:@"%c%d",i,j];[arraySmall addObject:str];}//这里就相当于一个二维数组[self.arrayData addObject:arraySmall];}//当数据的数据源发生变化时,更新数据视图,重新加载数据[self.tableview reloadData];}- (void)creatButton {self.isEdit = NO;self.buttonOfEdit = [[UIBarButtonItem alloc] initWithTitle:@"编辑" style:UIBarButtonItemStylePlain target:self action:@selector(pressEdit)];self.buttonOfFinish = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStylePlain target:self action:@selector(pressFinish)];self.buttonOfDelete = [[UIBarButtonItem alloc] initWithTitle:@"删除" style:UIBarButtonItemStylePlain target:self action:@selector(pressDelete)];self.navigationItem.rightBarButtonItem = self.buttonOfEdit;}
- (void)pressEdit {self.isEdit = YES;self.navigationItem.rightBarButtonItem = self.buttonOfFinish;[self.tableview setEditing:YES];self.navigationItem.leftBarButtonItem = self.buttonOfDelete;
}- (void)pressFinish {self.isEdit = NO;self.navigationItem.rightBarButtonItem = self.buttonOfEdit;[self.tableview setEditing:NO];self.navigationItem.leftBarButtonItem = nil;
}/*参数讲解:参数一:触发事件的表格视图对象参数二:用户对这个单元格执行的编辑类型参数三:表示当前单元格的位置,包含两个信息:section(第几组)、row(第几行)*/
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyleforRowAtIndexPath:(NSIndexPath *)indexPath {if (editingStyle == UITableViewCellEditingStyleDelete) {// 1. 先删除数据源中的数据[self.arrayData[indexPath.section] removeObjectAtIndex:indexPath.row];// 2. 更新表格视图(动画删除这一行)[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];}
}//- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
//    if (editingStyle == UITableViewCellEditingStyleInsert) {
//        // 1. 创建一个新的数据项(你可以替换成你自己的默认值)
//        NSString *newItem = @"新添加的内容";
//
//        // 2. 往数据源中插入(在指定 section 的对应位置)
//        [self.arrayData[indexPath.section] insertObject:newItem atIndex:indexPath.row];
//
//        // 3. 更新表格界面(带动画插入新行)
//        [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
//    }
//}/*告诉表格视图每一行在处于编辑状态时,应该支持什么操作UITableViewCellEditingStyleDeleteUITableViewCellEditingStyleInsertUITableViewCellEditingStyleNone*/
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {return UITableViewCellEditingStyleDelete ;
}- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {NSLog(@"选中单元格!%lu %lu", indexPath.section, indexPath.row);
}- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {NSLog(@"取消 选中单元格!%lu %lu", indexPath.section, indexPath.row);
}
//或取每组元素的个数(行数)
//必须要实现的协议函数
//程序在显示数据视图时会调用此函数
//p1:数据视图对象本身
//p2: 那一组需要的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {NSInteger num = [[self.arrayData objectAtIndex:section] count];return num;
}
//设定数据视图的组数,默认返回1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {return  self.arrayData.count;
}//创建单元格函数对象
//参数一:调用函数的对象
//参数二:单元格的索引,就是上面的行数与组数
/*//单元格文字赋值cell.textLabel.text = [_arrayData[indexPath.section] objectAtIndex:indexPath.row];//设置子文字标题cell.detailTextLabel.text = @"子标题";//设置图片NSString* str = [NSString stringWithFormat:@"photo0%ld.jpg",indexPath.row];cell.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:str]];*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {NSString* cellstr = @"cell";//尝试获得可复用的单元格,如果得不到就返回空/*当滚动表格时,屏幕上的单元格会离开屏幕,已经滚出屏幕的单元格不会被立刻销毁,而是存入复用迟中,当需要显示新的cell时,系统会从复用池中获取一个单元格重新使用,而不是重新创建*/UITableViewCell* cell = [self.tableview dequeueReusableCellWithIdentifier:cellstr];if (!cell) {//创建一个单元格对象//参数一:单元格样式//参数二:单元格的复用标记cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellstr];}//NSString* str = [NSString stringWithFormat:@"第%ld组,第%ld行",indexPath.section,indexPath.row];//单元格内容赋值cell.textLabel.text = self.arrayData[indexPath.section][indexPath.row];//调用创建功能按钮方法[self creatButton];return cell;
}- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {return 100;
}- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {return @"头部标题";
}- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {return @"尾部标题";
}- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {return 40;
}- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {return 40;
}@end

请添加图片描述
请添加图片描述

照片墙案例

userInteractionEnable属性介绍:

userInteractionEnabled是UIView的一个重要属性,用于控制用户是否能与该视图及其子视图进行交互(如点击、滑动、手势等)。在照片墙案,若需要对图片进行点击查看、缩放、删除等操作,必须将相关视图的该属性设为 YES(默认值也是 YES,但某些场景下可能被意外修改)。

这个属性是属于UIView的,是BOOL类型的,决定UIView是否接受有关touch和keyBoard的相关操作,然后UIView就可以通过相应的一些方法来处理。

其次我们需要创建一个手势识别器UITapGestureRecognizer

//给每个控件添加手势
UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(press:)];//创建一个手势识别器,并且添加相应的方法
tap.numberOfTapsRequired = 1;//设置触摸次数
tap.numberOfTouchesRequired = 1;//设置触摸点个数
[iView addGestureRecognizer:tap];//添加手势识别器到view中
//触摸后实现方法函数
- (void) press:(UITapGestureRecognizer*) tap {//强制转换类型UIImageView* imageView = (UIImageView*) tap.view;//创建即将推出的视图控制器ShowImage* imageShow = [[ShowImage alloc] init];//点击的图像视图赋值imageShow.imageTag = imageView.tag;imageShow.image = imageView.image;//将控制器推出[self.navigationController pushViewController:imageShow animated:YES];
}

在SceneDelegate文件中,设置导航控制器

#import "SceneDelegate.h"
#import "VCRoot.h"
#import "VCImageShow.h"
@interface SceneDelegate ()@end@implementation SceneDelegate- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {//导航控制器照片结构UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:[VCRoot new]];self.window.rootViewController = nav;[self.window makeKeyAndVisible];
}- (void)sceneDidDisconnect:(UIScene *)scene {// Called as the scene is being released by the system.// This occurs shortly after the scene enters the background, or when its session is discarded.// Release any resources associated with this scene that can be re-created the next time the scene connects.// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}- (void)sceneDidBecomeActive:(UIScene *)scene {// Called when the scene has moved from an inactive state to an active state.// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}- (void)sceneWillResignActive:(UIScene *)scene {// Called when the scene will move from an active state to an inactive state.// This may occur due to temporary interruptions (ex. an incoming phone call).
}- (void)sceneWillEnterForeground:(UIScene *)scene {// Called as the scene transitions from the background to the foreground.// Use this method to undo the changes made on entering the background.
}- (void)sceneDidEnterBackground:(UIScene *)scene {// Called as the scene transitions from the foreground to the background.// Use this method to save data, release shared resources, and store enough scene-specific state information// to restore the scene back to its current state.
}@end

在VCRoot中设置照片墙

#import "VCRoot.h"
#import "VCImageShow.h"
@interface VCRoot ()@end@implementation VCRoot- (void)viewDidLoad {[super viewDidLoad];self.title = @"照片墙";self.view.backgroundColor = [UIColor whiteColor];self.navigationController.navigationBar.translucent = YES;self.navigationController.navigationBar.barTintColor = [UIColor yellowColor];//创建一个滚动视图并设置位置和画布大小UIScrollView* sv = [UIScrollView new];sv.frame = CGRectMake(5, 10, 394, 852);sv.contentSize = CGSizeMake(394, 852 * 1.5);sv.showsVerticalScrollIndicator = NO;//打开交互事件sv.userInteractionEnabled = YES;//利用循环给根视图上添加照片对象for (int i = 0; i < 9; i++) {UIImage* image = [UIImage imageNamed:[NSString stringWithFormat:@"photo0%d.jpg",i + 1]];UIImageView* view = [[UIImageView alloc] initWithImage:image];view.frame = CGRectMake(10 + (i % 3) * 125, (i / 3) * 165, 110, 150);[sv addSubview:view];view.userInteractionEnabled = YES;//创建点击手势UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pressTap:)];//单次点击tap.numberOfTapsRequired = 1;//单个手指tap.numberOfTouchesRequired = 1;[view addGestureRecognizer:tap];view.tag = 101 + i;}[self.view addSubview: sv];
}//方法3:
- (void)pressTap:(UITapGestureRecognizer* )tap {UIImageView* imageView = (UIImageView*)tap.view;VCImageShow* imageshow = [VCImageShow new];imageshow.imageTag = imageView.tag;[self.navigationController pushViewController:imageshow animated:YES];}//方法2:
//- (void)pressTap:(UITapGestureRecognizer* )tap {
//    UIImageView* imageView = (UIImageView*)tap.view;
//    //创建显示视图控制器
//    VCImageShow* imageshow = [[VCImageShow alloc] init];
//    //点击的图像视图赋值
//    //imageshow.imageView = imageView;//不可行
//    imageshow.image = imageView.image;
//    //将视图控制器推出
//    [self.navigationController pushViewController:imageshow animated:YES];
//    
//    
//}
/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

接下来需要解决如何将被点击的视图传入到展示图片的页面,这里要注意,不可以直接传视图对象,因为一个人视图对象只能有一个根视图,当我们把视图添加到新的父视图上时,会从原来的父亲视图删除掉

//
//  VCImageShow.m
//  PhotoWall
//
//  Created by xiaoli pop on 2025/6/3.
//#import "VCImageShow.h"@interface VCImageShow ()@end@implementation VCImageShow- (void)viewDidLoad {[super viewDidLoad];self.title = @"图片展示";self.imageView = [[UIImageView alloc] init];self.imageView.frame = [[UIScreen mainScreen] bounds];//方法2://self.imageView.image = self.image;//方法3:self.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"photo0%lu.jpg",(unsigned long)(self.imageTag - 100) ]];/*一个视图对象只能有一个根视图当我们把视图添加到新的父视图上时会从原来的父亲视图删除掉*/[self.view addSubview:self.imageView];}/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end
  • 实现效果

请添加图片描述

点击图片就会跳转一个新页面,内容就是选中的图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/83034.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/83034.shtml
英文地址,请注明出处:http://en.pswp.cn/web/83034.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Microsoft前后端不分离编程新风向:cshtml

文章目录 什么是CSHTML&#xff1f;基础语法内联表达式代码块控制结构 布局页面_ViewStart.cshtml_Layout.cshtml使用布局 模型绑定强类型视图模型集合 HTML辅助方法基本表单验证 局部视图创建局部视图使用局部视图 高级特性视图组件依赖注入Tag Helpers 性能优化缓存捆绑和压缩…

【SpringBoot+SpringCloud】Linux配置nacos踩坑大全

*建议在开发时使用Linux环境下搭建nacos 1.在nacos官网找到搭配SpringBoot和SpringCloud的版本 2.Nacos 依赖 Java 环境来运行&#xff0c;需要在linux系统中安装JDK 1.8 3.按照Nacos官网步骤安装&#xff0c;防火墙配置开放8848和9848端口 客户端拥有相同的计算逻辑&…

如何在 Java 中优雅地使用 Redisson 实现分布式锁

分布式系统中&#xff0c;节点并发访问共享资源可能导致数据一致性问题。分布式锁是常见的解决方案&#xff0c;可确保操作原子性。Redisson是基于Redis的Java分布式对象库&#xff0c;提供多种分布式同步工具&#xff0c;包括分布式锁。Redisson与Redis&#xff08;实时数据平…

pikachu靶场通关笔记20 SQL注入03-搜索型注入(GET)

目录 一、SQL注入 二、搜索型注入 三、源码分析 1、渗透思路1 2、渗透思路2 四、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入百分号单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取…

mac:大模型系列测试

0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何&#xff0c;是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试&#xff0c;是可以跑通文章里面的代码。训练速度也是很快的。 注意…

A Survey on the Memory Mechanism of Large Language Model based Agents

目录 摘要Abstract1. LLM-Based Agent的Memory1.1 基础概念1.2 用于解释Memory的例子1.3 智能体记忆的定义1.3.1 狭义定义(肯定不用这个定义)1.3.2 广义定义 1.4 记忆协助下智能体与环境的交互过程1.4.1 记忆写入1.4.2 记忆管理1.4.3 记忆读取1.4.4 总过程 2. 如何实现智能体记…

搭建 Serverless 架构

✅ 一、理解 Serverless 架构核心概念 核心理念&#xff1a; 无需管理服务器&#xff1a;只需编写业务逻辑&#xff0c;部署后由云平台托管运行环境。 事件驱动&#xff08;Event-driven&#xff09; 按需计费&#xff08;按调用次数/资源消耗&#xff09; 高可扩展性与自动…

Git仓库的创建

Git服务器准备 假设Git所在服务器为Ubuntu系统&#xff0c;IP地址10.17.1.5。 一. 准备运行git服务的git用户&#xff0c;这里用户名就直接设定为git。 1. 创建一个git用户组&#xff0c;并创建git用户。 sudo groupadd git sudo useradd git -g git 2. 创建git用户目录&…

电脑提示dll文件缺失怎么办 dll修复方法

当你在使用某些应用程序或启动电脑时&#xff0c;看到提示“DLL文件缺失”的错误信息&#xff0c;这通常意味着某个必要的动态链接库&#xff08;DLL&#xff09;文件无法被找到或加载&#xff0c;导致软件无法正常运行。本文将详细介绍如何排查和修复DLL文件缺失的问题&#x…

使用 Rest-Assured 和 TestNG 进行购物车功能的 API 自动化测试

这段代码使用了 Rest-Assured 进行 API 测试&#xff0c;结合 TestNG 框架执行多个 HTTP 请求并进行断言验证。以下是对每个测试方法的详细解释&#xff0c;包括代码逻辑和测试目的。 1. test01() 方法 - 提取响应数据 Test public void test01() {String jsonData "{\&…

【设计模式-4.7】行为型——备忘录模式

说明&#xff1a;本文介绍行为型设计模式之一的备忘录模式 定义 备忘录模式&#xff08;Memento Pattern&#xff09;又叫作快照模式&#xff08;Snapshot Pattern&#xff09;或令牌模式&#xff08;Token Pattern&#xff09;指在不破坏封装的前提下&#xff0c;捕获一个对…

2025年渗透测试面试题总结-天融信[社招]渗透测试工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 天融信[社招]渗透测试工程师 一、Java Spring Boot组件漏洞 1. CVE-2018-1270&#xff08;WebSocket RCE&…

华为OD机考-内存冷热标记-多条件排序

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextInt();int[] arr new int[a];for(int…

PPT转图片拼贴工具 v3.0

软件介绍 这个软件就是将PPT文件转换为图片并且拼接起来。 这个代码支持导入单个文件也支持导入文件夹 但是目前还没有解决可视化界面问题。 效果展示 软件源码 import os import re import win32com.client from PIL import Image from typing import List, Uniondef con…

NLP学习路线图(三十):微调策略

在自然语言处理领域,预训练语言模型(如BERT、GPT、T5)已成为基础设施。但如何让这些“通才”模型蜕变为特定任务的“专家”?微调策略正是关键所在。本文将深入剖析七种核心微调技术及其演进逻辑。 一、基础概念:为什么需要微调? 预训练模型在海量语料上学习了通用语言表…

讲述我的plc自学之路 第十三章

我和lora都是那种理想主义者&#xff0c;这是我们的共同之处。但是lora比我要更文艺一些&#xff0c;她读的书毕竟比我多&#xff0c;上的又是名校。受北大人文气息的熏陶&#xff0c;她总是对爱情充满了太多幻想。 “说说你的过往吧&#xff0c;lora。”我给lora倒了一杯啤酒&…

GPU虚拟化

引言 现有如下环境&#xff08;注意相关配置&#xff1a;只有一个k8s节点&#xff0c;且该节点上只有一张GPU卡&#xff09;&#xff1a; // k8s版本 $ kubectl version Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.7&…

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)

旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据&#xff01;该数据集源自2025年4月发表于《地理学报》的论文成果…

AI智能驱动浏览器工具Browser Use详解

前言 在之前关于 AI 测试相关的几篇文章中,我们分别介绍了通过 playwright-mcp,以及 midscene.js、magentic ui 等几个不同的 AI 浏览器工具,实现 AI 驱动自动化测试的方法介绍。而其实在这些不断涌现的新工具出现之前,还有一个更早推出(2024.11),也同样还在不断完善的…

新成果:GaN基VCSEL动态物理模型开发

作为高速数据传输与光电信号处理的核心器件&#xff0c;垂直腔面发射激光器&#xff08;VCSEL&#xff09;在高速光通信、激光雷达等领域应用广泛&#xff0c;其动态特性直接关联器件调制速率及稳定性等关键参数。近期&#xff0c;天津赛米卡尔科技有限公司技术团队开发了GaN基…