文章的目的为了记录使用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
三、手机效果

1288

被折叠的 条评论
为什么被折叠?



