开源 Objective-C IOS 应用开发(八)常见控件UI

  文章的目的为了记录使用Objective-C 进行IOS app 开发学习的经历。本职为嵌入式软件开发,公司安排开发app,临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

 相关链接:

开源 Objective-C IOS 应用开发(一)macOS 的使用

开源 Objective-C IOS 应用开发(二)Xcode安装

开源 Objective-C IOS 应用开发(三)第一个iPhone的APP

开源 Objective-C IOS 应用开发(四)Xcode工程文件结构

开源 Objective-C IOS 应用开发(五)iOS操作(action)和输出口(Outlet)

开源 Objective-C IOS 应用开发(六)Objective-C 和 C语言

开源 Objective-C IOS 应用开发(七)Objective-C核心代码示例

开源 Objective-C IOS 应用开发(八)常见控件UI

开源 Objective-C IOS 应用开发(九)复杂控件-tableview

开源 Objective-C IOS 应用开发(十)数据持久化--文件

开源 Objective-C IOS 应用开发(十一)数据持久化--sqlite

开源 Objective-C IOS 应用开发(十二)通讯--ble

开源 Objective-C IOS 应用开发(十三)通讯--Http访问

开源 Objective-C IOS 应用开发(十四)传感器--陀螺仪和gps

开源 Objective-C IOS 应用开发(十五)通讯--蓝牙ble扫描

开源 Objective-C IOS 应用开发(十六)Storyboard模式下的纯代码界面

开源 Objective-C IOS 应用开发(十七)CAF音频的录制

开源 Objective-C IOS 应用开发(十八)音频的播放

开源 Objective-C IOS 应用开发(十九)视频的播放

开源 Objective-C IOS 应用开发(二十)多线程处理

开源 Objective-C IOS 应用开发(二十一)自定义控件--示波器

开源 Objective-C IOS 应用开发(二十二)自定义控件--车速仪表盘

 推荐链接:

开源 Arkts 鸿蒙应用 开发(一)工程文件分析-优快云博客

开源 Arkts 鸿蒙应用 开发(二)封装库.har制作和应用-优快云博客

开源 Arkts 鸿蒙应用 开发(三)Arkts的介绍-优快云博客

开源 Arkts 鸿蒙应用 开发(四)布局和常用控件-优快云博客

开源 Arkts 鸿蒙应用 开发(五)控件组成和复杂控件-优快云博客

开源 Arkts 鸿蒙应用 开发(六)数据持久--文件和首选项存储-优快云博客

开源 Arkts 鸿蒙应用 开发(七)数据持久--sqlite关系数据库-优快云博客

开源 Arkts 鸿蒙应用 开发(八)多媒体--相册和相机-优快云博客

开源 Arkts 鸿蒙应用 开发(九)通讯--tcp客户端-优快云博客

开源 Arkts 鸿蒙应用 开发(十)通讯--Http-优快云博客

开源 Arkts 鸿蒙应用 开发(十一)证书和包名修改-优快云博客

开源 Arkts 鸿蒙应用 开发(十二)传感器的使用-优快云博客

开源 Arkts 鸿蒙应用 开发(十三)音频--MP3播放_arkts avplayer播放音频 mp3-优快云博客

开源 Arkts 鸿蒙应用 开发(十四)线程--任务池(taskpool)-优快云博客

开源 Arkts 鸿蒙应用 开发(十五)自定义绘图控件--仪表盘-优快云博客

开源 Arkts 鸿蒙应用 开发(十六)自定义绘图控件--波形图-优快云博客

开源 Arkts 鸿蒙应用 开发(十七)通讯--http多文件下载-优快云博客

开源 Arkts 鸿蒙应用 开发(十八)通讯--Ble低功耗蓝牙服务器-优快云博客

推荐链接:

开源 java android app 开发(一)开发环境的搭建-优快云博客

开源 java android app 开发(二)工程文件结构-优快云博客

开源 java android app 开发(三)GUI界面布局和常用组件-优快云博客

开源 java android app 开发(四)GUI界面重要组件-优快云博客

开源 java android app 开发(五)文件和数据库存储-优快云博客

开源 java android app 开发(六)多媒体使用-优快云博客

开源 java android app 开发(七)通讯之Tcp和Http-优快云博客

开源 java android app 开发(八)通讯之Mqtt和Ble-优快云博客

开源 java android app 开发(九)后台之线程和服务-优快云博客

开源 java android app 开发(十)广播机制-优快云博客

开源 java android app 开发(十一)调试、发布-优快云博客

开源 java android app 开发(十二)封库.aar-优快云博客
 

本章内容主要是Xcode开发中的多种常用 UI 控件的使用方法。

主要有:

  • UILabel: 显示文本

  • UITextField: 文本输入,添加了编辑变化监听

  • UIButton: 可点击按钮,设置圆角和背景色

  • UIImageView: 显示图片,通过绘图上下文创建颜色图片

  • UISwitch: 开关控件

  • UISlider: 滑块控件,范围 0-100

  • UIActivityIndicatorView: 活动指示器

  • UIProgressView: 进度条

  • UIStepper: 步进器

  • UISegmentedControl: 分段控件

目录:

1.源码分析

2.所有源码

3.手机效果

一、源码分析

1. 核心生命周期函数

- (void)viewDidLoad

objc

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setupUI];
    [self setupConstraints];
}

详细分析:

  • 调用时机:在控制器的视图层次被加载到内存后调用,只调用一次

  • [super viewDidLoad]:调用父类实现,确保 UIKit 完成必要的初始化工作

  • 功能职责:这是执行一次性初始化任务的理想位置

  • 代码组织:将复杂的 UI 设置分解为两个独立方法,提高可读性

  • 最佳实践:避免在此方法中执行耗时的同步操作,防止界面卡顿

2. UI 初始化函数

- (void)setupUI

objc

- (void)setupUI {
    self.view.backgroundColor = [UIColor whiteColor];
    
    // 创建 UIScrollView 来容纳所有控件
    self.scrollView = [[UIScrollView alloc] init];
    self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:self.scrollView];
    
    // 后续创建各个控件...
}

详细分析:

  • 架构设计:采用"容器-内容"模式,UIScrollView 作为容器确保内容可滚动

  • Auto Layout 准备translatesAutoresizingMaskIntoConstraints = NO 禁用自动转换掩码,这是使用代码布局的前提

  • 视图层次[self.view addSubview:self.scrollView] 将 scrollView 添加到控制器的主视图

  • 背景设置:设置白色背景是 iOS 应用的标准做法

各个控件的创建模式分析:

UILabel 创建:

objc

self.demoLabel = [[UILabel alloc] init];
self.demoLabel.text = @"Hello, UIKit!";
self.demoLabel.textColor = [UIColor blackColor];
self.demoLabel.textAlignment = NSTextAlignmentCenter;
self.demoLabel.backgroundColor = [UIColor systemGray6Color];
self.demoLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:self.demoLabel];

属性分析:

  • text:设置显示文本内容

  • textColor:文字颜色为黑色

  • textAlignment:居中对齐,确保文本在标签内居中显示

  • backgroundColor:使用系统灰色系,适配深色模式

  • 添加到 scrollView 而不是 self.view,成为可滚动内容的一部分

UITextField 创建:

objc

[self.demoTextField addTarget:self 
                       action:@selector(textFieldDidChange:) 
             forControlEvents:UIControlEventEditingChanged];

事件绑定分析:

  • 使用 Target-Action 模式监听文本变化

  • UIControlEventEditingChanged:当文本框内容发生变化时触发

  • @selector(textFieldDidChange:):指定处理方法

UIImageView 图片生成:

objc

UIGraphicsBeginImageContext(CGSizeMake(100, 100));
[[UIColor systemGreenColor] setFill];
UIRectFill(CGRectMake(0, 0, 100, 100));
UIImage *demoImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.demoImageView.image = demoImage;

绘图上下文分析:

  • UIGraphicsBeginImageContext():创建位图绘图上下文

  • setFill 和 UIRectFill:用绿色填充整个区域

  • UIGraphicsGetImageFromCurrentImageContext():从上下文获取 UIImage 对象

  • UIGraphicsEndImageContext():必须手动关闭上下文,释放资源

- (void)setupLocalImageSection

objc

- (void)setupLocalImageSection {
    // 创建图片区域标题、ImageView 和切换按钮
    self.isShowingFirstImage = YES;
    [self loadCurrentImage];
}

模块化设计分析:

  • 将相关的 UI 元素组织在一起,提高代码内聚性

  • 初始化状态标志 isShowingFirstImage

  • 立即调用 loadCurrentImage 加载初始图片

3. 布局约束函数

- (void)setupConstraints

objc

[NSLayoutConstraint activateConstraints:@[
    [self.scrollView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
    [self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
    [self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
    [self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
]];

ScrollView 约束分析:

  • 安全区域适配safeAreaLayoutGuide 自动避开刘海、Home 指示器等

  • 四边贴合:让 scrollView 填满整个安全区域

  • 内容大小:scrollView 的内容大小由内部约束自动计算

动态查找标签的巧妙方法:

objc

UILabel *imageSectionLabel = nil;
for (UIView *view in self.scrollView.subviews) {
    if ([view isKindOfClass:[UILabel class]]) {
        UILabel *label = (UILabel *)view;
        if ([label.text isEqualToString:@"本地图片显示区域"]) {
            imageSectionLabel = label;
            break;
        }
    }
}

设计分析:

  • 问题:由于 setupLocalImageSection 在 setupUI 中调用,无法直接获取标签引用

  • 解决方案:通过遍历子视图并比较文本来动态查找

  • 类型安全:使用 isKindOfClass: 确保找到的是 UILabel

  • 效率优化:找到后立即 break 退出循环

垂直布局约束模式:

objc

[self.demoLabel.topAnchor constraintEqualToAnchor:self.scrollView.topAnchor constant:20],
[self.demoLabel.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:20],
[self.demoLabel.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor constant:-20],
[self.demoLabel.heightAnchor constraintEqualToConstant:40],

布局规则分析:

  • 垂直间距:每个控件通过 topAnchor 与前一个控件的 bottomAnchor 连接

  • 水平边距:左右各 20pt 的边距,保持视觉一致性

  • 固定高度:明确指定控件高度,确保布局精确

  • 关键路径:最后一个控件的 bottomAnchor 决定 scrollView 的内容高度

4. 图片处理函数

- (void)loadCurrentImage

objc

- (void)loadCurrentImage {
    NSString *imageName = self.isShowingFirstImage ? @"1.png" : @"2.png";
    UIImage *image = [UIImage imageNamed:imageName];
    
    if (image) {
        // 图片加载成功的情况
        self.localImageView.image = image;
        [self.imageToggleButton setTitle:self.isShowingFirstImage ? @"切换到图片2" : @"切换到图片1"
                                forState:UIControlStateNormal];
        self.demoLabel.text = [NSString stringWithFormat:@"当前显示: %@", imageName];
    } else {
        // 图片加载失败的降级处理
        [self handleImageLoadFailureForImage:imageName];
    }
}

图片加载逻辑分析:

  • 资源命名:使用简单的 "1.png", "2.png" 命名

  • 缓存机制imageNamed: 方法使用系统缓存,提高重复加载性能

  • 状态同步:更新按钮标题反映下一次操作

  • 用户反馈:在主标签显示当前图片信息

图片加载失败的降级处理:

objc

// 创建提示文本图像
UIGraphicsBeginImageContext(CGSizeMake(200, 150));
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 200, 150)];
[[UIColor systemRedColor] setFill];
[path fill];

NSString *warningText = @"图片未找到";
NSDictionary *attributes = @{
    NSForegroundColorAttributeName: [UIColor whiteColor],
    NSFontAttributeName: [UIFont systemFontOfSize:14]
};
// 文本尺寸计算和绘制...

错误处理分析:

  • 视觉反馈:使用红色背景明确指示错误状态

  • 动态绘图:在运行时创建包含错误信息的图片

  • 文本居中:精确计算文本尺寸并居中绘制

  • 控制台日志:通过 NSLog 输出调试信息

- (void)toggleImageButtonTapped:(UIButton *)sender

objc

- (void)toggleImageButtonTapped:(UIButton *)sender {
    // 切换图片状态
    self.isShowingFirstImage = !self.isShowingFirstImage;
    
    // 加载对应的图片
    [self loadCurrentImage];
    
    // 添加切换动画
    [UIView transitionWithView:self.localImageView
                     duration:0.3
                      options:UIViewAnimationOptionTransitionFlipFromLeft
                   animations:nil
                   completion:nil];
}

用户体验优化:

  • 状态切换:简单的布尔值取反实现状态管理

  • 动画效果:使用翻转动画增强交互体验

  • UIViewAnimationOptionTransitionFlipFromLeft:从左侧翻转的动画类型

  • 持续时间:0.3 秒符合 iOS 动画时长标准

5. 事件处理函数

- (void)buttonTapped:(UIButton *)sender

objc

- (void)buttonTapped:(UIButton *)sender {
    NSLog(@"按钮被点击");
    
    // 更新 UILabel
    self.demoLabel.text = @"按钮已点击!";
    self.demoLabel.textColor = [UIColor systemRedColor];
    
    // 切换 UISwitch 状态
    [self.demoSwitch setOn:!self.demoSwitch.isOn animated:YES];
    
    // 改变 UISlider 值
    float newValue = (self.demoSlider.value + 10) > 100 ? 0 : self.demoSlider.value + 10;
    [self.demoSlider setValue:newValue animated:YES];
    
    // 后续其他控件更新...
}

综合交互分析:

  • 日志记录:使用 NSLog 便于调试

  • 多控件联动:单个操作触发多个界面更新,展示控件间协作

  • 动画效果animated:YES 为状态变化添加平滑动画

  • 边界处理:对 slider 值进行范围检查,防止越界

  • 颜色变化:使用系统红色提供视觉反馈

其他事件处理函数的模式:

objc

- (void)textFieldDidChange:(UITextField *)textField {
    self.demoLabel.text = textField.text;
}

- (void)switchChanged:(UISwitch *)sender {
    NSString *state = sender.isOn ? @"开" : @"关";
    NSLog(@"Switch 状态: %@", state);
    self.demoLabel.text = [NSString stringWithFormat:@"Switch: %@", state];
}

事件处理模式分析:

  • 实时反馈:文本框变化立即反映在标签上

  • 状态转换:将布尔值转换为用户友好的文字描述

  • 字符串格式化:使用 stringWithFormat: 构建显示文本

  • 统一的反馈机制:都通过更新 demoLabel 向用户提供反馈

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

objc

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}

键盘管理分析:

  • 响应链重写:覆盖触摸事件处理方法

  • endEditing:YES:强制结束所有编辑状态,收起键盘

  • 用户体验:点击空白处收起键盘是 iOS 应用的标准行为

二、所有源码

红框中为所需图片和修改的文件

ViewController.h文件

//
//  ViewController.h
//  ctrls
//
//  
//
/*
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController


@end

*/

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (nonatomic, strong) UILabel *demoLabel;
@property (nonatomic, strong) UITextField *demoTextField;
@property (nonatomic, strong) UIButton *demoButton;
@property (nonatomic, strong) UIImageView *demoImageView;
@property (nonatomic, strong) UISwitch *demoSwitch;
@property (nonatomic, strong) UISlider *demoSlider;
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicator;
@property (nonatomic, strong) UIProgressView *progressView;
@property (nonatomic, strong) UIStepper *demoStepper;
@property (nonatomic, strong) UISegmentedControl *segmentedControl;

// 新增:专门用于显示本地图片的 ImageView
@property (nonatomic, strong) UIImageView *localImageView;
@property (nonatomic, strong) UIButton *imageToggleButton;
@property (nonatomic, assign) BOOL isShowingFirstImage;

@property (nonatomic, strong) UIScrollView *scrollView;

@end

ViewController.m文件

//
//  ViewController.m
//  ctrls
//
//  
//
/*
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}


@end
*/

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setupUI];
    [self setupConstraints];
}

- (void)setupUI {
    self.view.backgroundColor = [UIColor whiteColor];
    
    // 创建 UIScrollView 来容纳所有控件
    self.scrollView = [[UIScrollView alloc] init];
    self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:self.scrollView];
    
    // 1. UILabel
    self.demoLabel = [[UILabel alloc] init];
    self.demoLabel.text = @"Hello, UIKit!";
    self.demoLabel.textColor = [UIColor blackColor];
    self.demoLabel.textAlignment = NSTextAlignmentCenter;
    self.demoLabel.backgroundColor = [UIColor systemGray6Color];
    self.demoLabel.translatesAutoresizingMaskIntoConstraints = NO;
    [self.scrollView addSubview:self.demoLabel];
    
    // 2. UITextField
    self.demoTextField = [[UITextField alloc] init];
    self.demoTextField.placeholder = @"请输入文本";
    self.demoTextField.borderStyle = UITextBorderStyleRoundedRect;
    self.demoTextField.translatesAutoresizingMaskIntoConstraints = NO;
    [self.demoTextField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
    [self.scrollView addSubview:self.demoTextField];
    
    // 3. UIButton
    self.demoButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.demoButton setTitle:@"点击我" forState:UIControlStateNormal];
    self.demoButton.backgroundColor = [UIColor systemBlueColor];
    [self.demoButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    self.demoButton.layer.cornerRadius = 8;
    self.demoButton.translatesAutoresizingMaskIntoConstraints = NO;
    [self.demoButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
    [self.scrollView addSubview:self.demoButton];
    
    // 4. UIImageView (原有的颜色图像)
    self.demoImageView = [[UIImageView alloc] init];
    self.demoImageView.backgroundColor = [UIColor systemGray4Color];
    self.demoImageView.contentMode = UIViewContentModeScaleAspectFit;
    self.demoImageView.translatesAutoresizingMaskIntoConstraints = NO;
    // 创建一个简单的颜色图像
    UIGraphicsBeginImageContext(CGSizeMake(100, 100));
    [[UIColor systemGreenColor] setFill];
    UIRectFill(CGRectMake(0, 0, 100, 100));
    UIImage *demoImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    self.demoImageView.image = demoImage;
    [self.scrollView addSubview:self.demoImageView];
    
    // 5. UISwitch
    self.demoSwitch = [[UISwitch alloc] init];
    self.demoSwitch.translatesAutoresizingMaskIntoConstraints = NO;
    [self.demoSwitch addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
    [self.scrollView addSubview:self.demoSwitch];
    
    // 6. UISlider
    self.demoSlider = [[UISlider alloc] init];
    self.demoSlider.minimumValue = 0;
    self.demoSlider.maximumValue = 100;
    self.demoSlider.value = 50;
    self.demoSlider.translatesAutoresizingMaskIntoConstraints = NO;
    [self.demoSlider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
    [self.scrollView addSubview:self.demoSlider];
    
    // 7. UIActivityIndicatorView
    self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleMedium];
    self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
    [self.scrollView addSubview:self.activityIndicator];
    
    // 8. UIProgressView
    self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
    self.progressView.progress = 0.5;
    self.progressView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.scrollView addSubview:self.progressView];
    
    // 9. UIStepper
    self.demoStepper = [[UIStepper alloc] init];
    self.demoStepper.minimumValue = 0;
    self.demoStepper.maximumValue = 10;
    self.demoStepper.stepValue = 1;
    self.demoStepper.value = 5;
    self.demoStepper.translatesAutoresizingMaskIntoConstraints = NO;
    [self.demoStepper addTarget:self action:@selector(stepperValueChanged:) forControlEvents:UIControlEventValueChanged];
    [self.scrollView addSubview:self.demoStepper];
    
    // 10. UISegmentedControl
    NSArray *segmentedItems = @[@"选项1", @"选项2", @"选项3"];
    self.segmentedControl = [[UISegmentedControl alloc] initWithItems:segmentedItems];
    self.segmentedControl.selectedSegmentIndex = 0;
    self.segmentedControl.translatesAutoresizingMaskIntoConstraints = NO;
    [self.segmentedControl addTarget:self action:@selector(segmentedControlChanged:) forControlEvents:UIControlEventValueChanged];
    [self.scrollView addSubview:self.segmentedControl];
    
    // 新增:本地图片显示区域
    [self setupLocalImageSection];
}

- (void)setupLocalImageSection {
    // 标题标签
    UILabel *imageSectionLabel = [[UILabel alloc] init];
    imageSectionLabel.text = @"本地图片显示区域";
    imageSectionLabel.textColor = [UIColor darkGrayColor];
    imageSectionLabel.textAlignment = NSTextAlignmentCenter;
    imageSectionLabel.font = [UIFont boldSystemFontOfSize:16];
    imageSectionLabel.translatesAutoresizingMaskIntoConstraints = NO;
    [self.scrollView addSubview:imageSectionLabel];
    
    // 本地图片 ImageView
    self.localImageView = [[UIImageView alloc] init];
    self.localImageView.backgroundColor = [UIColor systemGray5Color];
    self.localImageView.contentMode = UIViewContentModeScaleAspectFit;
    self.localImageView.layer.borderWidth = 1.0;
    self.localImageView.layer.borderColor = [UIColor systemGray3Color].CGColor;
    self.localImageView.layer.cornerRadius = 8;
    self.localImageView.clipsToBounds = YES;
    self.localImageView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.scrollView addSubview:self.localImageView];
    
    // 图片切换按钮
    self.imageToggleButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.imageToggleButton setTitle:@"显示图片1" forState:UIControlStateNormal];
    self.imageToggleButton.backgroundColor = [UIColor systemPurpleColor];
    [self.imageToggleButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    self.imageToggleButton.layer.cornerRadius = 6;
    self.imageToggleButton.titleLabel.font = [UIFont systemFontOfSize:14];
    self.imageToggleButton.translatesAutoresizingMaskIntoConstraints = NO;
    [self.imageToggleButton addTarget:self action:@selector(toggleImageButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    [self.scrollView addSubview:self.imageToggleButton];
    
    // 初始状态
    self.isShowingFirstImage = YES;
    
    // 尝试加载初始图片
    [self loadCurrentImage];
}

- (void)setupConstraints {
    // ScrollView 约束
    [NSLayoutConstraint activateConstraints:@[
        [self.scrollView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
        [self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
        [self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
        [self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
    ]];
    
    // 找到图片区域标题标签的简单方法
    UILabel *imageSectionLabel = nil;
    for (UIView *view in self.scrollView.subviews) {
        if ([view isKindOfClass:[UILabel class]]) {
            UILabel *label = (UILabel *)view;
            if ([label.text isEqualToString:@"本地图片显示区域"]) {
                imageSectionLabel = label;
                break;
            }
        }
    }
    
    // 垂直布局约束
    [NSLayoutConstraint activateConstraints:@[
        // UILabel
        [self.demoLabel.topAnchor constraintEqualToAnchor:self.scrollView.topAnchor constant:20],
        [self.demoLabel.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:20],
        [self.demoLabel.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor constant:-20],
        [self.demoLabel.heightAnchor constraintEqualToConstant:40],
        
        // UITextField
        [self.demoTextField.topAnchor constraintEqualToAnchor:self.demoLabel.bottomAnchor constant:15],
        [self.demoTextField.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:20],
        [self.demoTextField.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor constant:-20],
        [self.demoTextField.heightAnchor constraintEqualToConstant:40],
        
        // UIButton
        [self.demoButton.topAnchor constraintEqualToAnchor:self.demoTextField.bottomAnchor constant:15],
        [self.demoButton.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:20],
        [self.demoButton.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor constant:-20],
        [self.demoButton.heightAnchor constraintEqualToConstant:44],
        
        // UIImageView (颜色图像)
        [self.demoImageView.topAnchor constraintEqualToAnchor:self.demoButton.bottomAnchor constant:15],
        [self.demoImageView.centerXAnchor constraintEqualToAnchor:self.scrollView.centerXAnchor],
        [self.demoImageView.widthAnchor constraintEqualToConstant:100],
        [self.demoImageView.heightAnchor constraintEqualToConstant:100],
        
        // UISwitch
        [self.demoSwitch.topAnchor constraintEqualToAnchor:self.demoImageView.bottomAnchor constant:15],
        [self.demoSwitch.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:20],
        
        // UISlider
        [self.demoSlider.topAnchor constraintEqualToAnchor:self.demoSwitch.bottomAnchor constant:15],
        [self.demoSlider.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:20],
        [self.demoSlider.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor constant:-20],
        
        // UIActivityIndicatorView
        [self.activityIndicator.topAnchor constraintEqualToAnchor:self.demoSlider.bottomAnchor constant:15],
        [self.activityIndicator.centerXAnchor constraintEqualToAnchor:self.scrollView.centerXAnchor],
        
        // UIProgressView
        [self.progressView.topAnchor constraintEqualToAnchor:self.activityIndicator.bottomAnchor constant:15],
        [self.progressView.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:20],
        [self.progressView.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor constant:-20],
        
        // UIStepper
        [self.demoStepper.topAnchor constraintEqualToAnchor:self.progressView.bottomAnchor constant:15],
        [self.demoStepper.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:20],
        
        // UISegmentedControl
        [self.segmentedControl.topAnchor constraintEqualToAnchor:self.demoStepper.bottomAnchor constant:15],
        [self.segmentedControl.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:20],
        [self.segmentedControl.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor constant:-20],
        
        // 图片区域标题
        [imageSectionLabel.topAnchor constraintEqualToAnchor:self.segmentedControl.bottomAnchor constant:25],
        [imageSectionLabel.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:20],
        [imageSectionLabel.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor constant:-20],
        [imageSectionLabel.heightAnchor constraintEqualToConstant:30],
        
        // 本地图片 ImageView
        [self.localImageView.topAnchor constraintEqualToAnchor:imageSectionLabel.bottomAnchor constant:10],
        [self.localImageView.centerXAnchor constraintEqualToAnchor:self.scrollView.centerXAnchor],
        [self.localImageView.widthAnchor constraintEqualToConstant:200],
        [self.localImageView.heightAnchor constraintEqualToConstant:150],
        
        // 图片切换按钮
        [self.imageToggleButton.topAnchor constraintEqualToAnchor:self.localImageView.bottomAnchor constant:10],
        [self.imageToggleButton.centerXAnchor constraintEqualToAnchor:self.scrollView.centerXAnchor],
        [self.imageToggleButton.widthAnchor constraintEqualToConstant:120],
        [self.imageToggleButton.heightAnchor constraintEqualToConstant:35],
        [self.imageToggleButton.bottomAnchor constraintEqualToAnchor:self.scrollView.bottomAnchor constant:-30]
    ]];
}

#pragma mark - 图片处理方法

- (void)loadCurrentImage {
    NSString *imageName = self.isShowingFirstImage ? @"1.png" : @"2.png";
    UIImage *image = [UIImage imageNamed:imageName];
    
    if (image) {
        self.localImageView.image = image;
        [self.imageToggleButton setTitle:self.isShowingFirstImage ? @"切换到图片2" : @"切换到图片1"
                                forState:UIControlStateNormal];
        
        // 更新主标签显示当前图片信息
        self.demoLabel.text = [NSString stringWithFormat:@"当前显示: %@", imageName];
    } else {
        // 如果图片不存在,显示提示信息
        self.localImageView.image = nil;
        self.localImageView.backgroundColor = [UIColor systemRedColor];
        
        // 创建提示文本图像
        UIGraphicsBeginImageContext(CGSizeMake(200, 150));
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 200, 150)];
        [[UIColor systemRedColor] setFill];
        [path fill];
        
        NSString *warningText = @"图片未找到";
        NSDictionary *attributes = @{
            NSForegroundColorAttributeName: [UIColor whiteColor],
            NSFontAttributeName: [UIFont systemFontOfSize:14]
        };
        CGRect textRect = [warningText boundingRectWithSize:CGSizeMake(200, 150)
                                                   options:NSStringDrawingUsesLineFragmentOrigin
                                                attributes:attributes
                                                   context:nil];
        [warningText drawInRect:CGRectMake((200 - textRect.size.width) / 2,
                                         (150 - textRect.size.height) / 2,
                                         textRect.size.width,
                                         textRect.size.height)
                 withAttributes:attributes];
        
        UIImage *warningImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        self.localImageView.image = warningImage;
        [self.imageToggleButton setTitle:@"图片加载失败" forState:UIControlStateNormal];
        self.imageToggleButton.backgroundColor = [UIColor systemGrayColor];
        
        NSLog(@"警告: 图片 '%@' 未找到,请确保图片已添加到项目中", imageName);
    }
}

- (void)toggleImageButtonTapped:(UIButton *)sender {
    // 切换图片状态
    self.isShowingFirstImage = !self.isShowingFirstImage;
    
    // 加载对应的图片
    [self loadCurrentImage];
    
    // 添加切换动画
    [UIView transitionWithView:self.localImageView
                     duration:0.3
                      options:UIViewAnimationOptionTransitionFlipFromLeft
                   animations:nil
                   completion:nil];
}

#pragma mark - 控件事件处理方法

// 按钮点击事件
- (void)buttonTapped:(UIButton *)sender {
    NSLog(@"按钮被点击");
    
    // 更新 UILabel
    self.demoLabel.text = @"按钮已点击!";
    self.demoLabel.textColor = [UIColor systemRedColor];
    
    // 切换 UISwitch 状态
    [self.demoSwitch setOn:!self.demoSwitch.isOn animated:YES];
    
    // 改变 UISlider 值
    float newValue = (self.demoSlider.value + 10) > 100 ? 0 : self.demoSlider.value + 10;
    [self.demoSlider setValue:newValue animated:YES];
    
    // 控制 UIActivityIndicatorView
    if (self.activityIndicator.isAnimating) {
        [self.activityIndicator stopAnimating];
    } else {
        [self.activityIndicator startAnimating];
    }
    
    // 更新 UIProgressView
    float newProgress = self.progressView.progress + 0.1;
    if (newProgress > 1.0) newProgress = 0.0;
    [self.progressView setProgress:newProgress animated:YES];
    
    // 改变 UIStepper 值
    self.demoStepper.value = (self.demoStepper.value + 1) > 10 ? 0 : self.demoStepper.value + 1;
    
    // 切换 UISegmentedControl
    NSInteger nextIndex = (self.segmentedControl.selectedSegmentIndex + 1) % self.segmentedControl.numberOfSegments;
    [self.segmentedControl setSelectedSegmentIndex:nextIndex];
    
    // 改变 UIImageView 背景色
    UIColor *randomColor = [UIColor colorWithRed:arc4random_uniform(255)/255.0
                                         green:arc4random_uniform(255)/255.0
                                          blue:arc4random_uniform(255)/255.0
                                         alpha:1.0];
    self.demoImageView.backgroundColor = randomColor;
    
    // 新增:同时切换本地图片
    [self toggleImageButtonTapped:sender];
}

// 文本输入框变化
- (void)textFieldDidChange:(UITextField *)textField {
    self.demoLabel.text = textField.text;
}

// Switch 状态变化
- (void)switchChanged:(UISwitch *)sender {
    NSString *state = sender.isOn ? @"开" : @"关";
    NSLog(@"Switch 状态: %@", state);
    self.demoLabel.text = [NSString stringWithFormat:@"Switch: %@", state];
}

// Slider 值变化
- (void)sliderValueChanged:(UISlider *)sender {
    NSLog(@"Slider 值: %.2f", sender.value);
    self.progressView.progress = sender.value / 100;
}

// Stepper 值变化
- (void)stepperValueChanged:(UIStepper *)sender {
    NSLog(@"Stepper 值: %.0f", sender.value);
    self.demoLabel.text = [NSString stringWithFormat:@"Stepper: %.0f", sender.value];
}

// SegmentedControl 变化
- (void)segmentedControlChanged:(UISegmentedControl *)sender {
    NSString *selected = [sender titleForSegmentAtIndex:sender.selectedSegmentIndex];
    NSLog(@"选择了: %@", selected);
    self.demoLabel.text = [NSString stringWithFormat:@"选择了: %@", selected];
}

// 点击空白处收起键盘
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}

@end

三、手机效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值