您现在的位置是:首页 >技术教程 >【iOS】UI学习总结网站首页技术教程

【iOS】UI学习总结

温柔何曾赋我 2024-08-12 00:01:02
简介【iOS】UI学习总结


前言

近期学习了有关UI的相关内容,特此撰写博客总结

一、UIView

UIView是一种核心的视图类,用于构建用户界面。它是UIKit框架中的一部分,是iOS应用程序中所有可见元素的基本构建块。

  • 创建一个UIView

在这里插入图片描述

  • UIView的一些基本属性
    在这里插入图片描述在这里插入图片描述
    UIView的层级关系:
  • 创建三个视图对象:

在这里插入图片描述

  • 对于创建的子视图对象,一定要将其添加到父视图中才能显示
    在这里插入图片描述
  • 谁先被添加到子视图,谁就可以被覆盖,也就是后面添加的视图可以覆盖前面添加的视图
    在这里插入图片描述

二、UIViewController基础

我们创建我们的项目时会自动帮我们创建一个ViewController.m的文件,但是我们也可以不使用它。我们可以创建一个以UIViewController的父类的Cocoa类,那么这里就引申出一个问题

  • 我们的项目调用过程是怎么样的
  • 我们的新建的Cocoa类是怎么被执行的

这里我们先看一个例子:
我们的SceneDelegate.m
在这里插入图片描述
我们的AViewController.m文件
在这里插入图片描述
显示结果:
在这里插入图片描述
我们可以知道会显示红色,但是这两个不同的文件之间是怎么关联的呢?

首先我们需要知道我们的项目大致的执行顺序是 AppDelegate.m → SceneDelegate.m → ViewController.m,目前笔者暂时还没用过AppDelegate.m,在这里重点讲解一下另外两种

  • 我们会在程序的开始通过SceneDelegate.m方法配置场景的窗口、根视图控制器,通过这些操作来与我们的ViewController.m进行关联

这里给出我们的例子:

AViewController *aViewController = [[AViewController alloc] init];
// 创建视图控制器对象

self.window.rootViewController = aViewController;
// 将视图控制器设置为窗口的根视图控制器,视图会自动加载并显示

// 在AViewController.m文件中实现viewDidLoad方法
- (void)viewDidLoad {
    [super viewDidLoad];
    // 在这里进行视图的初始化和配置操作
    // ...
}

我们这里的AViewController.m就是以ViewController.m为父类的一个Cocoa类

总结一下:如果我们同各国代码手动创建了一个视图控制器对象,并将其设置为窗口的根视图控制器,系统会在应用程序启动时自动加载并显示该视图控制器的视图,并调用 viewDidLoad 方法。

tip:调用 viewDidLoad 方法的情况

我们在这里既然提到了我们的viewdidiload方法是如何被调用的,我们在这里就总结一下所有情况:

1、当一个视图控制器被推入导航堆栈时

UIViewController *viewController = [[UIViewController alloc] init];
// 创建视图控制器对象

[self.navigationController pushViewController:viewController animated:YES];
// 将视图控制器推入导航堆栈,视图会自动加载并显示

// 在视图控制器的.m文件中实现viewDidLoad方法
- (void)viewDidLoad {
    [super viewDidLoad];
    // 在这里进行视图的初始化和配置操作
    // ...
}

我们上面的是模版,接下来我们给出示例:
在这里插入图片描述

例如我们想在我们导航栏控制器的第二个页面切换到第三个页面,就需要用pushViewController: 来实现

当我们使用这个方法,我们的程序就会自动加载并显示视图控制器的视图,并调用推入堆栈的视图控制器的Cocoa类的 viewDidLoad 方法

2、当使用模态呈现(present)一个视图控制器时

UIViewController *viewController = [[UIViewController alloc] init];
// 创建视图控制器对象

[self presentViewController:viewController animated:YES completion:nil];
// 以模态方式呈现视图控制器,视图会自动加载并显示

// 在视图控制器的.m文件中实现viewDidLoad方法
- (void)viewDidLoad {
    [super viewDidLoad];
    // 在这里进行视图的初始化和配置操作
    // ...
}

我们上面的是模版,接下来我们给出示例:
在这里插入图片描述
当我们调用presentViewController: 方法时,也会自动调用被呈现的视图的viewdidload方法

3、通过代码手动创建并设置根视图控制器

这种情况也就是我们在UIViewController基础阐述的情况,这里就不再赘述了

三、UIIamge

UIImage是UIKit框架中的一个类,用于表示图像或照片。它是iOS开发中处理图像的核心类之一。

// 1. 创建UIImageView实例
UIImageView *customImageView = [[UIImageView alloc] init];

// 2. 设置UIImageView的frame或约束,决定图片视图的位置和大小
customImageView.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);

// 3. 创建UIImage实例,用于显示在UIImageView上的自定义图片
UIImage *customImage = [UIImage imageNamed:@"customImage.jpg"];

// 4. 将自定义图片赋值给UIImageView的image属性,以显示在界面中
customImageView.image = customImage;

// 5. 配置UIImageView的其他属性,如contentMode、clipsToBounds等,根据需要进行设置
customImageView.contentMode = UIViewContentModeScaleAspectFit;
customImageView.clipsToBounds = YES;

// 6. 将UIImageView添加到视图层次中,以便在界面中显示出来
[self.view addSubview:customImageView];

// 可选步骤:
// 7. 配置视图控制器的标题(如果需要)
self.title = @"图片显示";

// 8. 配置导航栏(如果需要)
// self.navigationController.navigationBar.translucent = NO;
// self.navigationController.navigationBar.backgroundColor = [UIColor whiteColor];

// 注意:以上代码为Objective-C的示例,如果你正在使用Swift进行开发,相应的语法会有所不同,但概念和步骤是类似的。

  • 这里需要注意一点就是如果我们要显示我们的图片,首先要创建一个UIImage实例,将我们的图片通过imageNamed方法赋值给UIImage
  • 但是UIImage实例并不能显示在我们的视图上,所以我们必须要创建一个UIImageView实例,将自定义图片赋值给UIImageView的image属性,以显示在界面中

四、UIButton

UIButton是UIKit框架中的一个类,它是继承自UIView的子类,用于创建可点击的按钮控件。UIButton通常用于响应用户的触摸事件,并执行相应的操作或触发特定的动作。

特点与功能:

  • 多种按钮类型:
    在这里插入图片描述
    可以创建圆角按钮与普通按钮等按钮类型,通过buttonWithType: 方法创建
    在这里插入图片描述
  • 可定制的外观:

同时因为其是UIView,它同样拥有UIView的frame属性与color等属性,同时它还支持不同状态下的外观设置。
如正常状态、高亮状态、选中状态等,可以根据按钮的状态改变外观以提供更好的用户反馈。
例如:
在这里插入图片描述
正常状态如图:
在这里插入图片描述
按下状态如图:
在这里插入图片描述

  • 响应用户交互
    在这里插入图片描述
    通过addTarget:action:forControlEvents:方法将目标对象与按钮的特定事件关联起来,一般我们的forControlEvents选择 UIControlEventTouchUpInside,就是当你点击按钮后手指是在按钮的范围内离开的,就触发action事件

五、定时器与视图对象

定时器的开始函数:
一般是在.h文件中定义一个NSTimer型变量,然后在.m文件通过scheduledTimerWithTimeInterval: 调用
在这里插入图片描述

定时器的结束函数:
在这里插入图片描述
而我们定时器的具体使用是通过按钮的addtarget:方法来具体实现的
例如:
在这里插入图片描述

六、UIAlertController

我们的UIAlertController有两种形式,一种是警告框,一种是操作表
1、警告框

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"标题" message:@"消息内容" preferredStyle:UIAlertControllerStyleAlert];

// 添加操作按钮
UIAlertAction *action = [UIAlertAction actionWithTitle:@"按钮标题" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    // 在按钮点击后执行的代码
}];
//将确认按钮添加到我们的警告框中
[alertController addAction:action];

// 添加取消按钮
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
//将取消按钮添加到我们的警告框中
[alertController addAction:cancelAction];

// 在视图控制器中呈现警告框(通过这个方法是来其弹出)
[self presentViewController:alertController animated:YES completion:nil];

我们还可以在警告框里添加我们的文本框

[self.alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
            textField.placeholder = @"请填写你的反馈信息";
        }];

最终的效果如图:
在这里插入图片描述
2、操作表

self.alertSheet = [UIAlertController alertControllerWithTitle:@"标题" message:@"一些信息" preferredStyle:UIAlertControllerStyleActionSheet];
    //其实alertSheet唯一与警告对话框的区别就是我们的preferredStyle的样式不同
        //这里一定要记得default的adj意思是默认
UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"项目1" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            NSLog(@"点击了项目1");
        }];
UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"项目2" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            NSLog(@"点击了项目2");
        }];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            NSLog(@"取消哩");
        }];
        //添加动作
[self.alertSheet addAction:action1];
[self.alertSheet addAction:action2];
[self.alertSheet addAction:cancel];
        
        //presentViewController:显示的视图控制器对象
[self presentViewController:self.alertSheet animated:YES completion:nil];

与我们的警告框类似,最后的效果如图:
在这里插入图片描述
可以看到我们的两种样式都有取消按钮,取消按钮是通过创建UIAlertAction的变量时的style的不同来实现的
例如取消按钮的style的就是UIAlertActionStyleCancel
默认按钮的style就是UIAlertActionStyleDefault

两种样式的不同是通过不同的preferredStyle:来实现的

  • 警告框的是UIAlertControllerStyleAlert
  • 操作表的是UIAlertControllerStyleActionSheet

七、UITextField

我们先给出我们一些常用的UITextField属性

text:文本字段中显示的文本内容。
placeholder:当文本字段为空时显示的占位符文本。
textColor:文本的颜色。
font:文本的字体。
secureTextEntry:设置为YES时,输入的文本将被隐藏,通常用于密码输入。
keyboardType:键盘类型,如默认键盘、数字键盘、邮箱键盘等。
returnKeyType:返回键类型,如Done、Next、Go等。
autocapitalizationType:自动大写设置,控制文本是否自动大写。
autocorrectionType:自动纠正设置,控制是否自动纠正文本。
clearButtonMode:清除按钮的显示模式,控制何时显示清除按钮。
delegate:UITextFieldDelegate委托对象,用于处理文本字段的各种事件和行为。

我们在我们接口部分定义我们的属性在这里插入图片描述

我们要使用我们的文本框时,我们要先创建一个文本框对象
在这里插入图片描述
给出我们使用属性的具体例子:
在这里插入图片描述

我们还可以在接口部分调用我们的协议,然后再实现部分实现我们的协议
接口部分:
在这里插入图片描述
实现部分实现协议:

//点击空白处回收键盘
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //使虚拟键盘回收,不再作为第一消息响应者
    [self.textField resignFirstResponder];
}


//如果返回值为YES,可以进行输入,默认为YES,结束输入也相同,
- (void)textFieldDidBeginEditing:(UITextField *)textField {
    NSLog(@"已经开始编辑了");
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    //结束时可以清空数据
    //self.textField.text = @"";
    //可以根据情况决定是否清空
    NSLog(@"已经结束编辑");
}

//是否可以进行输入
//如果返回值为YES,可以进行输入,默认为YES,
//NO:不能输入文字
//当权限不够可以弹出NO
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    return YES;
}

//是否可以结束输入
//如果返回值为YES,可以结束输入,默认为YES,
//NO:不能结束输入文字,常用于提示用户输入不合法,不合法键盘就不退回去,就得重新修改文本
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    return YES;
}

八、登陆界面案例

我们先来看一下我们的实现效果:
在这里插入图片描述

看一下我们的接口部分
在这里插入图片描述

再来看一下我们的实现部分:

  • 先给出我们的基本实现界面
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    //用户名提示标签创建
    _lbUserName = [[UILabel alloc] init];
    _lbUserName.frame = CGRectMake(20, 150, 80, 40);
    _lbUserName.text = @"用户名";
    _lbUserName.font = [UIFont boldSystemFontOfSize:20];
    _lbUserName.textAlignment = NSTextAlignmentLeft;
    
    //用户密码提示
    _lbPassword = [[UILabel alloc] init];
    _lbPassword.frame = CGRectMake(20, 200, 80, 40);
    _lbPassword.text = @"密码";
    _lbPassword.font = [UIFont boldSystemFontOfSize:20];
    _lbPassword.textAlignment = NSTextAlignmentLeft;
    
    //用户名输入框
    _tfUserName = [[UITextField alloc]init];
    _tfUserName.frame = CGRectMake(120, 150, 180, 40);
    _tfUserName.placeholder = @"请输入用户名";
    _tfUserName.borderStyle = UITextBorderStyleRoundedRect;
    
    //密码输入框
    _tfPassword = [[UITextField alloc] init];
    _tfPassword.frame = CGRectMake(120, 200, 180, 40);
    _tfPassword.placeholder = @"请输入密码";
    _tfPassword.borderStyle = UITextBorderStyleRoundedRect;
    _tfPassword.secureTextEntry = YES;
    
    //登陆与注册btn创建
    _btLogin = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    _btLogin.frame = CGRectMake(120, 300, 80, 40);
    //UIControlStateNormal 意思是选中状态
    [_btLogin setTitle:@"登陆" forState:UIControlStateNormal];
    [_btLogin addTarget:self action:@selector(pressLogin) forControlEvents:UIControlEventTouchUpInside];
    
    _btRegister  = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    _btRegister.frame = CGRectMake(120, 360, 80, 40);
    [_btRegister setTitle:@"注册" forState:UIControlStateNormal];
    [_btRegister addTarget:self action:@selector(pressRegister) forControlEvents:UIControlEventTouchUpInside];
    
    //所有控件添加到视图中显示
    [self.view addSubview:_lbUserName];
    [self.view addSubview:_lbPassword];
    [self.view addSubview:_btRegister];
    [self.view addSubview:_btLogin];
    [self.view addSubview:_tfPassword];
    [self.view addSubview:_tfUserName];
}

接下来看看我们如何具体实现我们的登陆操作,就像c语言中的链表实现我们的登陆操作一样

//登陆事件函数
 - (void)pressLogin {
    NSString *strName = @"Summer";
    NSString *strPass = @"123456";
    
    //获取输入框中的用户名文字
    NSString *strTextName =  _tfUserName.text;
    NSString *strTextPass =  _tfPassword.text;
    
    if ([strName isEqualToString:strTextName] && [strPass isEqualToString:strTextPass]) {
        NSLog(@"用户名密码正确");
        
        UIAlertController *tishi = [UIAlertController alertControllerWithTitle:@"提示" message:@"登陆成功" preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction *conform = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            NSLog(@"确认");
        }];
            
            [tishi addAction:conform];
            [self presentViewController:tishi animated:NO completion:nil];
        
    }
    else {
        UIAlertController *tishi = [UIAlertController alertControllerWithTitle:@"提示" message:@"登陆失败" preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction *conform = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            NSLog(@"确认");
        }];
            [tishi addAction:conform];
            [self presentViewController:tishi animated:NO completion:nil];
    }
    
}

同样需要获取我们的账号密码,然后验证我们的账号

  • 需要先用NSString型获取我们输入的的账号密码
NSString *strTextName =  _tfUserName.text;
NSString *strTextPass =  _tfPassword.text;
  • 然后通过if判断我们是否登陆成功
if ([strName isEqualToString:strTextName] && [strPass isEqualToString:strTextPass])
  • 登陆成功则显示登陆成功提示框,失败则显示登陆失败提示框

在这里插入图片描述

  • 通过一个函数来回收我们的键盘

在这里插入图片描述

具体效果:
在这里插入图片描述

九、UIScrollView

UIScrollView是一个强大的视图容器,它提供了许多属性来控制和配置其行为和外观。以下是UIScrollView的一些常见属性:

  • contentSize: 指定滚动视图内容的大小。它是一个CGSize类型的属性,用于设置滚动视图可滚动的区域大小。
  • contentOffset:
    获取或设置滚动视图内容的偏移量。它是一个CGPoint类型的属性,表示滚动视图当前显示的内容在整个内容区域中的偏移量。
  • contentInset:
    设置滚动视图内容的内边距。它是一个UIEdgeInsets类型的属性,用于在滚动视图的边缘周围添加额外的内边距。
  • delegate:
    用于设置UIScrollView的委托对象,以便响应滚动和缩放事件。委托对象需要遵循UIScrollViewDelegate协议。
  • bounces: 指定滚动视图是否具有弹簧效果。设置为YES时,在滚动到边缘时会产生弹簧效果,设置为NO时禁用弹簧效果。
  • pagingEnabled: 指定滚动视图是否启用分页滚动。设置为YES时,滚动视图会按页进行滚动,每次滚动一个整页的内容。
  • showsHorizontalScrollIndicator和showsVerticalScrollIndicator:
    用于控制水平和垂直滚动指示器的显示。设置为YES时,滚动指示器将可见,设置为NO时将隐藏。
  • minimumZoomScale和maximumZoomScale:
    用于设置滚动视图的最小和最大缩放比例。通过设置这些属性,可以控制滚动视图上内容的缩放级别。

在这里比较主要的就是frame属性与contentSize属性

我们的滚动视图能滚动的次数实际上就是我们的 contentSize / frame

在这里我给出例子:
在这里插入图片描述
在这里插入图片描述
这样以来,实际上我们的滚动视图就可以滚动三次

然后另外就是讲我们的图片放入我们的滚动视图
在这里插入图片描述

接下来给出基本滚动视图的完整代码


- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    //创建滚动视图的位置
    self.scrollView = [[UIScrollView alloc] init];
    
    //设定滚动视图的位置
    self.scrollView.frame = CGRectMake(0, 0, self.view.bounds.size.width, [UIScreen mainScreen].bounds.size.height);
    
    //设定滚动视图的弹动效果
    self.scrollView.bounces = YES;
    
    //是否允许通过点击屏幕让滚动视图响应时间
    //yes:滚动视图可以接受触碰时间
    //no:不接受触屏事件
    self.scrollView.userInteractionEnabled = YES;
    
    //纵向画布
    self.scrollView.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height * 3);
    
    for (int i = 0; i < 3; i++) {
        NSString *strName = [NSString stringWithFormat:@"%d.jpg", i + 1];
        //创建图片,将自定义图片导入视图
        UIImage *image = [UIImage imageNamed:strName];
        //创建视图
        //创建image,将image赋给imageView视图
        UIImageView *iView = [[UIImageView alloc] init];
        iView.image = image;
        iView.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height * i, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
        [self.scrollView addSubview:iView];
    }
    
    [self.view addSubview:self.scrollView];
    
    //按页滚动效果
    self.scrollView.pagingEnabled = YES;
    
    //滚动视图画布的移动位置,偏移位置
    self.scrollView.contentOffset = CGPointMake(0, 0);
    
    //协议函数部分
    //将当前视图控制器作为代理对象
    self.scrollView.delegate = self;
}

给出一些它的高级属性:

//当滚动视图移动时,只要offset坐标发生变化,都会调用此函数
//参数:调用此协议的滚动视图对象
//可以使用此函数来监控滚动视图的位置
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    NSLog(@"y = %f", scrollView.contentOffset.y);
}

//但滚动视图结束拖拽时,调用此函数
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    NSLog(@"Did End Drag!");
}

//滚动视图即将开始拖动时
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    NSLog(@"Will Begin Drag!");
}

//视图即将结束拖动时调用
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    NSLog(@"Will End Drag");
}

//视图即将减速时调用
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
    NSLog(@"Will Begin Decelerate");
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    NSLog(@"视图停止移动");
}

//点击画布外就会回到初始位置
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//    self.scrollView.contentOffset = CGPointMake(0, 0);
    //动画滑动逐步回到开始的位置
    [self.scrollView scrollRectToVisible:CGRectMake(0 , 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) animated:YES];
}

十、导航栏控制器(UINavigationController)

首先我们先来看一下效果图:
在这里插入图片描述
可以考到我们的界面多了我们的导航栏,我们先来看一下我们该如何设置我们的导航栏:

//    //创建一个根视图控制器
    VCRoot *root = [[VCRoot alloc] init];
    
    //导航控制器,navigate的意思是导航
    //创建导航控制器
    //导航控制器主要用来管理多个视图控制器的切换
    //层级的方式来管理多个视图控制器
    //创建控制器时,一定要有一个根视图控制器
    //参数一:作为导航控制器的根视图控制器
    
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:root];
    
    //将window的根视图控制器设置为导航控制器
    //就是将当前窗口的根视图控制器设置为导航控制器
    self.window.rootViewController = nav;
//    [self.window makeKeyAndVisible];
//    创建一个名为 root 的 VCRoot 视图控制器对象,并将其设置为 nav 导航栏控制器的根视图控制器。然后,将 nav 导航栏控制器对象设置为应用程序窗口的根视图控制器。这样,当应用程序启动时,它将显示 nav 导航栏控制器的界面,并将 root 视图控制器作为导航堆栈的根视图控制器,从而实现 iOS 应用程序的导航功能。
    

在这段代码中,我们创建了一个nav变量,它的类型是 UINavigationController,我们将root视图作为nav的根视图控制器,就相当于将root作为我们的导航栏控制器中第一个显示的视图控制器。

根视图控制器
我们在这里解释一下根视图控制器的概念 :

根视图控制器是应用程序的主要界面管理者,它负责设置应用程序的初始界面、协调子视图控制器的显示和切换,以及处理应用程序的生命周期事件

根视图控制器通常是导航控制器(UINavigationController)、标签栏控制器(UITabBarController)或分栏控制器(UISplitViewController)等容器控制器,它们可以管理一个或多个子视图控制器。

我们以我们的导航栏控制器为例讲讲我们的根视图控制器:

  • 初始界面:
    根视图控制器是我们使用导航栏控制器时第一个显示的视图控制器,他是应用程序启动后的初始界面,是用户首次看到的界面
  • 导航堆栈的根结点:
    导航控制器维护了一个视图控制器的堆栈,根视图控制器是导航堆栈的根节点。其他视图控制器可以通过导航控制器进行切换和导航。
    我们在前文已经提过,当我们将一个视图控制器推入导航堆栈时,会调用对应的viewdidload方法,而根视图控制器就是导航堆栈的起点
  • 历史记录管理:
    导航控制器允许用户在不同的视图控制器之间进行导航,根视图控制器记录了导航过程中的历史记录。用户可以通过返回按钮回到根视图控制器,从而回到导航的起点。
  • 导航栏的定制:
    根视图控制器决定了导航栏的显示样式和内容。你可以在根视图控制器中设置导航栏的标题、按钮、背景等,从而影响整个导航控制器中的导航栏外观。

总的来说,根视图控制器是导航控制器中的第一个视图控制器,它起到初始界面、导航堆栈的根节点、历史记录管理和导航栏定制等多个作用。它是导航控制器的核心组成部分,通过它可以构建出具有导航功能的应用程序界面。


那么我们将导航控制器的根视图设置完毕后,我们肯定可以试着去切换导航栏控制器的界面,我们这里先给出我们导航栏的根视图的具体代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    
    //设置导航栏的透明度
    //默认透明度为YES,可透明的的
    //NO:使导航栏不透明
    //要两个参数一起设才能出现黑色
//    self.navigationController.navigationBar.translucent = NO;
//    self.navigationController.navigationBar.barStyle = UIBarStyleBlack;

    
    //设置导航栏风格
    self.navigationController.navigationBar.barStyle = UIBarStyleDefault;
    
    //设置导航栏的颜色
    self.navigationController.navigationBar.tintColor = [UIColor redColor];

    //    self.navigationController.navigationBar.barTintColor = [UIColor grayColor];

//        self.navigationController.navigationBar.tintColor = [UIColor greenColor];
    
    //隐藏导航栏
//    self.navigationController.navigationBar.hidden = YES;
    
    //工具栏
    self.navigationController.toolbarHidden = NO;
    
    self.navigationController.toolbar.translucent = NO;
    //对于工具栏,因为现在已经不常使用,所以我们这里不再对其进行使用,但his要知道我们可以忘工具栏里面添加按钮,如果要添加多个按钮,则要创建NSArray按钮数组
    
    
    
    self.view.backgroundColor = [UIColor greenColor];
    
    self.title = @"根视图";
    
    UIBarButtonItem *next = [[UIBarButtonItem alloc] initWithTitle:@"1" style:UIBarButtonItemStylePlain target:self action:@selector(pressNext)];
    
    self.navigationItem.rightBarButtonItem = next;
}

我们可以看到我们的倒数第二行的按钮中的action为pressNext,也就是说,我们需要在我们的当前视图的方法中定义函数并调用,才能切换到下一级视图,接下来笔者给出pressNext的具体代码:
在这里插入图片描述
可以看到当我们将下一级视图推入栈中时,系统会自动调用并加载下一级视图,这点知识我们在上文中也有提到

这里给出下一级视图的代码:
在这里插入图片描述
可以看到与上一级视图相同,我们要切换到再下一级视图,依然需要在当前视图中创建下一级视图的变量,然后将其推入栈中

注意:
在同一个导航控制器堆栈中的视图控制器,它们的 self.navigationController 属性是相同的。因为这些视图控制器都属于同一个导航控制器,它们共享同一个导航堆栈,因此它们的 navigationController 属性指向同一个导航控制器对象。

这就解释了为什么我们最后的推入栈中的代码调用对象永远是self.navigationController

第一级视图控制器:
在这里插入图片描述
点右上的1可进入下一级
在这里插入图片描述
点根视图可返回上一级

十一、UITabBarController(分栏控制器)

我们这里先给出分栏控制器的样例:
请添加图片描述
这底部的几个选项就是我们的分栏控制器,我们还可以配合导航栏对其进行操作,这就像我们qq中的切换消息与动态的功能

我们这里总结一下创建分栏控制器的几个步骤:

1、创建视图控制器
首先,创建需要显示在UITabBarController中的各个视图控制器

UIViewController *viewController1 = [[UIViewController alloc] init];
UIViewController *viewController2 = [[UIViewController alloc] init];
// 创建更多的视图控制器...

2、设置各个视图控制器的属性:
根据需要,可以设置每个视图控制器的标题、图标等属性。

viewController1.title = @"Tab 1";
viewController1.tabBarItem.image = [UIImage imageNamed:@"tab1_icon"];
viewController2.title = @"Tab 2";
viewController2.tabBarItem.image = [UIImage imageNamed:@"tab2_icon"];
// 设置更多的视图控制器属性...

3、创建UITabBarController对象:
创建UITabBarController对象,并将之前创建的视图控制器添加到UITabBarController中。
这里有两种方法:
一种是将所有视图控制器添加到数组中,再将数组添加到tbController.viewControllers

NSArray *arrayVC = [NSArray arrayWithObjects:vcFirst, vcSecond, vcThird, vcFourth, vcFifth, vcSixth, nil];
UITabBarController *tbController = [[UITabBarController alloc] init];
tbController.viewControllers = arrayVC;

另一种是直接添加:

UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = @[viewController1, viewController2];
// 添加更多的视图控制器...

4、设置UITabBarController为根视图控制器
将UITabBarController设置为应用程序窗口的根视图控制器。这点与导航栏控制器相同

self.window.rootViewController = tabBarController;

5、再定义一些分栏控制器选项卡的外观
在这里插入图片描述

还可以修改选项卡按钮的风格
在这里插入图片描述

十二、照片墙案例

先给出样例:
在这里插入图片描述

这里直接放出照片墙的代码,需要注意的就是我们需要在VCimageShow.h中添加一些成员变量

在这里插入图片描述

1、同样的,先创建分栏控制器
在这里插入图片描述

2、VCRoot.m文件

#import "VCRoot.h"
#import "VCimageShow.h"
@interface VCRoot ()

@end

@implementation VCRoot

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.title = @"照片墙";
    
    UIScrollView *sv = [[UIScrollView alloc] init];
    //使导航栏不透明
    //translucent的意思是半透明
    //半透明照片就有点模糊的效果
    self.navigationController.navigationBar.translucent = YES;
    //设置位置大小
    sv.frame = CGRectMake(0, 0, self.view.bounds.size.width, [UIScreen mainScreen].bounds.size.height);
    //    //设置画布大小
    sv.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height * 1.5);
    
    //    self.navigationController.navigationBar.barTintColor = [UIColor redColor];
    
    //打开交互事件
    sv.userInteractionEnabled = YES;
    
    sv.scrollEnabled = YES;
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    for (int i = 0; i < 10; i++) {
        NSString *strName = [NSString stringWithFormat:@"%d.jpg", i + 1];
        
        UIImage *image = [UIImage imageNamed:strName];
        
        UIImageView *iView = [[UIImageView alloc] initWithImage:image];
        
        //纵向用这个
        //        iView.frame = CGRectMake([UIScreen mainScreen].bounds.size.width * i, 0, [UIScreen mainScreen].bounds.size.width,  [UIScreen mainScreen].bounds.size.height);
        
        sv.bounces = YES;
        //开启横向弹动效果
        sv.alwaysBounceHorizontal = YES;
        //开启纵向弹动效果
        //一般会开启,但是对于滚动的只有图片不需要刷新的最好不要开启
        sv.alwaysBounceVertical = YES;
        //Horizont是横向
        //显示横向滚动条
        sv.showsHorizontalScrollIndicator = YES;
        //是否显示纵向滚动条
        //必须要画布大小大于滚动视图框架大小才能显示
        //vertical是纵向
        sv.showsVerticalScrollIndicator = YES;
        
        iView.frame = CGRectMake(3 + (i % 3) * 100, (i / 3) * 140, 90, 130);
        
        [sv addSubview:iView];
        
        //        sv.pagingEnabled = YES;
        //        //是否可以开启滚动效果
        sv.scrollEnabled = YES;
        //开启交互模式
        iView.userInteractionEnabled = YES;
        
        //创建点击手势
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(pressTap:)];
        
        //单次点击
        tap.numberOfTapsRequired = 1;
        
        //单个手指
        tap.numberOfTouchesRequired = 1;
        
        [iView addGestureRecognizer:tap];
        
        iView.tag = 101 + i;
    }
    [self.view addSubview:sv];
}

//总结:不管是这两种方法的哪一种,我们到最后都是需要通过为我们的视图赋image来实现显示我们的image

- (void)pressTap:(UITapGestureRecognizer *)tap {
    NSLog(@"点击事件触发");
    UIImageView *imageView = (UIImageView *)tap.view;
    //创建显示视图控制器//方法2
    VCimageShow *imageShow = [[VCimageShow alloc] init];
    
    imageShow.imageTag = imageView.tag;

    [self.navigationController pushViewController:imageShow animated:YES];
}

//- (void)pressTap:(UITapGestureRecognizer *)tap {
//    NSLog(@"点击事件触发");
//    UIImageView *imageView = (UIImageView *)tap.view;
//
//    //创建显示视图控制器
//    VCimageShow *imageShow = [[VCimageShow alloc] init];
//    //d点击的图像赋值
//    imageShow.image = imageView.image;
//    //将控制器推出
    self.navigationController.navigationBar.translucent = NO;
//    [self.navigationController pushViewController:imageShow animated:YES];
//}

3、VCRoot.h文件
在这里插入图片描述
4、VCRoot.m文件
在这里插入图片描述

十三、多界面传值

概念:在iOS中,多界面传值是指在不同的视图控制器之间传递数据或信息的过程。当你需要将数据从一个视图控制器传递到另一个视图控制器时,可以使用多种方法来实现。
这里给出多界面传值的几种方法:
在这里插入图片描述
笔者在这里解释一下代理模式传值

我们先给出实现效果:
第一级:
在这里插入图片描述
第二级:
在这里插入图片描述
点击右上角1后视图一变为红色:
在这里插入图片描述

代理模式传值通俗的讲就是当前视图控制器中对其他视图控制器进行操作

实现代理传值由许多方式,这里实现一下在视图二的控制器里改变视图一的颜色

1、在第二级视图控制器中的头文件中定义协议
在这里插入图片描述
2、在第二级视图控制器中定义代理属性
在这里插入图片描述

3、在第二级视图控制器的.m文件中,利用代理属性去调用协议里的方法
在这里插入图片描述

4、在第一级视图控制器中将自己设为被代理的对象,并实现代理的方法
在这里插入图片描述

十四、UITableView

我们先来看一下UITableViewCell的创建与使用的效果图
在这里插入图片描述

创建和使用UITableViewCell的方法主要涉及以下几个步骤:

  • 创建UITableViewCell对象:使用initWithStyle:reuseIdentifier:方法创建一个UITableViewCell对象,并指定其样式和重用标识符。
static NSString *cellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}

  • 配置单元格的内容:在tableView:cellForRowAtIndexPath:代理方法中,根据indexPath参数获取特定位置的单元格,并对其进行配置。可以设置文本、图像、背景颜色等属性来呈现所需的内容。
// 配置单元格的内容
cell.textLabel.text = [NSString stringWithFormat:@"Row %ld", (long)indexPath.row];

  • 返回单元格对象:在配置完单元格后,通过return语句将单元格对象返回给UITableView,以供显示在指定的位置。
    return cell;
  • 处理单元格的重用:为了提高性能和内存利用率,通常会使用dequeueReusableCellWithIdentifier:方法获取可重用的单元格对象。如果该方法返回一个非空对象,则说明存在可重用的单元格,可以直接使用并进行配置;如果返回空对象,则需要创建新的单元格对象并设置其重用标识符。这点在后面学习自定义cell后会重点强调并讲解

这里给出完整代码,我们其中一些方法是因为我们继承了<UITableViewDelegate>协议,我们必须实现那些方法,比如
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 方法

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    //创建数据视图
    //p1:数据视图的位置
    //p2:数据视图的风格
    //UITableViewStylePlain  普通风格
    //UITableViewStyleGrouped   分组风格
    _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
    
    //自动调整子视图的大小
    _tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    
    //设置数据视图的代理对象
    _tableView.delegate = self;
    //设置数据视图的数据源对象
    _tableView.dataSource = self;
    
    //数据视图的头部视图的设定
    _tableView.tableHeaderView = nil;
    //数据视图的尾部视图的设定
    _tableView.tableFooterView = nil;
    
    //数据视图显示
    [self.view addSubview:_tableView];
    
    //创建一个可变数组
    _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];
//        }
//        //生成一个二维数组
//        [_arrayData addObject:arraySmall];
//
//    }
    for (int i = 1; i < 20; i++) {
        NSString *str = [NSString stringWithFormat:@"A %d", i];
        
        [_arrayData addObject:str];
    }
    
    //当数据的数据源发生变化时
    //更新数据视图,重新加载数据
    [_tableView reloadData];
    
    [self createBtn];
}

- (void)createBtn {
    _isEdit = NO;
    
    //创建功能按钮
    _btnEdit = [[UIBarButtonItem alloc] initWithTitle:@"编辑" style:UIBarButtonItemStylePlain target:self action:@selector(pressEdit)];
    _btnFinish = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStylePlain target:self action:@selector(pressFinish)];
    _btnDelete = [[UIBarButtonItem alloc] initWithTitle:@"删除" style:UIBarButtonItemStylePlain target:self action:@selector(pressDelete)];
    
    self.navigationItem.rightBarButtonItem = _btnEdit;
    
}

- (void)pressEdit {
    _isEdit = YES;
    self.navigationItem.rightBarButtonItem = _btnFinish;
    //开启编辑的一个状态
    [_tableView setEditing:YES];
    self.navigationItem.leftBarButtonItem = _btnDelete;
}

- (void)pressFinish {
    _isEdit = NO;
    self.navigationItem.rightBarButtonItem = _btnEdit;
    [_tableView setEditing:NO];
    self.navigationItem.leftBarButtonItem = nil;
}

//获取每组元素的个数(行数)
//必须要实现的协议函数
//程序在显示数据视图时会调用此函数
//返回值:表示每组元素的个数
//p1:数据视图对象本身
//p2:那一组需要的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//    return 5;
    
//    NSInteger numRow = [[_arrayData objectAtIndex:section] count];
//    return numRow;
    
    return _arrayData.count;
}

//获得设置数据视图的组数
//默认组数返回1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    //    return  _arrayData.count;
    
    return 1;
}

创建单元格对象函数
每创建一个单元格,都会调用这个函数
//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//    NSString *cellStr = @"cell";
//
//    //尝试获取可复用的单元格
//    //如果得不到,返回为空
//    UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:cellStr];
//
//    if (cell == nil) {
//        //创建一个单元格对象
//        //参数1:单元格的样式
//        //参数2:单元格的复用标记
//        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellStr];
//    }
    NSString *str = [NSString stringWithFormat:@"第%d组,第%d行", indexPath.section, indexPath.row];
//    //将单元格的主文字内容赋值
//    cell.textLabel.text = _arrayData[indexPath.section][indexPath.row];
//
//    return cell;
//}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *strID = @"ID";
    
    //尝试获取可以复用的单元格
    //如果得不到,返回为nil
    UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:strID];
    
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strID];
    }
    //单元格文字赋值
    cell.textLabel.text = [_arrayData objectAtIndex:indexPath.row];
    
    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 60;
}

@end

有关UITableViewCell会在后面细讲

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。