六、彈窗提示組件:UIAlertController
UIAlertController 是 iOS 8+ 推出的彈窗/底部彈出框組件,用於替代舊版 UIAlertView 和 UIActionSheet,支持兩種樣式(alert 居中彈窗、actionSheet 底部彈出),可添加按鈕、輸入框,實現提示、確認、輸入等交互場景。
6.1 核心功能
- 提供兩種彈窗樣式:
alert(居中顯示,用於提示、確認)、actionSheet(底部彈出,用於選擇操作); - 支持添加多種類型按鈕:默認按鈕(
default)、取消按鈕(cancel)、危險按鈕(destructive,文字紅色); - 可添加文本輸入框(如賬號密碼輸入);
- 通過閉包(
handler)綁定按鈕點擊後的邏輯,無需代理。
6.2 關鍵屬性與方法
|
類別
|
屬性/方法
|
作用説明
|
|
初始化
|
|
創建彈窗: |
|
添加按鈕
|
|
添加按鈕( |
|
添加輸入框
|
|
添加文本輸入框,可配置佔位符、密碼隱藏等(如登錄場景的賬號密碼框)
|
|
顯示彈窗
|
|
在當前控制器上顯示彈窗( |
|
按鈕類型
|
|
按鈕樣式: |
6.3 代碼邏輯解析
場景1:簡單提示彈窗(僅確認按鈕)
@objc func simpleHint() {
// 1. 創建居中彈窗:標題「提示」,副標題「一個簡單提示...」,樣式.alert
let alert = UIAlertController(title: "提示", message: "一個簡單提示,請按確認繼續", preferredStyle: .alert)
// 2. 添加確認按鈕:樣式.default,點擊後打印日誌
let okAction = UIAlertAction(title: "確認", style: .default) { _ in
print("按下確認後,閉包裡的動作")
}
alert.addAction(okAction)
// 3. 顯示彈窗(帶動畫)
present(alert, animated: true)
}
場景2:危險操作彈窗(取消+刪除按鈕)
@objc func deleteSomething() {
// 1. 創建居中彈窗:標題「刪除」,提示文字紅色
let alert = UIAlertController(title: "刪除", message: "刪除字樣會變紅色的", preferredStyle: .alert)
// 2. 添加取消按鈕:樣式.cancel,點擊無邏輯(handler為nil)
let cancelAction = UIAlertAction(title: "取消", style: .cancel, handler: nil)
alert.addAction(cancelAction)
// 3. 添加刪除按鈕:樣式.destructive(紅色),點擊無邏輯
let deleteAction = UIAlertAction(title: "刪除", style: .destructive, handler: nil)
alert.addAction(deleteAction)
// 4. 顯示彈窗
present(alert, animated: true)
}
場景3:帶輸入框的登錄彈窗
@objc func login() {
// 1. 創建居中彈窗:標題「登入」,提示輸入賬號密碼
let alert = UIAlertController(title: "登入", message: "請輸入帳號與密碼", preferredStyle: .alert)
// 2. 添加賬號輸入框:佔位符「帳號」
alert.addTextField { textField in
textField.placeholder = "帳號"
}
// 3. 添加密碼輸入框:佔位符「密碼」,密碼隱藏
alert.addTextField { textField in
textField.placeholder = "密碼"
textField.isSecureTextEntry = true // 密碼隱藏為•
}
// 4. 添加取消按鈕
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
// 5. 添加登錄按鈕:點擊後獲取輸入框內容並打印
let loginAction = UIAlertAction(title: "登入", style: .default) { [weak self] _ in
// 安全獲取輸入框(alert.textFields為數組,按添加順序排列)
guard let accField = alert.textFields?.first,
let pwdField = alert.textFields?.last else { return }
print("輸入的帳號為:\(accField.text ?? "")")
print("輸入的密碼為:\(pwdField.text ?? "")")
// 此處可添加實際登錄邏輯(如網絡請求)
}
alert.addAction(loginAction)
// 6. 顯示彈窗
present(alert, animated: true)
}
場景4:底部彈出選擇框(actionSheet)
@objc func bottomAlert() {
// 1. 創建底部彈出框:樣式.actionSheet
let alert = UIAlertController(title: "底部提示", message: "這個提示會從底部彈出", preferredStyle: .actionSheet)
// 2. 添加取消按鈕(自動居底部,點擊關閉彈窗)
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
// 3. 添加確認按鈕
alert.addAction(UIAlertAction(title: "確認", style: .default))
// 4. 顯示彈窗(從底部滑入)
present(alert, animated: true)
}
6.4 注意事項
- iPad 適配問題:
actionSheet樣式在 iPad 上無法直接顯示,需通過popoverPresentationController設置錨點(如按鈕),否則會崩潰; - 輸入框安全獲取:
alert.textFields可能為nil,需用guard或可選綁定安全獲取,避免崩潰; - 閉包循環引用:若在按鈕
handler中訪問self(如調用控制器方法),需用[weak self]避免循環引用(代碼中登錄場景已添加); - 按鈕數量限制:彈窗按鈕數量建議不超過 3 個(
actionSheet可多些),過多會導致界面擁擠,需改用其他組件(如UITableView選擇列表)。
七、圖片展示組件:UIImageView
UIImageView 是用於展示圖片的組件(繼承自 UIView),支持靜態圖片顯示與動態圖片輪播(如廣告 banner),可配置圖片拉伸、縮放、內容模式,是 App 中展示圖標、封面、輪播圖的核心組件。
7.1 核心功能
- 顯示單張靜態圖片(
image屬性); - 支持多張圖片輪播(
animationImages屬性),可控制輪播時長、重複次數; - 配置圖片內容模式(如填充、居中、按比例縮放);
- 可作為手勢識別的載體(如點擊圖片跳轉)。
7.2 關鍵屬性與方法
|
類別
|
屬性/方法
|
作用説明
|
|
靜態圖片
|
|
設置單張靜態圖片(如 |
|
動態輪播
|
|
設置輪播圖片數組( |
|
|
輪播一次的總時長(秒),如 |
|
|
|
輪播重複次數( |
|
|
輪播控制
|
|
開始輪播
|
|
|
停止輪播
|
|
|
內容模式
|
|
圖片顯示模式(如 |
7.3 代碼邏輯解析
class ViewController: UIViewController {
let fullScreenSize = UIScreen.main.bounds.size
var myImageView: UIImageView! // 全局變量,用於控制輪播
override func viewDidLoad() {
super.viewDidLoad()
// 1. 創建UIImageView:大小200x200
myImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
// 2. 配置輪播圖片:需確保項目中存在"01.jpg"、"02.jpg"、"03.jpg"
let imgArr = [
UIImage(named: "01.jpg")!,
UIImage(named: "02.jpg")!,
UIImage(named: "03.jpg")!
]
myImageView.animationImages = imgArr // 設置輪播數組
// 3. 配置輪播參數:6秒一輪,無限循環
myImageView.animationDuration = 6
myImageView.animationRepeatCount = 0 // 0=無限
// 4. 開始輪播
myImageView.startAnimating()
// 5. 位置:屏幕中上部,加入視圖
myImageView.center = CGPoint(x: fullScreenSize.width * 0.5, y: fullScreenSize.height * 0.4)
self.view.addSubview(myImageView)
// 6. 創建「播放」按鈕:點擊繼續輪播
let playBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 64, height: 64))
playBtn.setImage(UIImage(named: "play"), for: .normal) // 播放圖標
playBtn.addTarget(self, action: #selector(play), for: .touchUpInside)
playBtn.center = CGPoint(x: fullScreenSize.width * 0.35, y: fullScreenSize.height * 0.65)
self.view.addSubview(playBtn)
// 7. 創建「停止」按鈕:點擊停止輪播
let stopBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 64, height: 64))
stopBtn.setImage(UIImage(named: "stop"), for: .normal) // 停止圖標
stopBtn.addTarget(self, action: #selector(stop), for: .touchUpInside)
stopBtn.center = CGPoint(x: fullScreenSize.width * 0.65, y: fullScreenSize.height * 0.65)
self.view.addSubview(stopBtn)
}
// 8. 播放按鈕回調
@objc func play() {
print("play images auto play")
myImageView.startAnimating()
}
// 9. 停止按鈕回調
@objc func stop() {
print("stop images auto play")
myImageView.stopAnimating()
}
}
7.4 注意事項
- 圖片資源導入:需將圖片文件(如
01.jpg、play.png)拖入 Xcode 項目,並確保「Add to targets」勾選當前項目,否則UIImage(named:)會返回nil,導致崩潰(建議用guard let安全獲取); - 輪播性能問題:輪播圖片過多或尺寸過大會佔用內存,建議對圖片進行壓縮,或使用「懶加載」僅加載當前顯示的圖片;
- 內容模式選擇:若圖片尺寸與
UIImageView不一致,需設置contentMode:
.scaleAspectFit:按比例縮放,圖片完整顯示(可能留空白);.scaleAspectFill:按比例縮放,填滿視圖(可能裁剪邊緣,需配合clipsToBounds = true);.scaleToFill:拉伸圖片填滿視圖(可能變形,不推薦)。
八、日期時間選擇組件:UIDatePicker
UIDatePicker 是用於選擇日期、時間的原生組件(繼承自 UIControl),支持多種選擇模式(如日期+時間、僅日期、僅時間),可配置時間範圍、分鐘間隔、顯示語言,無需自定義佈局,適用於生日選擇、預約時間選擇等場景。
8.1 核心功能
- 提供多種選擇模式:日期+時間(
dateAndTime)、僅日期(date)、僅時間(time)、倒計時(countDownTimer); - 限制可選時間範圍(
minimumDate最小日期、maximumDate最大日期); - 自定義分鐘間隔(如 15 分鐘一步);
- 支持多語言顯示(
locale屬性,如中文、英文); - 通過
target-action綁定日期變化後的回調,實時獲取選擇結果。
8.2 關鍵屬性與方法
|
類別
|
屬性/方法
|
作用説明
|
|
初始化
|
|
創建日期選擇器,通常設置寬度為屏幕寬度(適配不同設備)
|
|
選擇模式
|
|
設置模式: |
|
時間範圍
|
|
設置可選的最小/最大日期( |
|
分鐘間隔
|
|
設置分鐘選擇間隔(如 |
|
語言配置
|
|
設置顯示語言(如 |
|
日期回調
|
|
綁定日期變化事件( |
|
日期格式化
|
|
將 |
8.3 代碼邏輯解析
class ViewController: UIViewController {
let fullScreenSize = UIScreen.main.bounds.size
var myDatePicker: UIDatePicker!
var myLabel: UILabel! // 用於顯示選擇的日期時間
override func viewDidLoad() {
super.viewDidLoad()
// 1. 創建日期選擇器:寬度為屏幕寬度,高度100
myDatePicker = UIDatePicker(frame: CGRect(x: 0, y: 0, width: fullScreenSize.width, height: 100))
// 2. 配置選擇模式:日期+時間
myDatePicker.datePickerMode = .dateAndTime
// 3. 配置分鐘間隔:15分鐘一步
myDatePicker.minuteInterval = 15
// 4. 配置可選時間範圍:2016-01-02 18:08 到 2017-12-25 10:45
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm" // 定義日期字符串格式
// 字符串轉Date:需與format格式完全一致
let minDate = formatter.date(from: "2016-01-02 18:08")
let maxDate = formatter.date(from: "2017-12-25 10:45")
myDatePicker.minimumDate = minDate
myDatePicker.maximumDate = maxDate
// 5. 配置語言:繁體中文
myDatePicker.locale = Locale(identifier: "zh_TW")
// 6. 綁定日期變化事件:選擇日期時觸發datePickerChanged方法
myDatePicker.addTarget(self, action: #selector(datePickerChanged), for: .valueChanged)
// 7. 位置:屏幕中上部,加入視圖
myDatePicker.center = CGPoint(x: fullScreenSize.width * 0.5, y: fullScreenSize.height * 0.4)
self.view.addSubview(myDatePicker)
// 8. 創建標籤:顯示選擇的日期時間
myLabel = UILabel(frame: CGRect(x: 0, y: 0, width: fullScreenSize.width, height: 50))
myLabel.backgroundColor = .lightGray
myLabel.textAlignment = .center
myLabel.text = "請選擇日期時間" // 初始提示
myLabel.center = CGPoint(x: fullScreenSize.width * 0.5, y: fullScreenSize.height * 0.15)
self.view.addSubview(myLabel)
}
// 9. 日期變化回調:更新標籤顯示
@objc func datePickerChanged(datePicker: UIDatePicker) {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm" // 與設置範圍時的格式一致
// Date轉字符串,更新標籤
myLabel.text = formatter.string(from: datePicker.date)
}
}
8.4 注意事項
- 日期格式一致性:
DateFormatter的dateFormat必須與字符串格式完全匹配(如"yyyy-MM-dd HH:mm"對應"2016-01-02 18:08"),大小寫、分隔符錯誤會導致date(from:)返回nil; - 時區問題:
Date類型默認使用設備時區,若需統一時區(如 UTC),需設置formatter.timeZone = TimeZone(identifier: "UTC"); - iOS 14+ 樣式變化:iOS 14 後
UIDatePicker支持preferredStyle屬性(.compact緊湊樣式、.inline內嵌樣式),若需兼容舊版本,需判斷系統版本; - 默認日期設置:若未設置
myDatePicker.date,默認顯示當前日期時間,如需指定默認日期,需用formatter.date(from:)轉換後賦值。
九、自定義選項選擇組件:UIPickerView
UIPickerView 是用於多列自定義選項選擇的滾動式組件(繼承自 UIView),支持自定義列數、每列選項內容,通過代理模式(UIPickerViewDelegate/UIPickerViewDataSource)實現數據配置與交互回調,適用於日期、地區、分類等多維度選擇場景(如“星期+餐次”選擇),也可替代鍵盤作為 UITextField 的輸入視圖。
9.1 核心功能
- 支持多列選項(如 2 列分別顯示“星期”和“餐次”);
- 自定義每列的選項內容(文字、圖片均可,需通過代理方法實現);
- 實時響應選項變化(
didSelectRow回調); - 可作為 UITextField 的
inputView,替代系統鍵盤實現自定義輸入。
9.2 關鍵屬性與方法
|
類別
|
屬性/方法
|
作用説明
|
|
數據配置(必須實現)
|
|
數據源方法:返回 UIPickerView 的列數(如 |
|
|
數據源方法:返回指定列的選項行數(如第 0 列返回“星期”數組長度 7)
|
|
|
外觀配置
|
|
代理方法:返回指定列、指定行的選項文字(如第 0 列第 0 行返回“星期日”)
|
|
交互回調
|
|
代理方法:選項變化時觸發,返回當前選中的列和行(用於更新選中狀態)
|
|
輸入視圖替換
|
|
將 UIPickerView 設為 UITextField 的輸入視圖,點擊輸入框時彈出 PickerView 而非鍵盤
|
|
子控制器管理
|
|
若將代理邏輯拆分到獨立控制器(如 |
9.3 代碼邏輯解析
場景1:獨立 UIPickerView(多列選擇)
// 1. 獨立控制器實現代理邏輯(MyViewController.swift)
class MyViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
// 數據源:2列分別對應“星期”和“餐次”
let week = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]
let meals = ["早餐","午餐","晚餐","宵夜"]
// 記錄選中結果
var whatDay = "星期日"
var whatMeal = "早餐"
// 必須實現:返回列數(2列)
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
// 必須實現:返回指定列的行數(第0列7行,第1列4行)
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return component == 0 ? week.count : meals.count
}
// 配置選項文字:第0列顯示星期,第1列顯示餐次
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return component == 0 ? week[row] : meals[row]
}
// 選項變化回調:更新選中結果並打印
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if component == 0 {
whatDay = week[row]
} else {
whatMeal = meals[row]
}
print("選擇的是 \(whatDay) , \(whatMeal)")
}
}
// 2. 主控制器創建並配置PickerView(ViewController.swift)
class ViewController: UIViewController {
let fullScreenSize = UIScreen.main.bounds.size
override func viewDidLoad() {
super.viewDidLoad()
// 創建PickerView:位置在屏幕中上部,高度150
let myPickerView = UIPickerView(frame: CGRect(
x: 0,
y: fullScreenSize.height * 0.3,
width: fullScreenSize.width,
height: 150
))
// 初始化代理控制器,添加為子控制器(避免內存泄漏)
let myVC = MyViewController()
self.addChild(myVC) // 關鍵:子控制器需加入父控制器管理
// 綁定代理和數據源
myPickerView.delegate = myVC
myPickerView.dataSource = myVC
self.view.addSubview(myPickerView)
}
}
場景2:UIPickerView + UITextField(替代鍵盤)
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
let meals = ["早餐","午餐","晚餐","宵夜"] // PickerView數據源
let fullScreenSize = UIScreen.main.bounds.size
override func viewDidLoad() {
super.viewDidLoad()
// 1. 創建TextField:用於顯示選中結果
let mealTextField = UITextField(frame: CGRect(
x: 0, y: 0,
width: fullScreenSize.width, height: 40
))
mealTextField.backgroundColor = .lightGray
mealTextField.textAlignment = .center
mealTextField.text = meals[0] // 默認選中第0項
mealTextField.tag = 100 // 用tag區分多個TextField
mealTextField.center = CGPoint(x: fullScreenSize.width * 0.5, y: fullScreenSize.height * 0.15)
self.view.addSubview(mealTextField)
// 2. 創建PickerView,設為TextField的輸入視圖(替代鍵盤)
let myPickerView = UIPickerView()
myPickerView.delegate = self
myPickerView.dataSource = self
mealTextField.inputView = myPickerView // 關鍵:替換輸入視圖
// 3. 點擊空白隱藏PickerView(添加手勢)
let tap = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
tap.cancelsTouchesInView = false
self.view.addGestureRecognizer(tap)
}
// 數據源方法:1列
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
// 數據源方法:4行(餐次數組長度)
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return meals.count
}
// 配置選項文字
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return meals[row]
}
// 選項變化:更新TextField內容
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
// 通過tag找到目標TextField
let textField = self.view?.viewWithTag(100) as? UITextField
textField?.text = meals[row]
}
// 隱藏PickerView(結束編輯)
@objc func hideKeyboard() {
self.view.endEditing(true)
}
}
9.4 注意事項
- 代理方法必須實現:
numberOfComponents(in:)和pickerView(_:numberOfRowsInComponent:)是數據源協議的必須實現方法,未實現會導致崩潰; - 子控制器管理:若將代理邏輯拆分到獨立控制器(如
MyViewController),必須通過addChild(_:)將其添加為子控制器,否則代理對象會被提前釋放,PickerView 無數據; - 多TextField區分:當多個 TextField 共用 PickerView 時,需通過
tag或屬性記錄當前激活的 TextField,避免更新錯誤; - 自定義選項外觀:若需顯示圖片或富文本選項,可重寫
pickerView(_:viewForRow:forComponent:reusing:)方法,返回自定義 View(如 UIImageView + UILabel)。
十、開關組件:UISwitch
UISwitch 是用於二元狀態切換的開關組件(繼承自 UIControl),支持“開啓/關閉”兩種狀態,可自定義滑塊、背景顏色,通過 valueChanged 事件響應狀態變化,適用於功能開關(如“通知開啓”“夜間模式”)。
10.1 核心功能
- 直觀展示二元狀態(開啓
isOn = true/ 關閉isOn = false); - 自定義外觀(滑塊顏色、開啓/關閉狀態的背景色);
- 支持點擊切換,通過
target-action綁定狀態變化回調。
10.2 關鍵屬性與方法
|
類別
|
屬性/方法
|
作用説明
|
|
狀態控制
|
|
布爾值,獲取/設置開關狀態( |
|
外觀配置
|
|
滑塊顏色(如 |
|
|
關閉狀態( |
|
|
|
開啓狀態( |
|
|
交互回調
|
|
綁定 |
10.3 代碼邏輯解析
class ViewController: UIViewController {
let fullScreenSize = UIScreen.main.bounds.size
override func viewDidLoad() {
super.viewDidLoad()
// 1. 默認樣式開關
let defaultSwitch = UISwitch()
defaultSwitch.center = CGPoint(x: fullScreenSize.width * 0.5, y: fullScreenSize.height * 0.3)
self.view.addSubview(defaultSwitch)
// 2. 自定義樣式開關
let customSwitch = UISwitch()
customSwitch.thumbTintColor = .orange // 滑塊橙色
customSwitch.tintColor = .blue // 關閉時背景藍色
customSwitch.onTintColor = .brown // 開啓時背景棕色
// 綁定狀態變化事件
customSwitch.addTarget(self, action: #selector(onChange(_:)), for: .valueChanged)
customSwitch.center = CGPoint(x: fullScreenSize.width * 0.5, y: fullScreenSize.height * 0.5)
self.view.addSubview(customSwitch)
}
// 狀態變化回調:根據開關狀態切換背景色
@objc func onChange(_ sender: AnyObject) {
// 將sender強轉為UISwitch,獲取當前狀態
let tempSwitch = sender as! UISwitch
// 切換父視圖背景色
self.view.backgroundColor = tempSwitch.isOn ? .black : .white
}
}
10.4 注意事項
- 狀態判斷安全:回調中
sender需強轉為UISwitch才能訪問isOn屬性,建議用guard let避免強轉失敗(如guard let tempSwitch = sender as? UISwitch else { return }); - 初始狀態設置:若需默認開啓,需在添加到視圖前設置
customSwitch.isOn = true,否則外觀可能不更新; - 自定義限制:UISwitch 不支持修改大小(
frame的寬高設置無效),僅能通過系統屬性自定義顏色,如需特殊大小需自定義 View。