UI学习3

UI学习3

UIScrollView

我们可以使用UIScroll来创造可以滚动的视图,可以让我们把几张图片合起来

objectivec 复制代码
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    // 创建一个滚动视图,用于水平展示多张图片
    UIScrollView* sv = [[UIScrollView alloc] init];
    
    // 设置滚动视图的位置和大小(x=0, y=0, 宽=320, 高=570)
    sv.frame = CGRectMake(0, 0, 320, 570);
    
    // 开启分页效果,滑动时会自动对齐到每一页的边界
    sv.pagingEnabled = YES;
    
    // 允许用户滚动(默认为YES,可省略)
    sv.scrollEnabled = YES;
    
    // 设置内容区域的大小:宽度为 320 * 5(5张图片),高度为 570
    // 这样滚动视图就知道需要滚动多长的距离
    sv.contentSize = CGSizeMake(320 * 5, 570);
    
    // 开启弹性效果,拖拽到边界时会反弹
    sv.bounces = YES;
    
    // 始终允许水平方向弹性(即使内容宽度小于滚动视图宽度)
    sv.alwaysBounceHorizontal = YES;
    
    // 始终允许垂直方向弹性(这里内容高度等于滚动视图高度,垂直方向不会滚动,但设置也无妨)
    sv.alwaysBounceVertical = YES;
    
    // 显示垂直滚动条(当内容高度超过滚动视图高度时才显示,这里不会显示)
    sv.showsVerticalScrollIndicator = YES;
    
    // 显示水平滚动条
    sv.showsHorizontalScrollIndicator = YES;
    
    // 设置滚动视图的背景颜色为黄色,便于调试
    sv.backgroundColor = [UIColor yellowColor];
    
    // 循环添加5张图片
    for (int i = 0; i < 5; i++) {
        // 根据索引生成图片名称,例如 1.jpg, 2.jpg, ... 5.jpg
        NSString* strName = [NSString stringWithFormat:@"%d.jpg", i + 1];
        // 从项目资源中加载图片
        UIImage* image = [UIImage imageNamed:strName];
        // 创建图片视图,并直接使用图片初始化
        UIImageView* iView = [[UIImageView alloc] initWithImage:image];
        // 每个宽度为320,正好是滚动视图的宽度,实现分页
        iView.frame = CGRectMake(320 * i, 0, 320, 570);
        // 将图片视图添加到滚动视图中
        [sv addSubview:iView];
    }
    
    // 将滚动视图添加到当前控制器的根视图上,显示出来
    [self.view addSubview:sv];
}

contentSize:决定滚动范围

pagingEnabled:开启分页(类似轮播图)

bounces:是否有回弹效果

contentOffset:当前滚动位置

复制代码
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UIScrollViewDelegate>
{
    UIScrollView* scrollView;
}

@end
objectivec 复制代码
//
//  ViewController.m
//  UIScrollView高级
//
//  Created by 王子鸣 on 2026/4/13.
//

#import "ViewController.h"

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 1. 创建滚动视图对象
    scrollView = [[UIScrollView alloc] init];
    // 设置滚动视图的位置和大小 (x=10, y=50, width=300, height=400)
    scrollView.frame = CGRectMake(10, 50, 300, 400);
    // 关闭弹性效果(滚动到边界时不会反弹)
    scrollView.bounces = NO;
    // 允许用户交互(默认为YES,可省略)
    scrollView.userInteractionEnabled = YES;
    // 设置内容区域大小:宽度400,高度2000(5张图片 * 400)
    scrollView.contentSize = CGSizeMake(400, 400 * 5);
    
    // 2. 循环添加5张图片作为子视图
    for (int i = 0; i < 5; i++) {
        // 生成图片名称,例如 1.jpg, 2.jpg ... 5.jpg
        NSString* strName = [NSString stringWithFormat:@"%d.jpg", i + 1];
        // 从资源包加载图片
        UIImage* image = [UIImage imageNamed:strName];
        // 创建图片视图
        UIImageView* iView = [[UIImageView alloc] init];
        iView.image = image;
        // 设置图片视图的位置:x=0, y=400*i, 宽=300, 高=400
        // 这样图片会垂直排列,每个占满滚动视图的宽度和高度,便于分页滚动
        iView.frame = CGRectMake(0, 400 * i, 300, 400);
        [scrollView addSubview:iView];
    }
    
    // 将滚动视图添加到当前控制器的根视图
    [self.view addSubview:scrollView];
    
    // 开启分页效果,滑动停止时自动对齐到图片边界(每页高度400)
    scrollView.pagingEnabled = YES;
    // 初始滚动偏移量为 (0,0),显示第一张图片
    scrollView.contentOffset = CGPointMake(0, 0);
    // 设置代理为当前控制器,以便接收滚动事件
    scrollView.delegate = self;
}

#pragma mark - UIScrollViewDelegate 代理方法

// 当滚动视图滚动时(任何偏移变化)都会调用
-(void) scrollViewDidScroll:(UIScrollView *)scrollView {
    // 打印当前垂直滚动偏移量
    NSLog(@"y = %f", scrollView.contentOffset.y);
}

// 当用户结束拖拽(手指离开屏幕)时调用
// decelerate 表示松手后是否还会继续减速滚动
-(void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    NSLog(@"Did End Drag");
}

// 当用户开始拖拽滚动视图时调用
-(void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    NSLog(@"WillBeginDrag");
}

// 当滚动视图即将开始减速(惯性滚动)时调用
-(void) scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
    NSLog(@"Will Begin Deceleratg");  // 注意:原代码有拼写错误(Deceleratg),但不影响执行
}

// 当滚动视图完全停止(减速结束)时调用
-(void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    NSLog(@"视图停止移动");
}

#pragma mark - 触摸事件

// 重写触摸开始方法,当用户点击屏幕时触发
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    // 将滚动视图的可见区域滚动到顶部(CGRectMake(0,0,300,400) 表示第一个图片的区域)
    // animated:YES 表示带动画效果
    [scrollView scrollRectToVisible:CGRectMake(0, 0, 300, 400) animated:YES];
}

@end

手动布局子视图

UIView 的 layoutSubviews 方法会在视图大小改变时自动调用,适合用来动态调整子视图的位置和大小。下面的例子演示了如何让四个橙色小方块始终位于父视图的四个角,并在变化时带有动画。

objectivec 复制代码
//
//  SuperView.h
//  手动布局子视图
//
//  Created by 王子鸣 on 2026/4/14.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface SuperView : UIView
{
    UIView* view1;
    UIView* view2;
    UIView* view3;
    UIView* view4;
    UIView* view5;
}

-(void) creatSubViews;
@end

NS_ASSUME_NONNULL_END
objectivec 复制代码
//
//  SuperView.m
//  手动布局子视图
//
//  Created by 王子鸣 on 2026/4/14.
//

#import "SuperView.h"

@implementation SuperView

// 重写 drawRect: 方法(通常用于自定义绘制),这里不需要,故注释掉
/*
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

// 创建四个子视图(橙色小方块)并添加到当前视图
-(void) creatSubViews {
    // 创建四个 UIView 实例,并设置初始位置和大小(40x40)
    view1 = [[UIView alloc] init];
    view1.frame = CGRectMake(0, 0, 40, 40);          // 左上角
    
    view2 = [[UIView alloc] init];
    view2.frame = CGRectMake(self.bounds.size.width - 40, 0, 40, 40); // 右上角
    
    view3 = [[UIView alloc] init];
    view3.frame = CGRectMake(self.bounds.size.width - 40, self.bounds.size.height - 40, 40, 40); // 右下角
    
    view4 = [[UIView alloc] init];
    view4.frame = CGRectMake(0, self.bounds.size.height - 40, 40, 40); // 左下角
    
    // 设置所有子视图的背景色为橙色
    view1.backgroundColor = [UIColor orangeColor];
    view2.backgroundColor = [UIColor orangeColor];
    view3.backgroundColor = [UIColor orangeColor];
    view4.backgroundColor = [UIColor orangeColor];
    
    // 将子视图添加到当前视图
    [self addSubview:view1];
    [self addSubview:view2];
    [self addSubview:view3];
    [self addSubview:view4];
}

// 重写 layoutSubviews 方法,当视图的 bounds 发生变化时自动调用
// 这里用于重新调整四个子视图的位置,使它们始终位于父视图的四个角,并带有动画效果
-(void) layoutSubviews {
    // 开始动画块(旧式动画 API)
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:1];   // 设置动画持续时间为 1 秒
    
    // 重新设置子视图的 frame,使其紧贴父视图的四个角
    view1.frame = CGRectMake(0, 0, 40, 40);                                        // 左上角
    view2.frame = CGRectMake(self.bounds.size.width - 40, 0, 40, 40);              // 右上角
    view3.frame = CGRectMake(self.bounds.size.width - 40, self.bounds.size.height - 40, 40, 40); // 右下角
    view4.frame = CGRectMake(0, self.bounds.size.height - 40, 40, 40);              // 左下角
    
    // 提交动画,开始执行
    [UIView commitAnimations];
}

@end

导航控制器

  1. 基础
objectivec 复制代码
//SceneDelegate.m
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    // 将传入的 UIScene 对象强制转换为 UIWindowScene,因为我们需要用它来创建窗口
    UIWindowScene* windowScene = (UIWindowScene*)scene;
    
    // 使用 UIWindowScene 初始化一个 UIWindow 对象,这是应用程序的窗口容器
    self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
    
    // 创建自定义的根视图控制器 VCRoot(假设已定义)
    VCRoot* root = [[VCRoot alloc] init];
    
    // 将 VCRoot 包装在一个 UINavigationController 中,这样就有了导航栏和栈式导航功能
    UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:root];
    
    // 将导航控制器设置为窗口的根视图控制器
    self.window.rootViewController = nav;
    
    // 使窗口成为应用的主窗口并显示在屏幕上
    [self.window makeKeyAndVisible];
}
objectivec 复制代码
// VCRoot.m
- (void)viewDidLoad {
    // 必须先调用父类的 viewDidLoad,以执行父类的初始化
    [super viewDidLoad];
    
    // 设置当前视图的背景颜色为黄色
    self.view.backgroundColor = [UIColor yellowColor];
    
    // 设置导航栏的标题
    self.title = @"根视图";
    
    // 另一种设置导航栏标题的方式(与 self.title 效果相同,通常只用其一即可)
    self.navigationItem.title = @"Title";
    
    // 创建一个导航栏左侧按钮,标题为"左侧",样式为 Done(蓝色加粗文字)
    // target 指定按钮点击时调用的对象为 self(当前控制器)
    // action 指定点击时执行的方法为 pressLeft
    UIBarButtonItem* leftBtn = [[UIBarButtonItem alloc] initWithTitle:@"左侧" style:UIBarButtonItemStyleDone target:self action:@selector(pressLeft)];
    // 将创建好的按钮设置到导航栏的左侧位置
    self.navigationItem.leftBarButtonItem = leftBtn;
}

// 左侧按钮的点击事件处理方法
-(void) pressLeft {
    NSLog(@"左侧按钮被按下");
}

2.切换

objectivec 复制代码
//SceneDelegate.m
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    // 设置窗口的 frame 为整个屏幕的大小
    self.window.frame = [UIScreen mainScreen].bounds;
    
    // 创建自定义的根视图控制器 VCRoot
    VCRoot* root = [[VCRoot alloc] init];
    
    // 将根视图控制器嵌入到导航控制器中(获得导航栏和栈式导航功能)
    UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:root];
    
    // 将导航控制器设置为窗口的根视图控制器
    self.window.rootViewController = nav;
    
    // 使窗口成为应用的主窗口并显示在屏幕上
    [self.window makeKeyAndVisible];
}
objectivec 复制代码
#import "VCRoot.h"
#import "VCSecond.h"

@interface VCRoot ()

@end

@implementation VCRoot

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 设置当前视图的背景颜色为黄色
    self.view.backgroundColor = [UIColor yellowColor];
    
    // 设置导航栏的标题(显示在顶部中央)
    self.title = @"根视图";
    
    // 创建导航栏外观对象,用于自定义导航栏样式
    UINavigationBarAppearance* appearance = [[UINavigationBarAppearance alloc] init];
    // 加载背景图片(图片需添加到项目中,命名为 1.jpg)
    UIImage* bgImage = [UIImage imageNamed:@"1.jpg"];
    appearance.backgroundImage = bgImage;                 // 设置导航栏背景图片
    // 将自定义外观应用到导航栏的标准状态和滚动边缘状态
    self.navigationController.navigationBar.standardAppearance = appearance;
    self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
    
    // 另一种设置导航栏标题的方式(与 self.title 类似,通常只用一个即可)
    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)];
    self.navigationItem.rightBarButtonItem = rightButton; // 先设置一个单独的右侧按钮(后面会被覆盖)
    
    // 创建一个全屏的 UIImageView,作为视图的背景(最底层)
    UIImageView* imageView = [[UIImageView alloc] init];
    imageView.frame = [[UIScreen mainScreen] bounds];    // 全屏尺寸
    imageView.alpha = 1;                                 // 不透明
    imageView.image = [UIImage imageNamed:@"2.jpg"];
    [self.view insertSubview:imageView atIndex:0];       // 插入到最底层(索引0)
    
    // 创建一个自定义视图(UILabel)用于导航栏按钮
    UILabel* lael = [[UILabel alloc] init];
    lael.frame = CGRectMake(10, 10, 50, 40);             // 设置标签位置和大小
    lael.text = @"test";                                 // 标签文字
    lael.textAlignment = NSTextAlignmentCenter;          // 文字居中
    lael.textColor = [UIColor blueColor];                // 文字蓝色
    // 使用自定义视图创建 UIBarButtonItem
    UIBarButtonItem* item3 = [[UIBarButtonItem alloc] initWithCustomView:lael];
    
    // 设置右侧按钮组(包含之前的 rightButton 和刚创建的 item3)
    NSArray* arrayOfButton = [NSArray arrayWithObjects:rightButton, item3, nil];
    self.navigationItem.rightBarButtonItems = arrayOfButton;   // 会覆盖之前单独设置的 rightBarButtonItem
    
    // 确保导航栏显示(这两行作用相同,保留一行即可)
    self.navigationController.navigationBar.hidden = NO;
    self.navigationController.navigationBarHidden = NO;
}

// 左侧按钮点击事件
-(void) pressleft {
    NSLog(@"leftButton is pressed");
}

// 右侧按钮点击事件(进入下一级页面)
-(void) pressright {
    // 创建第二个视图控制器
    VCSecond* vc2 = [[VCSecond alloc] init];
    // 通过导航控制器压入新视图控制器,实现页面跳转
    [self.navigationController pushViewController:vc2 animated:YES];
}

@end
objectivec 复制代码
#import "VCSecond.h"
#import "VCThird.h"

@interface VCSecond ()

@end

@implementation VCSecond

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 创建一个全屏的 UIImageView 作为背景
    UIImageView* imageView = [[UIImageView alloc] init];
    imageView.image = [UIImage imageNamed:@"3.jpg"];          // 加载图片 3.jpg(需添加到项目)
    imageView.frame = [[UIScreen mainScreen] bounds];         // 设置 frame 为屏幕大小
    [self.view insertSubview:imageView atIndex:0];            // 插入到视图最底层(索引0)
    
    // 设置导航栏为半透明效果(默认为 YES,此处可省略)
    self.navigationController.navigationBar.translucent = YES;
    // 设置导航栏的样式为默认(黑色文字,浅色背景)
    self.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)];
}

// 右侧按钮点击事件:压入 VCThird 控制器,实现页面跳转
-(void) pressright {
    VCThird* vc3 = [[VCThird alloc] init];                     // 创建第三个视图控制器
    [self.navigationController pushViewController:vc3 animated:YES]; // 导航控制器推入新页面
}

// 左侧按钮点击事件:弹出当前控制器,返回上一级
-(void) pressleft {
    [self.navigationController popViewControllerAnimated:YES]; // 从导航栈中移除当前控制器
}
@end
objectivec 复制代码
//
//  VCThird.m
//  导航控制器切换
//
//  Created by 王子鸣 on 2026/4/16.
//

#import "VCThird.h"
#import "VCRoot.h"
#import "VCSecond.h"

@interface VCThird ()

@end

@implementation VCThird

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    // 创建一个 UIImageView 用于显示背景图片
    UIImageView* imageView = [UIImageView new];
    // 设置 frame 为整个屏幕的大小
    imageView.frame = [[UIScreen mainScreen] bounds];
    // 加载图片 4.jpg(需添加到项目中)
    imageView.image = [UIImage imageNamed:@"4.jpg"];
    // 将图片视图插入到当前视图的最底层(索引0),作为背景
    [self.view insertSubview:imageView atIndex:0];
    
    // 设置导航栏的标题为"视图三"
    self.navigationItem.title = @"视图三";
    
    // 创建左侧按钮,标题为"上一级页面",点击时调用 pressleft 方法
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"上一级页面"
                                                                             style:UIBarButtonItemStylePlain
                                                                            target:self
                                                                            action:@selector(pressleft)];
    // 创建右侧按钮,标题为"下一级页面",点击时调用 pressright 方法
    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];
}

@end

分栏控制器

objectivec 复制代码
//  SceneDelegate.m
//  分栏控制器
//
//  Created by 王子鸣 on 2026/4/16.
//

#import "SceneDelegate.h"
// 导入所有视图控制器头文件
#import "VCFirst.h"
#import "VCSecond.h"
#import "VCThird.h"
#import "VCFourth.h"
#import "VCFifth.h"
#import "VCSixth.h"

@interface SceneDelegate ()<UITabBarControllerDelegate>

@end

@implementation SceneDelegate

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    // 1. 创建六个视图控制器,分别设置背景颜色和标题
    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";
    
    // 2. 创建标签栏控制器(UITabBarController)
    UITabBarController* tbc = [UITabBarController new];
    // 将六个视图控制器放入数组,作为标签栏的子控制器
    NSArray* arrvc = [NSArray arrayWithObjects:vc01, vc02, vc03, vc04, vc05, vc06, nil];
    tbc.viewControllers = arrvc;
    
    // 3. 将标签栏控制器设置为窗口的根视图控制器
    self.window.rootViewController = tbc;
    
    // 4. 默认选中第三个标签(索引从0开始,即视图3)
    tbc.selectedIndex = 2;
    // 判断当前选中的控制器是否为 vc03,若是则打印日志
    if (tbc.selectedViewController == vc03) {
        NSLog(@"选中的是下标为2的视图控制器");
    }
    
    // 5. 自定义标签栏外观
    tbc.tabBar.translucent = NO;                // 关闭半透明效果
    tbc.tabBar.backgroundColor = [UIColor redColor]; // 设置标签栏背景色为红色
    
    // 6. 设置代理,以便接收标签栏的事件(编辑、选中切换等)
    tbc.delegate = self;
}

#pragma mark - UITabBarControllerDelegate 代理方法

// 用户开始编辑标签栏(长按某个标签进入编辑模式)时调用
-(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 {
    NSLog(@"选中控制器对象");
}

#pragma mark - 其他场景生命周期方法(通常无需修改,保留默认实现)

- (void)sceneDidDisconnect:(UIScene *)scene {
    // 场景断开连接时调用(例如被系统释放)
}

- (void)sceneDidBecomeActive:(UIScene *)scene {
    // 场景变为活跃状态(从后台切换到前台)时调用
}

- (void)sceneWillResignActive:(UIScene *)scene {
    // 场景即将失去活跃状态(例如被电话打断)时调用
}

- (void)sceneWillEnterForeground:(UIScene *)scene {
    // 场景即将进入前台(从后台唤醒)时调用
}

- (void)sceneDidEnterBackground:(UIScene *)scene {
    // 场景已经进入后台(按Home键)时调用
}

@end
objectivec 复制代码
// VCFirst.m
- (void)viewDidLoad {
    [super viewDidLoad];
    // 创建一个系统预定义样式的标签栏项,使用"通讯录"图标(UITabBarSystemItemContacts)
    UITabBarItem* tabbarItem = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemContacts tag:101];
    // 将当前视图控制器的标签栏项设置为这个新创建的项
    self.tabBarItem = tabbarItem;
}
// VCSecond.m
- (void)viewDidLoad {
    [super viewDidLoad];
    // 创建一个自定义标题的标签栏项,标题为"发现",不设置图片(image 参数为 nil)
    // tag 设置为 101(可与第一个视图区分,但实际 tag 值通常不同,这里保持原样)
    UITabBarItem* tabbarItem = [[UITabBarItem alloc] initWithTitle:@"发现" image:nil tag:101];
    tabbarItem.badgeValue = @"22";
    // 将当前视图控制器的标签栏项设置为这个新创建的项
    self.tabBarItem = tabbarItem;
}
//后面四个文件不用修改(3,4,5,6)

frame和bounds

  1. frame

作用:描述视图在父视图坐标系中的位置和大小。

属性CGRect 类型,包含 origin(相对于父视图左上角的偏移)和 size(视图的宽高)。

可修改性 :可以修改 frame 来改变视图在父视图中的位置和大小。

坐标系:父视图的坐标系(以父视图的左上角为原点 (0,0))。

  1. bounds

作用 :描述视图在自身坐标系中的位置和大小。(解释自身坐标)

属性CGRect 类型,但 origin 通常为 (0,0)(除非子视图的坐标偏移或滚动)。

可修改性 :修改 bounds 会改变视图自身的坐标系统,影响子视图的布局以及视图自身的显示内容。

坐标系:以视图自身的左上角为原点 (0,0)。

场景 推荐使用
改变视图在父视图中的位置或大小 修改 frame
移动子视图(如滚动视图的内容) 修改 bounds.origin
缩放视图内容(如捏合手势) 修改 bounds.size
获取视图的实际显示区域(不考虑父视图) 读取 bounds
获取视图相对于父视图的矩形 读取 frame

在iOS中,frame主要用于视图布局bounds用于动画缩放,改变 bounds.size 时,视图会以 center 为中心向四周均匀缩放,符合常见缩放效果,如果直接用 frame 做缩放,视图会围绕左上角 (frame.origin) 缩放,另外,修改 bounds 不会影响视图的 center,因此可以方便地和位置动画组合。

总结

这次的学习主要是多个界面,多个视图的处理,学习这部分内容是对之前单个处理的整合

相关推荐
三品吉他手会点灯3 小时前
C语言学习笔记 - 3. C概述 - C语言的起源和发展
c语言·笔记·学习
Alice-YUE4 小时前
ai对话平台中的functioncalling+mcp
前端·笔记·学习·语言模型
王的宝库4 小时前
【K8s】集群安全机制(二):授权(Authorization)详解与实战
学习·云原生·容器·kubernetes
ReaF_star4 小时前
K8s Pod调度【学习笔记】
笔记·学习·kubernetes
fengci.5 小时前
ctfshow其他(web408-web432)
android·开发语言·前端·学习·php
sensen_kiss5 小时前
CPT306 Principles of Computer Games Design 电脑游戏设计原理 Pt.6 Gameplay 游戏玩法
学习·游戏
殷忆枫5 小时前
AI学习笔记三十六:基于 YOLOv8 与 Qwen3.5 的多模态视频行为分析系统
笔记·学习·yolo
小陈phd5 小时前
多模态大模型学习笔记(三十七)——模型管理平台实战:Ollama本地部署与全流程指南
笔记·学习
returnthem5 小时前
使用trae 学习AI编程
学习·ai编程