使用语言:swift
在Xcode的mian文件中查找控件:command + shift + L
UILabel
swift
//创建一个label
let label:UILabel = UILabel(frame: CGRectMake(20, 100, 280, 100))
// let label = UILabel(frame: CGRect(x: 100, y: 100, width: 150, height: 40))
label.text = "i am a label,i like ios,i like phone"
//设置字体
label.font = UIFont.boldSystemFont(ofSize: 20)
//设置字体颜色
label.textColor = UIColor.red
//设置label的背景颜色
label.backgroundColor = UIColor.blue
//设置文字的居中
label.textAlignment = NSTextAlignment.center
//设置label的阴影
// label.shadowColor = UIColor.orange
// label.shadowOffset = CGSizeMake(10, 10)//向右向下偏移10像素
//设置label行数:在label的尺寸内将长句换行
// 0表示无限行
label.numberOfLines = 2
self.view.addSubview(label)//把标签和视图关联
1.文本的常用字体样式:

2.背景常用的颜色样式:

3.常用颜色构造:
1.UIColor(white:alpha:):是一种快速创建灰度颜色的方法,white 是亮度值(0 是黑,1 是白),适合创建背景、灰色文字等
2.UIColor(red:green:blue:alpha:):通过 RGB 值创建自定义颜色
UIButton
swift
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//创建并设置button类型
/*
case custom = 0 //自定义,无类型
@available(iOS 7.0, *)
case system = 1 //标准的系统类型
case detailDisclosure = 2
case infoLight = 3
case infoDark = 4 //详情的按钮样式
case contactAdd = 5 //添加的按钮样式
*/
let button:UIButton = UIButton(type: .system)
button.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
button.backgroundColor = UIColor.orange
//添加事件
//而 addTarget 传递的 selector 不支持带外部标签的写法,所以必须用 _ 省略标签
button.addTarget(self, action: #selector(click(_:)), for: .touchUpInside)
//设置按钮标题
button.setTitle("an niu", for: .normal)
self.view.addSubview(button)
}
//必须声明这个方法,前面加 @objc才能被Selector调用
//按钮的点击事件需要 Objective-C runtime 支持
@objc func click(_ btn:UIButton){
print("按钮被点击了")
btn.backgroundColor = UIColor.blue
}
常用按钮样式






UIImageView
swift
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//创建一个imageview对象
let imageView = UIImageView(frame: CGRectMake(100, 100, 200, 200))
//给imageview设置图片
imageView.image = UIImage(named: "p1.jpg")
//设置imageview的背景颜色
imageView.backgroundColor = UIColor.red
self.view.addSubview(imageView)
//设置imageView的动画效果
var array:Array<UIImage?> = Array()
for i in 1...4 {
let image:UIImage? = UIImage(named: "p\(i).jpg")
array.append(image)
}
//设置动画数组
imageView.animationImages = array as? [UIImage]
//设置动画的播放次数
// 0表示循环播放
imageView.animationRepeatCount = 0
//设置播放一轮的时间
imageView.animationDuration = 3
//开始播放动画
imageView.startAnimating()
}
contentMode
contentMode 是 UIImageView 的属性,用来控制图片如何在 UIImageView 的 frame 内缩放、对齐。

控件的layer属性
swift
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//layer层专门对控件的视图进行渲染
let imageView:UIImageView = UIImageView(frame: CGRectMake(100, 100, 100, 100))
imageView.backgroundColor = UIColor.red
//设置圆角
//imageView.layer.masksToBounds = true
//imageView.layer.cornerRadius = 50 //此时为圆形了
//设置边框
imageView.layer.borderWidth = 2
imageView.layer.borderColor = UIColor.green.cgColor
//设置阴影
imageView.layer.shadowColor = UIColor.brown.cgColor
imageView.layer.shadowOffset = CGSizeMake(10,10)
imageView.layer.shadowOpacity = 1 //设置为不透明
self.view.addSubview(imageView)
}
searchBar
1.相关属性和UI方面
swift
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//搜索框控件
//创建一个搜索框
let searchBar:UISearchBar = UISearchBar(frame: CGRect(x: 20 ,y: 100 ,width: 320 ,height: 180))
//设置输入框上的默认提示语
searchBar.placeholder = "请输入关键字"
//设置搜索框上显示的默认文字
searchBar.text = "你好"
//设置搜索框风格
searchBar.barStyle = UIBarStyle.default
//设置搜索框背景文字
searchBar.prompt = "这是背景文字"
//设置相应功能按键的显示与否
// searchBar.showsBookmarkButton = true
searchBar.showsSearchResultsButton = true
//设置渲染颜色
searchBar.tintColor = UIColor.red
//设置搜索框颜色
searchBar.barTintColor = UIColor.blue
// 刷新布局,必写
//让控件根据内部子控件内容,自动重新计算、适配自身宽高尺寸,覆盖你手动设置的frame宽高。
searchBar.sizeToFit()
self.view.addSubview(searchBar)
}
2.与用户交互方面
swift
import UIKit
class ViewController: UIViewController,UISearchBarDelegate {
//创建一个搜索框
var searchBar:UISearchBar = UISearchBar(frame: CGRect(x: 20 ,y: 100 ,width: 320 ,height: 180))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//搜索框控件
//设置附件视图
searchBar.scopeButtonTitles = ["1","2","3","4"]
//展示附件视图
searchBar.showsScopeBar = true
searchBar.selectedScopeButtonIndex = 0
//设置输入框上的默认提示语
searchBar.placeholder = "请输入关键字"
//设置搜索框上显示的默认文字
// searchBar.text = "你好"
//设置搜索框风格
searchBar.barStyle = UIBarStyle.default
//设置搜索框背景文字
// searchBar.prompt = "这是背景文字"
//设置相应功能按键的显示与否
searchBar.showsBookmarkButton = true
// searchBar.showsSearchResultsButton = true
//设置渲染颜色
// searchBar.tintColor = UIColor.red
//设置搜索框颜色
// searchBar.barTintColor = UIColor.blue
//设置代理
searchBar.delegate = self
self.view.addSubview(searchBar)
}
//我们点击输入框时会弹出系统键盘,但是默认收不回去了
//点击屏幕时系统键盘收起
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
searchBar.resignFirstResponder()//注销第一响应
}
//代理回调函数
//点击附件视图代理方法的回调
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
print(selectedScope)
}
//当输入框文字变化时调用的方法
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// print(searchText)
}
//点击图书按钮时触发的方法
func searchBarBookmarkButtonClicked(_ searchBar: UISearchBar) {
print("点击了图书按钮")
}
//点击结果按钮时触发的方法
func searchBarResultsListButtonClicked(_ searchBar: UISearchBar) {
}
//将要进入编辑状态时触发的方法
//false不能进入编辑状态
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
return true
}
///将要结束编辑状态时触发的方法
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
return true
}
//检测用户的输入文字
func searchBar(_ searchBar: UISearchBar, shouldChangeTextInRanges ranges: [NSValue], replacementText: String) -> Bool {
print(replacementText)
return true
}
//点击取消按钮时触发的方法
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
}
//点击"搜索"按钮时触发的方法
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
}
}
UISwitch
swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//创建一个开关控件
//大小是系统固定的,影响的只有位置
let mySwitch:UISwitch = UISwitch(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
//添加触发事件
mySwitch.addTarget(self, action: #selector(click(_:)), for: .valueChanged)
//设置滑块的颜色
mySwitch.thumbTintColor = UIColor.red
//设置开关开启的颜色
mySwitch.onTintColor = UIColor.blue
//开关的渲染颜色
mySwitch.tintColor = UIColor.green
self.view.addSubview(mySwitch)
}
@objc func click(_ sw:UISwitch){
if sw.isOn{
self.view.backgroundColor = UIColor.gray
}else{
self.view.backgroundColor = UIColor.brown
}
}
}
对绑定事件和执行回调的理解
swift
//......
//添加触发事件
mySwitch.addTarget(self, action: #selector(click(_:)), for: .valueChanged)
//回调方法
@objc func click(_ sw:UISwitch){
if sw.isOn{
self.view.backgroundColor = UIColor.gray
}else{
self.view.backgroundColor = UIColor.brown
}
}
1.语法解释
上面的绑定事件:
1、#selector()
Swift 语法:编译期校验方法是否存在,写错函数名 Xcode 直接报错(老式Selector("字符串")写错要运行才崩溃)。
2.、click(_ :)
click:绑定的方法名;
_ : 冒号代表这个函数需要接收 1 个参数(对应下面click(_ sw:UISwitch)的入参),有几个参数就写几个::
- 无参函数:#selector(click)
- 1 个参数:#selector(click(_ :))(现在的写法)
- 2 个参数:#selector(click(_ :))
下面的回调函数:
1、@objc
Swift 的 addTarget 底层依赖 Objective-C 运行时,不加 @objc,OC 找不到这个 Swift 方法,点击 / 切换开关就找不到函数、直接崩溃。
作用:把 Swift 函数暴露给 OC 运行环境识别。
2、_ sw:UISwitch
- _ :省略外部参数标签,调用时不用写参数名,直接 click(控件),对应 selector 写法必须带_:
- sw:形参名,系统自动把触发事件的 UISwitch 控件传进来,sw.isOn 就是读取开关当前开 / 关状态;
- UISwitch:限定参数类型只能是开关控件。
2.回调逻辑步骤
第 1 步:你注册 "我要监听这个控件的事件"
swift
switch.addTarget(
self, // 目标:事件来了交给"当前控制器"处理
action: #selector(click(_:)), // 用哪个方法来响应
for: .valueChanged // 监听什么事件:开关"值变了"
)
你在这里没有调用 click,只是告诉系统:将来发生事时帮我调它。
第 2 步:用户动手(滑动开关)
- 用户手指滑开关 → 开关内部检测到 "值变了"
- 开关内部触发 UIControlEvent.valueChanged 事件
第 3 步:系统自动执行回调(核心!)
等价于系统帮你写了一句:
swift
self.click(switch)
所以:click(_ :) 是系统调用的,不是你手动调用的。
第 4 步:你的 click(_ :)执行
UISegementControl
1.相关属性和UI方面
swift
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//创建分段控制器控件
let seg:UISegmentedControl = UISegmentedControl(frame: CGRectMake(20, 100, 280, 40))
//设置按钮
seg.insertSegment(withTitle: "第一第一第一第一第一第一个按钮", at: 0, animated: true)
seg.insertSegment(withTitle: "第二个按钮", at: 1, animated: true)
//添加点击事件
seg.addTarget(self, action: #selector(click(_:)), for: .valueChanged)
//设置分段控制器是否保持选中状态
//true表示无法选中
seg.isMomentary = false
//设置宽度的自适应
// seg.apportionsSegmentWidthsByContent = true
//手动设置某个item的宽度
seg.setWidth(60, forSegmentAt: 0)
//设置内容区域的偏移量
seg.setContentOffset(CGSizeMake(10, 10), forSegmentAt: 1)
//手动设置默认选中item
seg.selectedSegmentIndex = 0
//设置渲染映射
seg.tintColor = UIColor.red
self.view.addSubview(seg)
}
@objc func click(_ seg:UISegmentedControl){
print(seg.selectedSegmentIndex,"按钮被点击")
}
2.切换视图方面
先在Main文件中拖取Navigation Controller视图
swift
import UIKit
class ViewController: UIViewController {
//创建两个视图
let viewBlue:UIView = UIView(frame: CGRectMake(0,0,320, 568))
let viewRed:UIView = UIView( frame: CGRectMake(0,0, 320, 568))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let seg: UISegmentedControl = UISegmentedControl(items:
["blue", "red"])
seg.addTarget(self, action: #selector(change(_:)),
for: .valueChanged)
self.navigationItem.titleView = seg
viewBlue.backgroundColor = UIColor.blue
viewRed.backgroundColor = UIColor.red
self.view.addSubview(viewBlue)
self.view.addSubview(viewRed)
//先把蓝色的放在上面,就会把红色挡住
self.view.bringSubviewToFront(viewBlue)
seg.selectedSegmentIndex = 0
}
@objc func change(_ seg:UISegmentedControl){
if seg.selectedSegmentIndex == 0 {
self.view.bringSubviewToFront(viewBlue)
}else{
self.view.bringSubviewToFront(viewRed)
}
}
}
UITextField
1.相关属性和UI方面
swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let textField:UITextField = UITextField(frame:
CGRectMake (20, 100, 280, 40))
//设置输入框风格为line
// textField.borderStyle = UITextField.BorderStyle.line
//设置输入框风格为bezel
textField.borderStyle = UITextField.BorderStyle.bezel
//设置输入框的提示文字
textField.placeholder = "请输入文字"
//设置输入字体颜色
textField.textColor = UIColor.red
//设置输入字体样式
textField.font = UIFont.italicSystemFont(ofSize: 15)
//设置文字的对齐方式
textField.textAlignment = NSTextAlignment.center
//设置背景颜色
// textField.backgroundColor = UIColor.red
//是否每次进入编辑状态时都清空输入框中的文字
textField.clearsOnBeginEditing = true
//是否字体大小自适应
textField.adjustsFontSizeToFitWidth = true
//设置输入框为无效
// textField.isEnabled = false
//设置输入框的左视图
let viewLeft:UIView = UIView(frame: CGRectMake (0,0,40,40))
let viewRight:UIView = UIView(frame: CGRectMake(0,0, 40,40))
viewLeft.backgroundColor = UIColor.blue
viewRight.backgroundColor = UIColor.green
textField.leftView = viewLeft
textField.rightView = viewRight
//设置左右视图的显示模式
textField.leftViewMode = UITextField.ViewMode.always
textField.rightViewMode = UITextField.ViewMode.always
//设置弹出的交互键盘
let board:UIView = UIView(frame: CGRectMake (0,0,320,80))
board.backgroundColor = UIColor.orange
// textField.inputView = board
//设置附键盘视图
textField.inputAccessoryView = board
self.view.addSubview(textField)
}
}
2.与用户交互方面
swift
import UIKit
class ViewController: UIViewController,UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let textField:UITextField = UITextField(frame:
CGRectMake (20, 100, 280, 40))
//设置输入框风格为line
// textField.borderStyle = UITextField.BorderStyle.line
//设置输入框风格为bezel
textField.borderStyle = UITextField.BorderStyle.bezel
//设置输入框的提示文字
textField.placeholder = "请输入文字"
//设置输入字体颜色
textField.textColor = UIColor.red
//设置输入字体样式
textField.font = UIFont.italicSystemFont(ofSize: 15)
//设置文字的对齐方式
textField.textAlignment = NSTextAlignment.center
//设置背景颜色
// textField.backgroundColor = UIColor.red
//是否每次进入编辑状态时都清空输入框中的文字
textField.clearsOnBeginEditing = true
//是否字体大小自适应
textField.adjustsFontSizeToFitWidth = true
//设置输入框为无效
// textField.isEnabled = false
//设置输入框的左视图
let viewLeft:UIView = UIView(frame: CGRectMake (0,0,40,40))
let viewRight:UIView = UIView(frame: CGRectMake(0,0, 40,40))
viewLeft.backgroundColor = UIColor.blue
//viewRight.backgroundColor = UIColor.green
textField.leftView = viewLeft
textField.rightView = viewRight
//设置左右视图的显示模式
textField.leftViewMode = UITextField.ViewMode.always
textField.rightViewMode = UITextField.ViewMode.always
//设置弹出的交互键盘
let board:UIView = UIView(frame: CGRectMake (0,0,320,80))
board.backgroundColor = UIColor.orange
// textField.inputView = board
//设置附键盘视图
textField.inputAccessoryView = board
//设置代理
textField.delegate = self
//设置文本框清除按钮的显示模式
textField.clearButtonMode = UITextField.ViewMode.always
self.view.addSubview(textField)
}
//代理方法
//当输入改变时调用的方法
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
print(string)
return true
}
//已经进入编辑状态时调用的方法
func textFieldDidBeginEditing(_ textField: UITextField) {
print("didBegin")
}
//结束编辑状态时调用的方法
func textFieldDidEndEditing(_ textField: UITextField) {
print("didEnd")
}
//将要进入编辑状态时调用的方法
//false表示不能进入编辑状态
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
print("shouldBegin")
return true
}
//将要结束编辑状态时调用的方法
//false表示不能进入结束编辑状态
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
print("shouldEnd")
return true
}
//设置清除键模式是否生效
func textFieldShouldClear(_ textField: UITextField) -> Bool{
return true
}
//点击键盘中return键触发的方法
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
UISlider
swift
import UIKit
class ViewController: UIViewController {
//创建一个滑块对象
let slider:UISlider = UISlider(frame: CGRectMake(20,100, 280, 40))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//滑块控件UISlider
//添加一个控制方法
slider.addTarget(self, action: #selector(slider(_:)), for: .valueChanged)
//设置滑块的取值范围
slider.maximumValue = 100
slider.minimumValue = 1
//设置是否在滑动时持续触发方法
//false代表停止滑动时才触发方法
slider.isContinuous = true
//设置滑动轴的颜色
slider.minimumTrackTintColor = UIColor.red
slider.maximumTrackTintColor = UIColor.yellow
self.view.addSubview(slider)
}
@objc func slider(_ mysl:UISlider){
print(mysl.value)
}
//点击屏幕滑块到任意位置
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
slider.setValue((Float)(arc4random()%99+1), animated: true)
}
}
UISlider的实操
实现通过滑块的滑动改变图片的大小
swift
import UIKit
class ViewController: UIViewController {
let imageView: UIImageView = UIImageView(frame: CGRectMake(0, 0, 320,400))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let slider:UISlider = UISlider(frame: CGRectMake(20, self.view.frame.size.height - 60,280, 20)) ;
self.view.addSubview(slider);
slider.addTarget(self, action: #selector(slider(_:)),
for: .valueChanged)
slider.maximumValue = 100
slider.minimumValue = 0
imageView.image = UIImage(named:"p1.jpg")
self.view.addSubview( imageView)
}
@objc func slider(_ mysl:UISlider){
let value:Float = 1-mysl.value/100
imageView.bounds = CGRectMake(0, 0,320*(CGFloat) (value), 400*(CGFloat) (value))
}
}
UIActivityIndicatorView
swift
import UIKit
class ViewController: UIViewController {
//创建一个活动提示控件
let act:UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRect(x: 320/2-10, y: 568/2, width: 20, height: 20))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// UIActivityIndicatorView -- 加载时出现的小圈圈
self.view.backgroundColor = UIColor.gray
//设置提示圈颜色
act.color = UIColor.red
//使用时要设置开始动画
act.startAnimating()
self.view.addSubview(act)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//停止活动
act.stopAnimating()
}
}
UIProgressView
swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//进度条控件
let progress:UIProgressView = UIProgressView(progressViewStyle: UIProgressView.Style.default)
progress.frame = CGRect(x: 20, y: 100, width: 280, height: 20)
//设置进度条进度 0-1
progress.progress = 0.5
//设置走过的进度颜色
progress.progressTintColor = UIColor.red
//设置没走过的进度颜色
progress.trackTintColor = UIColor.green
self.view.addSubview(progress)
}
}
UIPageControl
swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//创建一个分页控制器
let page:UIPageControl = UIPageControl(frame: CGRect(x: 150, y: 100, width: 100, height: 30))
self.view.backgroundColor = UIColor.red
//设置分页页数
page.numberOfPages = 4
//设置当前页码,下标从0开始
page.currentPage = 3
//设置只有一页时,是否自动隐藏
//true代表会自动隐藏
page.hidesForSinglePage = false
//设置分页控制器的当前页颜色
page.currentPageIndicatorTintColor = UIColor.blue
//设置分页点颜色
page.pageIndicatorTintColor = UIColor.purple
//添加方法
page.addTarget(self, action: #selector(change(_:)), for: .valueChanged)
self.view.addSubview(page)
}
@objc func change(_ pg:UIPageControl){
print(pg.currentPage) //打印当前页号
}
}
UIStepper
swift
import UIKit
class ViewController: UIViewController {
let label:UILabel = UILabel(frame: CGRect(x: 100, y: 300, width: 100, height: 100))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//创建一个Stepper步进控制器
let steper:UIStepper = UIStepper(frame: CGRect(x: 100, y: 100, width: 100, height: 40))
label.text = String(format: "%f", steper.value)
//设置最大值和最小值。默认是[0,100]
steper.maximumValue = 10
steper.minimumValue = 0
//设置步长
steper.stepValue = 2
//是否连续触发响应函数
steper.isContinuous = false
//值是否持续改变
//false表示长按后松手值不会改变
steper.autorepeat = false
//设置到达最值后是否可以循环触发
steper.wraps = true
//设置控件的颜色
steper.tintColor = UIColor.red //err
//添加方法
steper.addTarget(self, action: #selector(change(_:)), for: .valueChanged)
self.view.addSubview(steper)
self.view.addSubview(label)
}
@objc func change(_ steper:UIStepper){
//改变值时显示在标签里
label.text = String(format: "%f", steper.value)
}
}
UIAlertController
1.UIAlertController = 弹窗本身
就是你看到的那个白色框、标题、消息。
2.UIAlertAction = 弹窗里的按钮
就是 "确定""取消""删除" 这些可点击的按钮。
3.addAction = 把按钮加到弹窗里
1.AlertView
swift
import UIKit
class ViewController: UIViewController,UIAlertViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//使用旧方法创建警告框
// let alertView:UIAlertView = UIAlertView(title: "alert", message: "look me", delegate: self, cancelButtonTitle: "cancel", otherButtonTitles: "sure")
//
// //设置alertView的风格
// alertView.alertViewStyle = UIAlertViewStyle.loginAndPasswordInput
//
// alertView.show()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//使用新方法创建警告框
//UIAlertController不用代理,靠闭包 handler 接收点击事件。
let alertView:UIAlertController = UIAlertController(title: "alert", message: "look me", preferredStyle: UIAlertController.Style.alert)
//添加了一个封装了操作逻辑的按钮
let alertActionOne:UIAlertAction = UIAlertAction(title: "cancel", style: UIAlertAction.Style.destructive, handler: {
(alert) -> Void in print("cancel")
})
//添加一个输入框
alertView.addTextField(configurationHandler: {
(textField) -> Void in textField.placeholder = "hello world"
})
alertView.addAction(alertActionOne)
//弹出警告框
self.present(alertView, animated: true)
}
//代理回调方法
// func alertView(alertView:UIAlertView, clickedButtonAtIndex buttonIndex:Int){
// print(buttonIndex)
// }
}
为什么使用新方法创建警告框要重写在touchesBegan里,不能直接写在viewDidLoad?
1、viewDidLoad 阶段页面还没渲染、控制器还没完成挂载到屏幕上,不能执行 present 弹窗;
2、touchesBegan 是点击屏幕后、页面已经完全加载完毕,此时可以正常弹窗。
2.ActionSheet
swift
import UIKit
class ViewController: UIViewController ,UIActionSheetDelegate{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//警告弹窗
//使用旧的方法创建actionSheet
// let sheet: UIActionSheet = UIActionSheet(title: "actionSheet",delegate: self, cancelButtonTitle: "cancel",
// destructiveButtonTitle: "delete")
//
// sheet.show(in: self.view
}
//使用xin的方法创建actionSheet
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//创建一个警告弹窗
let actionSheet:UIAlertController = UIAlertController(title:"actionSheet", message: "look me", preferredStyle:
UIAlertController.Style.actionSheet)
let actionAction:UIAlertAction = UIAlertAction(title:"one",style: UIAlertAction.Style.default) {(action) -> Void in
print("helle world")
}
let actionActionOther:UIAlertAction = UIAlertAction(title:"cancel", style: UIAlertAction.Style.cancel) { (action) -> Void in print("cancel")
}
actionSheet.addAction(actionAction)
actionSheet.addAction (actionActionOther)
//弹出警告框
self.present(actionSheet, animated: true)
}
//代理方法,点击按钮时触发
// func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int) {
// print(buttonIndex)
// }
}
UIScrollView
一共包含两个部分:
相关属性和UI方面+与用户交互方面(代理方法)
swift
import UIKit
class ViewController: UIViewController,UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//滚动视图
let scrollView:UIScrollView = UIScrollView(frame: self.view.frame )
let view:UIView = UIView(frame:
CGRectMake (100,100,100, 100))
view.backgroundColor = UIColor.red
scrollView.addSubview(view)
//设置scrollerView的内容尺寸
scrollView.contentSize = CGSizeMake(self.view.frame.size.width*2, self.view.frame.size.height*2)
//设置回弹效果
scrollView.bounces = true
//设置指示条的位置
scrollView.scrollIndicatorInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 20.0, right: 20.0)
//设置指示条是否显示
scrollView.showsHorizontalScrollIndicator = true
//设置是否翻页效果
scrollView.isPagingEnabled = true
//设置拉伸和缩放的比值
scrollView.minimumZoomScale = 0.5
scrollView.maximumZoomScale = 2;
//设置代理
scrollView.delegate = self
self.view.addSubview(scrollView)
}
//设置拉伸和缩放操作,返回进行缩放的视图
func viewForZooming(in scrollView: UIScrollView) -> UIView?
{
return scrollView.subviews.first
}
//scrollView减速结束时触发的代理方法
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
}
//scrollView停止拖拽时触发的方法
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
}
//scrollView停止动画的时候触发的方法
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
}
//scrollView停止缩放效果时触发的方法
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
}
//scrollView进行缩放效果时触发的方法
func scrollViewDidZoom(_ scrollView: UIScrollView) {
}
//scrollView开始滑动时触发的方法
func scrollViewDidScroll(_ scrollView: UIScrollView) {
}
//scrollVie滑动到顶部时触发的方法
func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
}
//scrollVie将要滑动到顶部时触发的方法
//false代表不能进行回到顶部的操作
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
return true
}
}
UITableView
UITableView的创建流程+头尾视图的创建+编辑状态的变化+相关代理方法。
1.UITableView的创建的步骤
1.控制器遵守两个协议(必加)
dataSource:提供单元格数据;delegate:处理点击,缺少就空白
2.绑定数据源与代理
3.数据源的三个核心方法
设置分区,设置每个分区的行数,设置每行单元格
2.头尾视图的创建的步骤
首先说明,plain 样式默认没有 Header/Footer 视图。
1.设置头视图的高度
2.必须返回一个view视图,空白占位也要创建View,nil=系统默认空白不生效
3.改变编辑状态的两个步骤
1.设置具体的编辑状态
2.点击左侧删除圆圈触发
swift
import UIKit
//1. 控制器遵守两个协议(必加)
//dataSource:提供单元格数据;delegate:处理点击,缺少就空白
class ViewController: UIViewController ,UITableViewDataSource, UITableViewDelegate{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//创建tableView 风格可以是普通和分组两种
let tableView:UITableView = UITableView(frame: self.view.frame,style: UITableView.Style.grouped)
//2.绑定数据源与代理
tableView.dataSource = self
tableView.delegate = self
//重新刷新数据
tableView.reloadData()
//设置tableView的回弹效果
tableView.bounces = false
//设置tableView的编辑状态
tableView.isEditing = true
self.view.addSubview(tableView)
}
//3.数据源的三个核心方法
//分区数
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
// 行数
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10 // 一共10行
}
// 每行单元格
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = "第\(indexPath.row)行"
return cell
}
//plain 样式默认没有 Header/Footer 视图
//必须同时实现【高度方法 + 返回 header 视图】
//1.设置头视图的高度
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 100
}
//2.必须返回一个view,空白占位也要创建View,nil=系统默认空白不生效
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = UIView()
header.backgroundColor = UIColor.red //上色就能直观看到高度
return header
}
//设置尾视图的高度
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footer = UIView()
footer.backgroundColor = UIColor.blue
return footer
}
//设置cell的高度,默认时44
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
//相关代理方法
//点击cell触发的方法
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("%d, %d", indexPath.section, indexPath.row)
}
//取消选中某个cell触发的方法
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
}
//1.设置具体的编辑状态
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return UITableViewCell.EditingStyle.delete
}
//2.点击左侧删除圆圈触发
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
//1.先删除数据源
//xxxx.remove(at: indexPath.row)
//2.再删除单元格
//xxxx.deleteRows(at: [indexPath], with: .automatic)
}else if editingStyle == .insert{
//xxx.append()
}
}
//设置tableView的移动
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// let str = dataArray?[sourceIndexPath.row]
// dataArray?. removeAtIndex(sourceIndexPath.row)
// dataArray?.insert(str!, atIndex: destinationIndexPath.row)
}
}
UITextView
特点:文字链接化,还包括电话,地址,日历等类型
swift
import UIKit
class ViewController: UIViewController,UITextViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let textVew:UITextView = UITextView(frame: CGRectMake(20, 100,280, 100))
textVew.backgroundColor = UIColor.gray
//设置字体
textVew.font = UIFont.systemFont(ofSize: 25)
//设置文字颜色
textVew.textColor = UIColor.red
//设置对齐模式
textVew.textAlignment = NSTextAlignment.center
//设置是否可编辑
textVew.isEditable = true
//设置内容
// textVew.text = "你好,我是textView\n 网址:www.baidu.coml"
//设置链接化类型
textVew.dataDetectorTypes = UIDataDetectorTypes.link
//设置代理
textVew.delegate = self
self.view.addSubview(textVew)
}
//输入字符时调用
//false代表此时不能输入
func textView(_ textView: UITextView, shouldChangeTextInRanges ranges: [NSValue], replacementText text: String) -> Bool {
return false
}
//开始编辑时调用
func textViewDidBeginEditing(_ textView: UITextView) {
}
//结束编辑时调用
func textViewDidEndEditing(_ textView: UITextView) {
}
//输入改变时调用
func textViewDidChange(_ textView: UITextView) {
}
//改变选中文字时调用
func textViewDidChangeSelection(_ textView: UITextView) {
}
//将要开始编辑时调用
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
return true
}
//将要结束编辑时调用
func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
return true
}
}
UIPickerView
swift
import UIKit
class ViewController: UIViewController,UIPickerViewDelegate,UIPickerViewDataSource {
var dataArray:Array<String>?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//UIPickerView类似于UITableView,只不过UIPickerView的表现形式是滚动形式
let pickerView:UIPickerView = UIPickerView(frame: CGRect(x: 100, y: 100, width: 200, height: 150))
//设置数据源和代理
pickerView.delegate = self
pickerView.dataSource = self
dataArray = ["one","two","three","four","five"]
self.view.addSubview(pickerView)
}
//设置分区数
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
//设置每个分组的行数
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return dataArray!.count
}
//设置每一行的内容
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return dataArray?[row]
}
//设置每个分区的宽度
func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
return 100
}
}
UIDatePicker
swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//系统帮我们封装好的有关时间的操作
let datePicker:UIDatePicker = UIDatePicker(frame:
CGRectMake (100, 100, 200, 200))
//设置显示模式
datePicker.datePickerMode = UIDatePicker.Mode.dateAndTime
//继承了UIControl,可以添加绑定方法
datePicker.addTarget(self, action: #selector(changeDate(_:)), for: .valueChanged)
self.view.addSubview(datePicker)
}
@objc func changeDate(_ sp:UIDatePicker){
let date = sp.date
print(date)
}
}
UIWebView
要导入头文件 import WebKit
swift
import UIKit
import WebKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//网页视图,类似于一种简洁的网页浏览器
let webView:WKWebView = WKWebView(frame:self.view.bounds)
// 规范URL写法:https(现在苹果禁用http明文)
guard let url = URL(string: "https://www.baidu.com") else { return }
let req = URLRequest(url: url)
webView.load(req)
self.view.addSubview(webView)
}
}
UICollectionView
1.UICollectionView创建的步骤
1.控制器遵守协议
UICollectionViewDataSource:提供 item 个数、创建 cell;
UICollectionViewDelegateFlowLayout:布局、尺寸、边距、头尾部尺寸
布局类:必须搭配UICollectionViewFlowLayout(流式布局,格子排布规则)
2.绑定代理、注册 Cell
创建布局对象
创建collectionView
绑定数据源、代理
注册cell(必填,复用标识)
3.数据源的三个核心数据源方法
设置分区,设置每个分区的行数,设置每行单元格
swift
import UIKit
class ViewController: UIViewController,UICollectionViewDelegateFlowLayout,UICollectionViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//有点类似于UITableView,但是比UITableView更强大,不仅仅能设计表格类的布局,还能自定义布局(元素的大小,元素的排列方式)
let layout:UICollectionViewFlowLayout =
UICollectionViewFlowLayout()
//设置布局方向
layout.scrollDirection = UICollectionView.ScrollDirection.horizontal
//设置每个元素的大小
layout.itemSize = CGSizeMake (80, 80)
//设置元素间距
layout.minimumInteritemSpacing = 10
//设置行间距
layout.minimumLineSpacing = 30
let collectionView:UICollectionView = UICollectionView(frame:
self.view.frame, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
//注册普通 Item 单元格
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellID")
self.view.addSubview(collectionView)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath)
cell.backgroundColor = UIColor.red
return cell
}
//可以自定义色块的大小
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let tmp = indexPath.row%3 //0 1 2
if tmp == 0{
return CGSize(width: 50, height: 50)
}else if tmp == 1{
return CGSize(width: 100, height: 100)
}else{
return CGSize(width: 50, height: 50)
}
}
}
其他代理方法:
didSelectItemAt:
它是 UICollectionViewDelegate 协议的核心方法,当用户点击相册中的某张照片 / 视频单元格时,系统会自动调用这个方法。这段代码的核心逻辑是:根据用户点击的资源,调用 toggleSelection 方法来切换选中状态。
trailingSwipeActionsConfigurationForRowAt:处理单元格左滑操作。
contextMenuConfigurationForRowAt:处理单元格长按弹出菜单
2.UICollectionView的实操
做出来一个随机颜色的UICollectionView布局

自定义布局类MyLayout
swift
import UIKit
class MyLayout: UICollectionViewFlowLayout {
var itemCount:Int? //元素个数
var attributeArray:Array<UICollectionViewLayoutAttributes>? //存放layout中的布局属性
override func prepare(){
super.prepare()
attributeArray = Array()
//计算每个元素的宽度
let Width = (UIScreen.main.bounds.size.width - self.minimumInteritemSpacing) / 2
//循环设置每个元素的布局属性
var l = 0 //左边 列高
var r = 0 //右边 列高
for i in 0..<itemCount!{
let indexPath = NSIndexPath(item: i, section: 0)
let atti = UICollectionViewLayoutAttributes(forCellWith: indexPath as IndexPath)
//哪一个列高更小元素放在那一边
let height = (Int)(arc4random()%140 + 50) //随机高度
var tmp = 0//记录元素放在哪一列,0是第一列,1是第二列
var H = 0
if(l <= r){
H = l
l += (height + (Int)(self.minimumLineSpacing))
tmp = 0
}else{
H = r
r += (height + (Int)(self.minimumLineSpacing))
tmp = 1
}
//每个元素块的放置位置和大小
atti.frame = CGRect(x: Int((CGFloat)(tmp) * (Width + self.minimumInteritemSpacing)), y: (Int)(H), width: (Int)(Width), height: height)
attributeArray?.append(atti)
}
if l <= r{
self.itemSize = CGSize(width: Width, height: CGFloat((r * 2 / itemCount!)) - self.minimumLineSpacing)
}else{
self.itemSize = CGSize(width: Width, height: CGFloat((l * 2 / itemCount!)) - self.minimumLineSpacing)
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return attributeArray
}
}
ViewController.swift
swift
import UIKit
class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let myLayout = MyLayout()
myLayout.itemCount = 100
let collectionView:UICollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: myLayout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellID")
self.view.addSubview(collectionView)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath)
//给cell设置随机色
cell.backgroundColor = UIColor(red: CGFloat((CFloat)(arc4random()%255)/255.0), green: CGFloat((CFloat)(arc4random()%255)/255.0), blue: CGFloat((CFloat)(arc4random()%255)/255.0), alpha: 1)
return cell
}
}
UIStackView
用来垂直排列所有卡片的容器,它的好处是自动处理间距,不用手动给每个卡片加垂直约束。
一、核心布局属性(最常用)
1.axis:排列方向(主轴)
可选值:
.horizontal:水平排列(默认)
.vertical:垂直排列
作用:决定子视图是一行排开,还是一列排开。
swift
stackView.axis = .vertical
2.distribution:主轴方向分布方式
主轴:axis 指定的方向(水平 / 垂直)。
可选值(5 种):
.fill(默认)
拉伸子视图填满主轴空间
按 Content Hugging/Compression Resistance 决定谁被拉伸
.fillEqually
所有子视图等宽 / 等高(平分空间)
.fillProportionally
按子视图固有内容大小比例分配空间
.equalSpacing
子视图尺寸不变,间距自动相等
首尾也有空白间距
.equalCentering
子视图中心间距相等
视图不拉伸,适合图标 + 文字均匀分布

3.alignment:交叉轴对齐方式
交叉轴:与 axis 垂直的方向。
可选值:
.fill(默认) :子视图填满交叉轴
.leading / .top :靠起始边(水平→上对齐;垂直→左对齐)
.trailing / .bottom :靠结束边
.center:居中对齐
swift
// 水平stackView,子视图垂直居中
stackView.alignment = .center
4.spacing:子视图之间的间距
单位:pt
默认:0
作用:相邻子视图之间的最小间距Apple Developer
注意:distribution = .equalSpacing 时,spacing 是最小间距,实际会更大。
swift
stackView.spacing = 10
二、边距与基线相关(常用)
5.isLayoutMarginsRelativeArrangement
核心作用:
- 控制 StackView 的子视图是否以 layoutMargins 作为边界来布局。
- 默认值:false,子视图直接贴着 StackView 的边缘排列,不会留出内边距。
开启 true 时的效果:
- 子视图会自动和 layoutMargins 保持距离,不会顶到边缘;
- 你可以通过 stackView.layoutMargins 设置上下左右的内边距,子视图会自动适应。
典型用法:
swift
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
开启后,子视图就会和 StackView 边缘保持 16pt 的边距,不用再给每个子视图单独设置 leading/trailing 约束。
6.isBaselineRelativeArrangement
核心作用:
- 控制 垂直方向 子视图之间的间距,是按「视图顶部」计算,还是按「文字基线」计算。
- 默认值:false,间距是按子视图的 frame 边界计算的。
开启 true 时的效果
- 垂直 StackView 中,两个带文字的控件(比如两个 UILabel)之间的间距,会从上一行文字的基线,算到下一行文字的基线,而不是从控件的顶部 / 底部计算。
- 这样多行文本的排版会更整齐,视觉上的间距也更均匀。
举个直观例子
比如两个高度不同的 UILabel:
- false:间距按控件底部到下一个控件顶部计算,文字可能看起来挤在一起;
- true:间距按文字基线计算,两行文字的距离会更一致,排版更舒服。
适用场景:
- 垂直排列多行文本、标签、按钮,希望文字对齐更自然。
- 表单、说明文字、多行列表等排版场景。
小建议:
- 做卡片 / 列表:isLayoutMarginsRelativeArrangement = true 基本是必开的;
- 做多行文本:isBaselineRelativeArrangement = true 能让排版好看很多。
三、子视图管理属性
7.arrangedSubviews
swift
var arrangedSubviews: [UIView] { get }
只读数组:当前被 StackView 管理的子视图。
区别:
- addArrangedSubview(view):加入 arrangedSubviews,自动布局
- addSubview(view):仅添加到视图层级,不自动布局
8.addArrangedSubview(_ :) / removeArrangedSubview(_ :)
swift
func addArrangedSubview(_ view: UIView)
func removeArrangedSubview(_ view: UIView)
- 添加 / 移除受管理的子视图
- removeArrangedSubview 不会把 view 从父视图移除(只是不再管理布局)
UIViewController
Controller是将view和逻辑结合的控制器层。
本节学习的是ViewController的生命周期的相关方法。
先在main文件里再拖拽一个ViewController2界面,创建一个ViewController2.swift文件与这个界面关联,在第一个ViewController界面中放入一个"跳转"按钮,与第二个界面关联。
下面代码是在ViewController2.swift文件里写的:
swift
import UIKit
class ViewController2: UIViewController {
var tmp:Int = 0
override func loadView() {
super.loadView()
tmp += 1
print(tmp, "loadView")
}
override func viewDidLoad() {
super.viewDidLoad()
tmp += 1
print(tmp, "viewDidLoad")
// Do any additional setup after loading the view.
}
//视图将要展示时调用的方法
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tmp += 1
print(tmp, "viewWillAppear")
}
//将要布局子视图
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
tmp += 1
print(tmp, "viewWillLayoutSubviews")
}
//已经布局子视图完成
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tmp += 1
print(tmp, "viewDidLayoutSubviews")
}
//视图已经展示
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tmp += 1
print(tmp, "viewDidAppear")
}
//视图将要消失
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
tmp += 1
print(tmp, "viewWillDisappear")
}
//视图已经消失
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
tmp += 1
print(tmp, "viewDidDisappear")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//返回上一个controller
self.dismiss(animated: true, completion: nil)
}
从点击"跳转"到结束过程如下:

UINavigationController
UINavigationController 就是一个 "栈管理器"。
它用 栈(先进后出)结构 来管理一堆 UIViewController,是层级结构,负责:
1.压入页面(push)
2.弹出页面(pop)
3.显示顶部页面
4.自动生成导航栏(返回按钮、标题)
main文件准备
拖拽到导航界面

把View Controller界面与ViewController类关联
ViewController.swift文件
1、NavigationController页面与ViewController的切换
2、导航栏设置
导航栏标题规则:导航栏永远读取当前栈顶控制器的 title
- 首页在栈顶 → 显示首页
- push 新页面后新 VC 变成栈顶 → 显示新 VC 的 title(没赋值就空白)
iOS15之后的导航栏不显示且无色,要强制显示并设置背景颜色。
3、导航栏按键的自定义
swift
import UIKit
//导航栏标题规则:导航栏永远读取当前栈顶控制器的 title
//-首页在栈顶 → 显示首页
//-push 新页面后新 VC 变成栈顶 → 显示新 VC 的 title(没赋值就空白)
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// 内容自动从导航栏下方开始
edgesForExtendedLayout = []
// 强制显示导航栏
navigationController?.setNavigationBarHidden(false, animated: false)
// iOS15+强制显示导航栏底色(默认导航栏透明无底色)
let app = UINavigationBarAppearance()
app.backgroundColor = .gray
navigationController?.navigationBar.standardAppearance = app
navigationController?.navigationBar.scrollEdgeAppearance = app
self.title = "首页"
let label:UILabel = UILabel(frame: CGRect(x: 100, y: 100, width: 100, height: 30))
label.backgroundColor = UIColor.red
label.text = "hello world"
let button:UIButton = UIButton(frame: CGRect(x: 100, y: 200, width: 100, height: 30))
button.backgroundColor = UIColor.green
button.setTitle("切换", for: .normal)
button.addTarget(self, action: #selector(changeController(_:)), for: .touchUpInside)
//自定义导航栏按钮
let barButtonItem:UIBarButtonItem = UIBarButtonItem(title: "返回", style: .plain, target: self, action:#selector(back))
//只能对UI方面进行修改,无法触发方法
//self.navigationItem.backBarButtonItem = barButtonItem
self.navigationItem.leftBarButtonItem = barButtonItem
//使用系统的左右按键样式
let barR1 = UIBarButtonItem(barButtonSystemItem:
UIBarButtonItem.SystemItem.bookmarks, target:self, action:#selector(action1))
let barR2 = UIBarButtonItem(barButtonSystemItem:
UIBarButtonItem.SystemItem.camera, target: self, action:#selector(action2))
self.navigationItem.rightBarButtonItems = [barR1, barR2]
//系统的工具栏
//self.navigationController?.isToolbarHidden = false
//self.toolbarItems = [barR1, barR2]
self.view.addSubview(label)
self.view.addSubview(button)
}
@objc func changeController(_ bnt:UIButton){
let viewController:UIViewController = UIViewController()
//给新添加的页面设背景色
viewController.view.backgroundColor = UIColor.white
viewController.title = "标题2"
// 关键:自定义返回按钮文字(在上一页设置,不是新页面)
let backItem = UIBarButtonItem(title:"首页", style:.plain, target:nil, action:nil)
navigationItem.backBarButtonItem = backItem
self.navigationController?.pushViewController(viewController, animated: true)
}
@objc func back(){
print("返回")
}
@objc func action1() {
print("action1")
}
@objc func action2 () {
print("action2")
}
}
NavigationController的常用属性
一、最最常用
1.navigationBar
导航条本身(顶部那一条)
swift
navigationController?.navigationBar
你可以设置它的颜色、字体、背景、高度、隐藏分割线等。
2.viewControllers
栈里所有控制器(数组)
swift
navigationController?.viewControllers
- 第一个 = 根控制器
- 最后一个 = 当前显示的控制器
3.topViewController
当前最顶部的控制器
swift
navigationController?.topViewController
4.visibleViewController
当前正在显示的控制器(和 top 基本一样)
二、显示 / 隐藏导航栏
5.isNavigationBarHidden
隐藏 / 显示导航条
swift
navigationController?.isNavigationBarHidden = true // 隐藏
navigationController?.isNavigationBarHidden = false // 显示
带动画隐藏:
swift
navigationController?.setNavigationBarHidden(true, animated: true)
三、导航栏外观(最常用)
6.navigationBar.tintColor
导航条上按钮颜色(返回键、文字图标)
swift
navigationController?.navigationBar.tintColor = .red
7.navigationBar.barTintColor
导航条背景颜色
swift
navigationController?.navigationBar.barTintColor = .white
8.navigationBar.titleTextAttributes
导航标题字体、颜色
swift
navigationController?.navigationBar.titleTextAttributes = [
.foregroundColor: UIColor.black,
.font: UIFont.systemFont(ofSize: 17, weight: .bold)
]
9.isTranslucent
导航条半透明(默认 true)
swift
navigationController?.navigationBar.isTranslucent = false
- true:内容会从导航栏底下穿过
- false:内容从导航栏底部开始
10.去掉导航栏底部分割线(超级常用)
swift
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
四、手势(侧滑返回)
11.interactivePopGestureRecognizer
侧滑返回手势
swift
// 关闭侧滑返回
navigationController?.interactivePopGestureRecognizer?.isEnabled = false
五、页面切换(方法)
12.pushViewController 进入下一页
swift
navigationController?.pushViewController(vc, animated: true)
13.popViewController 返回上一页
swift
navigationController?.popViewController(animated: true)
14.popToRootViewController 回到根控制器
swift
navigationController?.popToRootViewController(animated: true)
UITabBarController
UITabBarController = 底部导航栏容器控制器
- 它是一个容器,专门管理多个并列页面
- 屏幕底部那一排可点击的按钮,就是它自带的 UITabBar
- 点击按钮 → 自动切换不同页面
关键点:
- 永远只显示一个子页面(当前选中的)
- 子页面之间是并列关系,不是栈
- 每个子页面最好套一层导航控制器(UINavigationController),这样才能 push 跳转
/////////////////////////////////////////////////////////////////////////////////////////////
UIStoryboard

UIStoryboard(name:bundle:) 是 iOS 中用来加载 Storyboard 文件的初始化方法。
参数:
name: 要加载的 Storyboard 文件名(不带 .storyboard 后缀)
bundle: 要从哪个「资源包」里找这个文件,一般传 nil 表示从当前 App 的主 Bundle 中加载
约束constraint
在 iOS 里,AutoLayout(自动布局)= 用 "约束公式" 代替 frame。
1.写法
swift
piece.leadingAnchor.constraint(equalTo: cornerContainer.leadingAnchor, constant: x)
piece.topAnchor.constraint(equalTo: cornerContainer.topAnchor, constant: y)
piece.widthAnchor.constraint(equalToConstant: ...)
这叫 Layout Anchors(锚点约束),是苹果推荐的、最简洁的写法。
最容易混的:equalTo 到底 "等于" 谁?
【谁.锚点】.constraint(equalTo:【和谁.锚点】, constant: 偏移)
左边:我自己(要布局的控件)
equalTo 右边:参照物(父 view 或别的控件)
constant:我相对于参照物的偏移
1.位置约束:leadingAnchor / topAnchor
swift
piece.leadingAnchor.constraint(equalTo: cornerContainer.leadingAnchor, constant: x)
- leadingAnchor = 左边那条线
- equalTo: 父视图的 leadingAnchor = 和父视图左边对齐
- constant: x = 向右偏移 x 个点(x 为负就向左)
同理:
- topAnchor = 上边那条线,constant: y 就是向下偏移 yApple Developer。
一句话:
- leading + top 就是用来定 "左上角坐标" 的。
2.大小约束:widthAnchor / heightAnchor
swift
piece.widthAnchor.constraint(equalToConstant: length)
piece.heightAnchor.constraint(equalToConstant: width)
- equalToConstant: 数值 = 固定宽 / 高,不依赖别的 view。
- 横线:width = 长,height = 粗
- 竖线:width = 粗,height = 长
一句话:
- width + height 就是用来定 "矩形尺寸" 的。
2.关键点
1.关掉 autoresizing(必须!)
swift
piece.translatesAutoresizingMaskIntoConstraints = false
意思:不用旧的 frame 布局,全权交给约束。
2.约束要激活
swift
// 写法1:单个激活
c.isActive = true
// 写法2:批量激活(推荐)
NSLayoutConstraint.activate([
piece.leadingAnchor.constraint(...),
piece.topAnchor.constraint(...)
])
不激活 = 约束只是创建了,没生效。
3.父子关系要先建立
swift
cornerContainer.addSubview(piece)
必须先 addSubview,再加约束,否则崩溃。
3.总结
leadingAnchor / topAnchor → 定坐标(x,y)
widthAnchor / heightAnchor → 定宽高
equalTo: → 相对另一个 view
equalToConstant: → 固定数值
必须:translatesAutoresizingMaskIntoConstraints = false + 激活约束。
CAShapeLayer
一、CAShapeLayer 是什么?
CAShapeLayer = 专门用来画矢量图形的图层
- CAShapeLayer:矢量绘图层(CALayer 子类),只负责渲染形状、线条、颜色
- UIBezierPath:路径容器,定义点、线、圆、圆弧、多边形等轮廓
和普通 UIView 区别:
- UIView:靠 frame 画矩形、图片
- CAShapeLayer:画任意形状(圆、弧、线、多边形、曲线)
二、使用步骤
1.使用UIBezierPath创建路径(path)
2.创建 CAShapeLayer对象layer
3.layer.path = path.cgPath
4.设置颜色、线宽
5.加到视图 layer 上(layer.addSublayer)
swift
// 1. 构造路径
let path = UIBezierPath()
// 2. 构造绘图层
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath // 关键:转 CGPath
// 3. 样式配置
shapeLayer.strokeColor = UIColor.xxx.cgColor
shapeLayer.fillColor = UIColor.xxx.cgColor
shapeLayer.lineWidth = 数值
// 4. 添加到视图
view.layer.addSublayer(shapeLayer)
三、CAShapeLayer 最常用属性
1.path
- 形状路径
- 必须传 CGPath
- 用 UIBezierPath 生成
swift
shapeLayer.path = path.cgPath
2.strokeColor
- 线条颜色
- 必须是 CGColor
swift
shapeLayer.strokeColor = UIColor.blue.cgColor
3.fillColor
- 填充颜色
- 只想画线,必须设为透明
swift
shapeLayer.fillColor = UIColor.clear.cgColor
4.lineWidth
- 线条宽度(pt)
swift
shapeLayer.lineWidth = 4
5.lineCap
- 线头样式
.butt 默认直角
.round 圆头
.square 方头
swift
shapeLayer.lineCap = .round
6.lineJoin
- 线条拐角样式
.miter 直角
.round 圆角
.bevel 斜角
swift
shapeLayer.lineJoin = .round
7.lineDashPattern
- 画虚线(常用)
swift
//→ 实线 5pt + 空 3pt
shapeLayer.lineDashPattern = [5,3] as [NSNumber]
8.strokeStart / strokeEnd
- 控制线条画多少
- 做扫描动画、进度条、路径动画必备
四、UIBezierPath 常用方法(画形状用)
1.基础移动 & 直线(画单条线、折线、L 型)
swift
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0)) // 抬起画笔,移动到起点
path.addLine(to: CGPoint(x: 50, y: 0))// 画直线
path.addLine(to: CGPoint(x: 50, y: 50))// 折角,组成 L 型
2.圆弧 / 圆形(圆环、圆角拐角、整圆)
① 整圆(快门按钮、圆形图标)
swift
let center = CGPoint(x: 40, y: 40) // 圆心
let path = UIBezierPath(
arcCenter: center,
radius: 30, // 圆半径
startAngle: 0, // 起始角度(弧度)
endAngle: 2 * .pi, // 结束角度,2π = 360° 整圆
clockwise: true // 是否顺时针绘制
)
clockwise: true:顺时针绘制圆弧
clockwise: false:逆时针绘制圆弧
它决定了画笔从 startAngle 到 endAngle 是往哪个方向走,直接影响圆弧的形状和位置。
② 局部圆弧(做圆角拐角核心)
swift
// 画 90° 圆弧(L型拐角圆角)
path.addArc(
withCenter: CGPoint(x: 20, y: 20), // 圆弧圆心
radius: 8, // 圆角半径
startAngle: -.pi/2, // 起始角度
endAngle: 0, // 结束角度
clockwise: true
)
角度速记(弧度):
0 → 向右
.pi/2 → 向下
.pi → 向左
-.pi/2 → 向上
3.圆角矩形(卡片、带圆角边框)
swift
let rect = CGRect(x: 0, y: 0, width: 200, height: 100)
let path = UIBezierPath(roundedRect: rect, cornerRadius: 12)
4.虚线
swift
let path = UIBezierPath()
path.move(to: CGPoint(x: 10, y: 20))
path.addLine(to: CGPoint(x: 200, y: 20))
let layer = CAShapeLayer()
layer.path = path.cgPath
layer.lineDashPattern = [4,4] // 实线4pt,间隔4pt
五、CAShapeLayer 使用场景
1.画圆角 L 型角(你现在的扫描框)
直角 → 圆角
用路径 + 圆弧实现
2.画圆环(快门按钮)
多层圆环
填充透明,只画线
3.圆角矩形卡片
比 cornerRadius 更流畅、不耗性能
4.虚线、分隔线
swift
lineDashPattern = [4,4]
5.扫描动画、波浪动画、圆弧进度条
靠 strokeEnd 从 0→1 动画
6.任意不规则图形
曲线、箭头、标签气泡、图标
7.带圆角的线条
比如你现在的圆滑边角
UIGraphicsGetCurrentContext
一、核心作用
- 获取当前的图形上下文(CGContext)
- 你在draw(_:)里画线条、形状、文字、图片时,必须先拿到这个上下文
- 本质上是一个全局状态指针,记录当前绘制的画布、画笔样式、坐标系统等信息
二、基础用法(标准场景:UIView 的 draw 方法)
swift
override func draw(_ rect: CGRect) {
// 1. 获取当前上下文(必须在 draw 方法里调用)
guard let ctx = UIGraphicsGetCurrentContext() else { return }
// 2. 开始绘制
// 示例:画一个红色圆形
ctx.setFillColor(UIColor.red.cgColor)
ctx.addEllipse(in: CGRect(x: 50, y: 50, width: 100, height: 100))
ctx.fill()
}
UIGraphicsGetCurrentContext() 就是获取当前 "画布" 的入口,是所有自定义绘制代码的起点,没有它就无法执行任何 Core Graphics 绘制操作。