Lines
爲 0,而後在Text
中用option+回車
換行。label.numberOfLines = 0
,設置文字的時候用\n
換行。textField.leftView = UIImageView(image: UIImage(systemName: "phone"))
textField.leftViewMode = .always
複製代碼
class ViewController: UIViewController {
@IBOutlet var textfield: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
// 自動佈局時放這裏
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// 設置無邊框
textfield.borderStyle = .none
// 調用
textfield.setBottomBorder(UIColor.red, 1)
}
}
extension UITextField {
func setBottomBorder(_ color: UIColor, _ lineWidth: Int) {
// 建立一個層
let bottomBorder = CALayer()
let lineWidth = CGFloat(lineWidth)
bottomBorder.borderColor = color.cgColor
// 設置層的frame
bottomBorder.frame = CGRect(x: 0, y: frame.size.height - lineWidth, width: frame.size.width, height: frame.size.height)
// 設置寬度
bottomBorder.borderWidth = lineWidth
// 插入
layer.addSublayer(bottomBorder)
// 裁剪
layer.masksToBounds = true
}
}
複製代碼
// 使用NSAttributedString
textField.attributedPlaceholder = NSAttributedString(string: "請輸入信息", attributes: [.foregroundColor : UIColor.red])
複製代碼
Word Wrap
,而後在 title 中用option+回車
換行。titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
,設置文字的時候用\n
換行。class ViewController: UIViewController {
@IBOutlet var username: UITextField!
@IBOutlet var password: UITextField!
@IBAction func loginBtnClicked(_ sender: Any) {
let uname = username.text
let upwd = password.text
// 能夠在這裏對輸入的信息進行判斷
print("用戶名爲:\(uname!), 密碼爲:\(upwd!)")
}
override func viewDidLoad() {
super.viewDidLoad()
}
// 觸摸屏幕方法
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// 退鍵盤的方式之一
view.endEditing(true)
}
}
複製代碼
class ViewController: UIViewController {
var imageArray: [UIImage] = [UIImage]()
@IBOutlet var tomcat: UIImageView!
@IBAction func drink(_ sender: Any) {
imageArray.removeAll()
var imgName = ""
// 1.加載drink的動畫圖片
for index in 0 ... 80 {
// drink_XX.jpg
imgName = "drink_\(index).jpg"
// 經過名字構造一張圖片
let image = UIImage(named: imgName)
imageArray.append(image!)
}
// 2.讓圖片進行動畫的播放
// 圖片數組
tomcat.animationImages = imageArray
// 動畫時間
tomcat.animationDuration = 3.0
// 動畫次數
tomcat.animationRepeatCount = 1
// 開始動畫
tomcat.startAnimating()
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
複製代碼
class ViewController: UIViewController {
@IBOutlet var light: UIImageView!
@IBOutlet var voice: UIImageView!
@IBOutlet var product: UILabel!
@IBOutlet var flower: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
// sender 誰觸發這個事件 就將誰傳進來
@IBAction func valueChanged(_ sender: Any) {
// UISwitch
let switchUI = sender as? UISwitch
if let switchUI = switchUI {
if switchUI.isOn {
light.image = UIImage(named: "light.png")
} else {
light.image = UIImage(named: "nomal.png")
}
}
// UISlider
let slider = sender as? UISlider
if let slider = slider {
if slider.value < 0.3 {
voice.image = UIImage(named: "low.png")
} else if slider.value < 0.7 {
voice.image = UIImage(named: "middle.png")
} else {
voice.image = UIImage(named: "high.png")
}
}
// UIStepper
let stepper = sender as? UIStepper
if let stepper = stepper {
let value = stepper.value
if value < stepper.maximumValue {
product.text = "您購買了\(Int(value))件商品"
}
if value == stepper.minimumValue {
product.text = "您未購買任何商品"
}
}
// UISegmentedControl
let segment = sender as? UISegmentedControl
if let segment = segment {
if segment.selectedSegmentIndex == 0 {
flower.image = UIImage(named: "red.png")
} else if segment.selectedSegmentIndex == 1 {
flower.image = UIImage(named: "purple.png")
}
}
}
}
複製代碼
思考:湯姆貓和本案例,事件都是相同的,那麼可否用一個 IBAction 完成?swift
class ViewController: UIViewController {
@IBOutlet var indicator: UIActivityIndicatorView!
@IBOutlet var progressView: UIProgressView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
indicator.stopAnimating()
// UIView動畫
// 動畫執行的時間
// 動畫執行的操做
UIView.animate(withDuration: 5.0) {
// 千萬不要直接設置progress,由於這樣是不會有動畫效果的
// self.progressView.progress = 1.0
// 必需要用帶animated參數的方法來進行設置 纔會有動畫
self.progressView.setProgress(1.0, animated: true)
}
}
}
複製代碼
class ViewController: UIViewController {
@IBOutlet var birthday: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let datePicker = UIDatePicker(frame: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: 300))
datePicker.datePickerMode = .dateAndTime
// 當控件datePicker發生valueChanged事件時 會調用target的action方法
datePicker.addTarget(self, action: #selector(getBirthday), for: .valueChanged)
birthday.inputView = datePicker
}
@objc func getBirthday(datePicker: UIDatePicker) {
// 獲取日期
let date = datePicker.date
// 日期格式化
// 2018.10.17 2018/10/17 2018-10-17 2018年10月17日
let dateFormatter = DateFormatter()
// 24小時制,hh小寫12小時制
dateFormatter.dateFormat = "yyyy年MM月dd日 HH:mm:ss"
// 賦值給birthday
birthday.text = dateFormatter.string(from: date)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// 退鍵盤的另一種方式
birthday.resignFirstResponder()
}
}
複製代碼
datePicker.preferredDatePickerStyle = .wheels
複製代碼
注意:須要在 frame 以前設置。數組
class ViewController: UIViewController {
let province: [String] = ["安徽", "浙江", "江蘇", "山東", "河南", "湖北"]
let city: [String] = ["合肥", "杭州", "南京", "濟南", "鄭州", "武漢", "廈門", "長沙"]
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController: UIPickerViewDataSource {
// UIPickerViewDataSource
// 返回選擇器的列數
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0 {
return province.count
} else {
return city.count
}
}
}
extension ViewController: UIPickerViewDelegate {
// UIPickerViewDelegate
// 該方法會調用屢次 根據numberOfRowsInComponent的返回值決定
// 每一次調用就應該返回一個數據 它會自動從第0行開始設置title
// 6行 0 1 2 3 4 5
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if component == 0 {
return province[row]
} else {
return city[row]
}
}
// 設置UIView
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
return UIImageView(image: UIImage(systemName: "person"))
}
// 設置高度
func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return 44
}
// 選擇的數據列(滾動的時候調用)
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if component == 0 {
print(province[row])
} else {
print(city[row])
}
}
}
複製代碼
說明:tomcat
titleForRow
方法在代理方法裏而不是在數據源方法裏。在某一列滾動的時候,從新設置聯動列的顯示數據,而後進行刷新操做。微信
class ViewController: UIViewController {
// 屏幕寬度
let bannerW = UIScreen.main.bounds.size.width
// 高度
let bannerH = 260
var banner: UIScrollView!
var pageControl: UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
// 設置UIScrollView
setupBanner()
// 設置UIPageControl
setupPageControl()
}
func setupBanner() {
banner = UIScrollView(frame: CGRect(x: 0, y: 0, width: Int(bannerW), height: bannerH))
// 是否顯示滾動條
banner.showsHorizontalScrollIndicator = false
// 是否須要彈簧效果
banner.bounces = false
// 是否分頁
banner.isPagingEnabled = true
// 代理
banner.delegate = self
// 添加圖片
for i in 0 ... 4 {
// x座標
let w = Int(bannerW) * i
// 圖片控件
let img = UIImageView(frame: CGRect(x: w, y: 0, width: Int(bannerW), height: bannerH))
img.image = UIImage(named: "img_\(i)")
banner.addSubview(img)
}
// 設置contentSize
banner.contentSize = CGSize(width: bannerW * 5.0, height: 0)
view.addSubview(banner)
}
func setupPageControl() {
pageControl = UIPageControl(frame: CGRect(x: 0, y: 0, width: 200, height: 20))
// 指示器的顏色
pageControl.pageIndicatorTintColor = UIColor.red
// 當前頁的顏色
pageControl.currentPageIndicatorTintColor = UIColor.cyan
// 總頁數
pageControl.numberOfPages = 5
pageControl.center = CGPoint(x: bannerW * 0.5, y: 240.0)
// 監聽事件
pageControl.addTarget(self, action: #selector(pageIndicate), for: .valueChanged)
view.addSubview(pageControl)
}
@objc func pageIndicate(pageControl: UIPageControl) {
let currentIndex = pageControl.currentPage
// 設置偏移
banner.setContentOffset(CGPoint(x: Int(bannerW) * currentIndex, y: 0), animated: true)
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// 獲取contentOffset
let contentOffset = scrollView.contentOffset
// 獲取索引
let index = contentOffset.x / bannerW
// 設置當前頁
pageControl.currentPage = Int(index)
}
}
複製代碼
contentView
,顯示的內容放在上面。contentView
裏默認有 3 個控件:2 個UILabel
、1一個UIImageView
,並由此產生了四種不一樣的 UITableViewCell 的顯示樣式。class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController: UITableViewDataSource {
// 有多少分組
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// 每一個分組中有多少行
func tableView(_ tableView: UITableView, numberOfRowsInSection section : Int) -> Int {
return 20
}
// 每一行的內容
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "abc")
// default 只顯示textLabel和imageView
// subtitle value1 三個都顯示
// value2 只顯示textLabel和detailTextLabel
cell.textLabel?.text = "AAA"
cell.detailTextLabel?.text = "BBB"
cell.imageView?.image = UIImage(named: "setting_about_pic")
return cell
}
}
複製代碼
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController: UITableViewDataSource {
// 有多少分組
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// 一個分組中有多少行
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
// 每一行長什麼樣
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
/** // 純代碼實現複用 // 去重用池子中找cell var cell = tableView.dequeueReusableCell(withIdentifier: "abc") // 池子中沒有就建立一個新的 if cell == nil { cell = UITableViewCell(style: .subtitle, reuseIdentifier: "abc") } cell?.textLabel?.text = "AAA" cell?.detailTextLabel?.text = "BBB" cell?.imageView?.image = UIImage(named: "setting_about_pic") return cell! */
// SB方式實現複用
let cell = tableView.dequeueReusableCell(withIdentifier: "abc")
cell?.textLabel?.text = "AAA"
cell?.detailTextLabel?.text = "BBB"
cell?.imageView?.image = UIImage(named: "setting_about_pic")
return cell!
}
}
複製代碼
數據再也不固定,而是由外界提供,多使用數組。markdown
class ViewController: UIViewController {
var content: Array<String>?
var detailContent: Array<String>?
override func viewDidLoad() {
super.viewDidLoad()
content = ["iPhone 4", "iPhone 4s", "iPhone 5", "iPhone 5s", "iPhone 6", "iPhone 6 Plus", "iPhone 6s", "iPhone 6s Plus", "iPhone 7", "iPhone 7 Plus", "iPhone 8", "iPhone 8 Plus", "iPhone X", "iPhone Xs", "iPhone XR", "iPhone Xs Max", "iPhone 11", "iPhone 11 Pro", "iPhone 11 Pro Max", "iPhone 12 mini", "iPhone 12", "iPhone 12 Pro", "iPhone 12 Pro Max"]
detailContent = ["iPhone 4 - iOS 4", "iPhone 4s - iOS 5", "iPhone 5 - iOS 6", "iPhone 5s - iOS 7", "iPhone 6 - iOS 8", "iPhone 6 Plus - iOS 8", "iPhone 6s - iOS 9", "iPhone 6s Plus - iOS 9", "iPhone 7 - iOS 10", "iPhone 7 Plus - iOS 10", "iPhone 8 - iOS 11", "iPhone 8 Plus - iOS 11", "iPhone X - iOS 11", "iPhone Xs - iOS 12", "iPhone XR - iOS 12", "iPhone Xs Max - iOS 12", "iPhone 11 - iOS 13", "iPhone 11 Pro - iOS 13", "iPhone 11 Pro Max - iOS 13", "iPhone 12 mini - iOS 14", "iPhone 12 - iOS 14", "iPhone 12 Pro - iOS 14", "iPhone 12 Pro Max - iOS 14"]
}
}
extension ViewController: UITableViewDataSource {
// 有多少分組
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// 一個分組中有多少行
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return content!.count
}
// 每一行長什麼樣
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// SB方式實現複用
let cell = tableView.dequeueReusableCell(withIdentifier: "ABC")
cell?.textLabel?.text = content?[indexPath.row]
cell?.detailTextLabel?.text = detailContent?[indexPath.row]
cell?.imageView?.image = UIImage(named: "iPhone")
return cell!
}
}
複製代碼
class ViewController: UIViewController {
var content: Array<String>?
var detailContent: Array<String>?
override func viewDidLoad() {
super.viewDidLoad()
content = ["iPhone 4", "iPhone 4s", "iPhone 5", "iPhone 5s", "iPhone 6", "iPhone 6 Plus", "iPhone 6s", "iPhone 6s Plus", "iPhone 7", "iPhone 7 Plus", "iPhone 8", "iPhone 8 Plus", "iPhone X", "iPhone Xs", "iPhone XR", "iPhone Xs Max", "iPhone 11", "iPhone 11 Pro", "iPhone 11 Pro Max", "iPhone 12 mini", "iPhone 12", "iPhone 12 Pro", "iPhone 12 Pro Max"]
detailContent = ["iPhone 4 - iOS 4", "iPhone 4s - iOS 5", "iPhone 5 - iOS 6", "iPhone 5s - iOS 7", "iPhone 6 - iOS 8", "iPhone 6 Plus - iOS 8", "iPhone 6s - iOS 9", "iPhone 6s Plus - iOS 9", "iPhone 7 - iOS 10", "iPhone 7 Plus - iOS 10", "iPhone 8 - iOS 11", "iPhone 8 Plus - iOS 11", "iPhone X - iOS 11", "iPhone Xs - iOS 12", "iPhone XR - iOS 12", "iPhone Xs Max - iOS 12", "iPhone 11 - iOS 13", "iPhone 11 Pro - iOS 13", "iPhone 11 Pro Max - iOS 13", "iPhone 12 mini - iOS 14", "iPhone 12 - iOS 14", "iPhone 12 Pro - iOS 14", "iPhone 12 Pro Max - iOS 14"]
}
}
extension ViewController: UITableViewDataSource {
// 有多少分組
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// 一個分組中有多少行
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return content!.count
}
// 每一行長什麼樣
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// SB方式實現複用
let cell = tableView.dequeueReusableCell(withIdentifier: "ABC")
cell?.textLabel?.text = content?[indexPath.row]
cell?.detailTextLabel?.text = detailContent?[indexPath.row]
cell?.imageView?.image = UIImage(named: "iPhone")
return cell!
}
}
extension ViewController: UITableViewDelegate {
// Section頭部
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "iPhone 大全"
}
// Section尾部
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return "iOS大全"
}
// 選中(點擊行)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let contentText = content?[indexPath.row]
let detailText = detailContent?[indexPath.row]
print("\(contentText!)--\(detailText!)")
}
// 行高
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80.0
}
// Section頭部高
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 100.0
}
// Section尾部高
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 60.0
}
}
複製代碼
class ViewController: UIViewController {
@IBOutlet var tableView: UITableView!
var content: Array<String>?
var detailContent: Array<String>?
override func viewDidLoad() {
super.viewDidLoad()
content = ["iPhone 4", "iPhone 4s", "iPhone 5", "iPhone 5s", "iPhone 6", "iPhone 6 Plus", "iPhone 6s", "iPhone 6s Plus", "iPhone 7", "iPhone 7 Plus", "iPhone 8", "iPhone 8 Plus", "iPhone X", "iPhone Xs", "iPhone XR", "iPhone Xs Max", "iPhone 11", "iPhone 11 Pro", "iPhone 11 Pro Max", "iPhone 12 mini", "iPhone 12", "iPhone 12 Pro", "iPhone 12 Pro Max"]
detailContent = ["iPhone 4 - iOS 4", "iPhone 4s - iOS 5", "iPhone 5 - iOS 6", "iPhone 5s - iOS 7", "iPhone 6 - iOS 8", "iPhone 6 Plus - iOS 8", "iPhone 6s - iOS 9", "iPhone 6s Plus - iOS 9", "iPhone 7 - iOS 10", "iPhone 7 Plus - iOS 10", "iPhone 8 - iOS 11", "iPhone 8 Plus - iOS 11", "iPhone X - iOS 11", "iPhone Xs - iOS 12", "iPhone XR - iOS 12", "iPhone Xs Max - iOS 12", "iPhone 11 - iOS 13", "iPhone 11 Pro - iOS 13", "iPhone 11 Pro Max - iOS 13", "iPhone 12 mini - iOS 14", "iPhone 12 - iOS 14", "iPhone 12 Pro - iOS 14", "iPhone 12 Pro Max - iOS 14"]
}
@IBAction func edit(_ sender: Any) {
tableView.setEditing(true, animated: true)
}
@IBAction func done(_ sender: Any) {
tableView.setEditing(false, animated: true)
}
}
extension ViewController: UITableViewDataSource {
// 有多少分組
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// 一個分組中有多少行
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return content!.count
}
// 每一行長什麼樣
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// SB方式實現複用
let cell = tableView.dequeueReusableCell(withIdentifier: "ABC")
cell?.textLabel?.text = content?[indexPath.row]
cell?.detailTextLabel?.text = detailContent?[indexPath.row]
cell?.imageView?.image = UIImage(named: "iPhone")
return cell!
}
}
extension ViewController: UITableViewDelegate {
// 容許編輯
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
// 提交編輯
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// 1.刪除數組中對應的數據
content?.remove(at: indexPath.row)
detailContent?.remove(at: indexPath.row)
// 2.TableView顯示的那同樣刪除
tableView.deleteRows(at: [indexPath], with: .automatic)
} else if editingStyle == .insert {
// 1.增長一條數據
content?.insert("iPhone 1", at: indexPath.row)
detailContent?.insert("iPhone 1 - iPhone OS", at: indexPath.row)
// 2.增長一行
tableView.insertRows(at: [indexPath], with: .automatic)
}
}
// 刪除按鈕的文字
func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
return "刪除"
}
// 編輯的風格(默認是刪除)
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .insert
}
// 可否移動
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
// 移動表格
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// 內容
let contentText = content?[sourceIndexPath.row]
// 先刪除
content?.remove(at: sourceIndexPath.row)
// 再增長
content?.insert(contentText!, at: destinationIndexPath.row)
// 詳情操做和內容同樣
let detailContentText = detailContent?[sourceIndexPath.row]
detailContent?.remove(at: sourceIndexPath.row)
detailContent?.insert(detailContentText!, at: destinationIndexPath.row)
}
}
複製代碼
class ViewController: UIViewController {
@IBOutlet var tableView: UITableView!
var sectionTitles: [String] = ["A", "C", "F", "G", "H", "M", "S", "T", "X", "Z"]
var contentsArray: [[String]] = [
["阿偉", "阿姨", "阿三"],
["陳晨", "成龍", "陳鑫", "陳丹"],
["芳仔", "房祖名", "方大同", "範偉"],
["郭靖", "郭美美", "過兒", "郭襄"],
["何仙姑", "和珅", "郝歌", "何仙姑"],
["馬雲", "毛不易"],
["孫周", "沈冰", "史磊"],
["陶也", "淘寶", "圖騰"],
["項羽", "夏紫薇", "許巍", "許晴"],
["祝枝山", "周杰倫", "張柏芝"],
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.sectionIndexBackgroundColor = UIColor.red
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return sectionTitles.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contentsArray[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "abc")
cell?.textLabel?.text = contentsArray[indexPath.section][indexPath.row]
return cell!
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionTitles[section]
}
}
extension ViewController: UITableViewDelegate {
// 索引的標題
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return sectionTitles
}
// 點擊索引
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
// 點擊的索引標題
print(title)
// 必定要返回index 不然 點擊索引不會自動滾動到指定位置
return index
}
}
複製代碼
用 3 種自定義 Cell 的方式分別實現下面的案例:閉包
class ViewController: UIViewController {
@IBOutlet var tableView: UITableView!
var content: Array<String> = ["iPhone 4", "iPhone 4s", "iPhone 5", "iPhone 5s", "iPhone 6", "iPhone 6 Plus", "iPhone 6s", "iPhone 6s Plus", "iPhone 7", "iPhone 7 Plus", "iPhone 8", "iPhone 8 Plus", "iPhone X", "iPhone Xs", "iPhone XR", "iPhone Xs Max", "iPhone 11", "iPhone 11 Pro", "iPhone 11 Pro Max", "iPhone 12 mini", "iPhone 12", "iPhone 12 Pro", "iPhone 12 Pro Max"]
var detailContent: Array<String> = ["iPhone 4 - iOS 4", "iPhone 4s - iOS 5", "iPhone 5 - iOS 6", "iPhone 5s - iOS 7", "iPhone 6 - iOS 8", "iPhone 6 Plus - iOS 8", "iPhone 6s - iOS 9", "iPhone 6s Plus - iOS 9", "iPhone 7 - iOS 10", "iPhone 7 Plus - iOS 10", "iPhone 8 - iOS 11", "iPhone 8 Plus - iOS 11", "iPhone X - iOS 11", "iPhone Xs - iOS 12", "iPhone XR - iOS 12", "iPhone Xs Max - iOS 12", "iPhone 11 - iOS 13", "iPhone 11 Pro - iOS 13", "iPhone 11 Pro Max - iOS 13", "iPhone 12 mini - iOS 14", "iPhone 12 - iOS 14", "iPhone 12 Pro - iOS 14", "iPhone 12 Pro Max - iOS 14"]
override func viewDidLoad() {
super.viewDidLoad()
// 建立UIRefreshControl
let refresh = UIRefreshControl()
// 設置顯示的標題
refresh.attributedTitle = NSAttributedString(string: "下拉刷新")
// 設置下拉事件
refresh.addTarget(self, action: #selector(loadData), for: .valueChanged)
// 放到tableView的頭部
tableView.refreshControl = refresh
}
@objc func loadData() {
// 延遲執行
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
// 增長一條數據
self.content.insert("iPhone 3GS", at: 0)
self.detailContent.insert("iPhone 3GS - iOS 3", at: 0)
// 刷新表格 結束刷新的狀態
self.tableView.reloadData()
// 中止刷新
if (self.tableView.refreshControl?.isRefreshing)! {
self.tableView.refreshControl?.endRefreshing()
}
}
}
}
extension ViewController: UITableViewDataSource {
// 一個分組中有多少行
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return content.count
}
// 每一行長什麼樣
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// SB方式實現複用
let cell = tableView.dequeueReusableCell(withIdentifier: "ABC")
cell?.textLabel?.text = content[indexPath.row]
cell?.detailTextLabel?.text = detailContent[indexPath.row]
cell?.imageView?.image = UIImage(named: "iPhone")
return cell!
}
}
複製代碼
在 iOS 13 中引入了新的 API — Diffable Data Source,它不只可以驅動 UITableView 和 UICollectionView,並且能夠更簡單高效的實現數據的刷新。app
var dataSource: UITableViewDiffableDataSource<Section, City>!
override func viewDidLoad() {
super.viewDidLoad()
dataSource = UITableViewDiffableDataSource
<Section, City>(tableView: tableView) { // 該閉包是tableView(_:cellForRowAtIndexPath:)方法的替代品
(tableView: UITableView, indexPath: IndexPath,
city: City) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = city.name
return cell
}
// 刷新時的動畫
dataSource.defaultRowAnimation = .fade
}
複製代碼
enum Section: CaseIterable {
case main
}
// 獲取NSDiffableDataSourceSnapshot
var snapshot = NSDiffableDataSourceSnapshot<Section, City>()
// 更改數據
snapshot.appendSections([.main])
snapshot.appendItems(filteredCities, toSection: .main)
// 更新
dataSource.apply(snapshot, animatingDifferences: true)
複製代碼
struct City: Hashable {
let identifier = UUID()
let name: String
func hash(into hasher: inout Hasher) {
hasher.combine(identifier)
}
static func ==(lhs: City, rhs: City) -> Bool {
return lhs.identifier == rhs.identifier
}
func contains(query: String?) -> Bool {
guard let query = query else { return true }
guard !query.isEmpty else { return true }
return name.contains(query)
}
}
複製代碼
與 UITableView 不一樣,UICollectionView 須要提供佈局參數,經常使用的有UICollectionViewFlowLayout
,經過它能夠設置內容的大小、間距和方向等信息。async
class ViewController: UIViewController {
@IBOutlet var collectionView: UICollectionView!
let screenW = UIScreen.main.bounds.size.width
override func viewDidLoad() {
super.viewDidLoad()
// 佈局
let layout = UICollectionViewFlowLayout()
// 設置item大小
layout.itemSize = CGSize(width: (screenW - 15.0) * 0.5, height: 212)
// item之間的間距
layout.minimumInteritemSpacing = 5.0
// 行間距
layout.minimumLineSpacing = 5.0
// 組邊距
layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
// 滾動方向
layout.scrollDirection = .vertical
collectionView.collectionViewLayout = layout
}
}
extension ViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "abc", for: indexPath)
return cell
}
}
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("\(indexPath.row)")
}
}
複製代碼
在 iOS 13 中 UICollectionView 推出了一種新的組合佈局 UICollectionViewCompositionalLayout,這是一次全新的升級。ide
UICollectionViewCompositionalLayout 是在已有的 Item 和 Section 的基礎上,增長了一個 Group 的概念。多個 Item 組成一個 Group ,多個 Group 組成一個 Section,所以層級關係從裏到外變爲:Item -> Group -> Section -> Layout
。佈局
決定了一個元素的大小。表達一個元素的 Size 有三種方法:
// 佔據Group寬和高各25%
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.25), heightDimension: .fractionalHeight(0.25))
複製代碼
let widthDimension = NSCollectionLayoutDimension.absolute(200)
let heightDimension = NSCollectionLayoutDimension.absolute(200)
複製代碼
let widthDimension = NSCollectionLayoutDimension.estimated(200)
let heightDimension = NSCollectionLayoutDimension.estimated(200)
複製代碼
描述一個 Item 的佈局,定義以下:
class NSCollectionLayoutItem {
convenience init(layoutSize: NSCollectionLayoutSize)
var contentInsets: NSDirectionalEdgeInsets
}
複製代碼
class NSCollectionLayoutGroup: NSCollectionLayoutItem {
class func horizontal(layoutSize: NSCollectionLayoutSize, subitems: [NSCollectionLayoutItem]) -> Self class func vertical(layoutSize: NSCollectionLayoutSize, subitems: [NSCollectionLayoutItem]) -> Self class func custom(layoutSize: NSCollectionLayoutSize, itemProvider: NSCollectionLayoutGroupCustomItemProvider) -> Self } 複製代碼
描述一個 Section 的佈局,定義以下:
class NSCollectionLayoutSection {
convenience init(layoutGroup: NSCollectionLayoutGroup)
var contentInsets: NSDirectionalEdgeInsets
}
複製代碼
由裏而外,由小到大地建立佈局,而後組合。
func generateLayout() -> UICollectionViewCompositionalLayout {
// 1. 構造Item的NSCollectionLayoutSize
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.25),
heightDimension: .fractionalHeight(1.0))
// 2. 構造NSCollectionLayoutItem
let item = NSCollectionLayoutItem(layoutSize: itemSize)
// 3. 構造Group的NSCollectionLayoutSize
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalWidth(0.1))
// 4. 構造NSCollectionLayoutGroup
let group = NSCollectionLayoutGroup.horizontal(
layoutSize: groupSize,
subitems: [item])
// 5. 構造NSCollectionLayoutSection
let section = NSCollectionLayoutSection(group: group)
// 6. 構造UICollectionViewCompositionalLayout
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
複製代碼
附加視圖,通常用於設置頭部和尾部 View。
// 頭部大小
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
// 頭部
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: "header", alignment: .top)
// 尾部大小
let footerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
// 尾部
let footer = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: footerSize, elementKind: "footer", alignment: .bottom)
// pinToVisibleBounds決定是否懸停
header.pinToVisibleBounds = true
// 設置Section的頭尾
section.boundarySupplementaryItems = [header, footer]
複製代碼
附加視圖使用以前須要註冊
SupplementaryView
,後面會進行講解。
在 Item 中,可能須要給其加上小紅點或者未讀消息數等附加視圖,在 UICollectionViewCompositionalLayout 中,能夠經過 NSCollectionLayoutSupplementaryItem 和 NSCollectionLayoutAnchor 這兩個類來實現這樣的需求。
class BadgeView: UICollectionReusableView {
static let reuseIdentifier = "badge"
let imageView = UIImageView(image: UIImage(systemName: "heart.fill"))
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
}
複製代碼
collectionView.register(
BadgeView.self,
forSupplementaryViewOfKind: "badge",
withReuseIdentifier: BadgeView.reuseIdentifier)
複製代碼
dataSource.supplementaryViewProvider = {
(collectionView: UICollectionView, kind: String, indexPath: IndexPath)
-> UICollectionReusableView? in
if let badgeView = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: BadgeView.reuseIdentifier,
for: indexPath) as? BadgeView {
return badgeView
} else {
fatalError("Cannot create Supplementary")
}
}
複製代碼
// Badge位置
let badgeAnchor = NSCollectionLayoutAnchor(edges: [.top, .trailing],
fractionalOffset: CGPoint(x: 0.5, y: -0.5))
// Badge大小
let badgeSize = NSCollectionLayoutSize(widthDimension: .absolute(16),
heightDimension: .absolute(16))
// Badge
let badge = NSCollectionLayoutSupplementaryItem(layoutSize: badgeSize, elementKind: "badge", containerAnchor: badgeAnchor)
// 附加Badge
let item = NSCollectionLayoutItem(layoutSize: itemSize, supplementaryItems: [badge])
複製代碼
iOS 14 中 UICollectionView 的功能得以繼續加強,能夠在必定程度上替換 UITableView。
爲 UICollectionView 配置 List 式的佈局,還能夠配置滑動菜單。
extension ViewController {
// 建立列表式UICollectionView
func makeCollectionView() -> UICollectionView {
var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
// 右側滑動刪除
config.trailingSwipeActionsConfigurationProvider = { indexPath in
// 找到刪除的內容
guard let city = self.dataSource.itemIdentifier(for: indexPath) else { return nil }
return UISwipeActionsConfiguration(
actions: [UIContextualAction(
style: .destructive,
title: "Delete",
handler: { [weak self] _, _, completion in
// 調用刪除數據
self?.deleteCity(city: city, indexPath: indexPath)
self?.updateList()
// 最後必定要調用completion
completion(true)
}
)]
)
}
// 左側滑動添加
config.leadingSwipeActionsConfigurationProvider = { indexPath in
return UISwipeActionsConfiguration(
actions: [UIContextualAction(
style: .normal,
title: "Add",
handler: { [weak self] _, _, completion in
// 調用增長數據
self?.addCity(city: City(name: "蕪湖"), indexPath: indexPath)
self?.updateList()
completion(true)
}
)]
)
}
// 列表佈局
let layout = UICollectionViewCompositionalLayout.list(using: config)
return UICollectionView(frame: view.frame, collectionViewLayout: layout)
}
}
複製代碼
能夠像 UITableView 同樣,填充 Cell 的內容。
extension ViewController {
// 註冊Cell
func makeCellRegistration() -> UICollectionView.CellRegistration<CityCollectionViewCell, City> {
UICollectionView.CellRegistration { cell, _, city in
// 自定義Cell顯示的內容
cell.cityLabel.text = city.name
// AccessoryView
cell.accessories = [.disclosureIndicator()]
}
}
}
複製代碼
extension ViewController {
// 配置數據源
func makeDataSource() -> UICollectionViewDiffableDataSource<Section, City> {
UICollectionViewDiffableDataSource<Section, City>(
collectionView: collectionView,
cellProvider: { view, indexPath, item in
view.dequeueConfiguredReusableCell(
using: self.makeCellRegistration(),
for: indexPath,
item: item
)
}
)
}
}
複製代碼
enum Section: CaseIterable {
case first
case second
}
extension ViewController {
func updateList() {
var snapshot = NSDiffableDataSourceSnapshot<Section, City>()
// 添加兩個分組
snapshot.appendSections(Section.allCases)
// 分別往兩個分組添加數據
snapshot.appendItems(firstCities, toSection: .first)
snapshot.appendItems(secondCities, toSection: .second)
dataSource.apply(snapshot)
}
}
複製代碼
class ViewController: UIViewController {
// 建立UICollectionView
private lazy var collectionView = makeCollectionView()
// 建立DataSource
private lazy var dataSource = makeDataSource()
let cityNames = ["北京", "南京", "西安", "杭州", "蕪湖"]
// 第一組
var firstCities: [City] = []
// 第二組
var secondCities: [City] = []
override func viewDidLoad() {
super.viewDidLoad()
for name in cityNames {
firstCities.append(City(name: name))
secondCities.append(City(name: name))
}
// CollectionView關聯DataSource
collectionView.dataSource = dataSource
view.addSubview(collectionView)
// 第一次進來刷新
updateList()
}
}
// 增長與刪除數據
extension ViewController {
// 刪除數據
func deleteCity(city: City, indexPath: IndexPath) {
if indexPath.section == 0 {
firstCities.remove(at: firstCities.firstIndex(of: city)!)
} else {
secondCities.remove(at: secondCities.firstIndex(of: city)!)
}
}
// 增長數據
func addCity(city: City, indexPath: IndexPath) {
if indexPath.section == 0 {
firstCities.append(city)
} else {
secondCities.append(city)
}
}
}
複製代碼
// 1.建立UIView
let subView = UIView()
// 2.設置frame
subView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
// 1和2能夠合併
// let subView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
// 3.設置其餘屬性
subView.backgroundColor = .red
// 4.UIControl能夠添加事件
...
// 5.添加到父View
view.addSubview(subView)
複製代碼
// UITextField
let textField = UITextField()
textField.addTarget(self, action: #selector(handlerEvent), for: .editingChanged)
@objc func handlerEvent(_ sender: UITextField) {
print(sender.text)
}
// UIButton
let button = UIButton()
button.addTarget(self, action: #selector(handlerEvent), for: .touchUpInside)
@objc func handlerEvent(_ sender: UIButton) {
print("按鈕點擊")
}
// UISwitch
let swi = UISwitch()
swi.addTarget(self, action: #selector(handlerEvent), for: .valueChanged)
@objc func handlerEvent(_ sender: UISwitch) {
print(sender.isOn)
}
// UISlider
let slider = UISlider()
slider.addTarget(self, action: #selector(handlerEvent), for: .valueChanged)
@objc func handlerEvent(_ sender: UISlider) {
print(sender.value)
}
// UIStepper
let stepper = UIStepper()
stepper.addTarget(self, action: #selector(handlerEvent), for: .valueChanged)
@objc func handlerEvent(_ sender: UISlider) {
print(sender.value)
}
// UISegmentedControl
let segmentedControl = UISegmentedControl()
segmentedControl.addTarget(self, action: #selector(handlerEvent), for: .valueChanged)
@objc func handlerEvent(_ sender: UISegmentedControl) {
print(sender.selectedSegmentIndex)
}
// UIPageControl
let pageControl = UIPageControl()
pageControl.addTarget(self, action: #selector(handlerEvent), for: .valueChanged)
@objc func handlerEvent(_ sender: UIPageControl) {
print(sender.currentPage)
}
// UIDatePicker
let datepicker = UIDatePicker()
datepicker.addTarget(self, action: #selector(handlerEvent), for: .valueChanged)
@objc func handlerEvent(_ sender: UIDatePicker) {
print(sender.date)
}
// UIRefreshControl
let tableView = UITableView(frame: UIScreen.main.bounds)
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(handlerEvent), for: .valueChanged)
tableView.refreshControl = refreshControl
@objc func handlerEvent(_ sender: UIRefreshControl) {
print(sender.isRefreshing)
}
複製代碼
// UITextField
let textField = UITextField()
textField.addAction(
UIAction { action in
let textField = action.sender as! UITextField
print(textField.text)
},
for: .editingChanged
)
// UIButton
// 方式一
let button = UIButton(primaryAction: UIAction { _ in
print("按鈕點擊")
})
// 方式二
let btn = UIButton()
btn.addAction(
UIAction { _ in
print("按鈕點擊")
},
for: .touchUpInside
)
// UISwitch
let swi = UISwitch()
swi.addAction(
UIAction { action in
let swi = action.sender as! UISwitch
print(swi.isOn)
},
for: .valueChanged
)
// UISlider
let slider = UISlider()
slider.addAction(
UIAction { action in
let slider = action.sender as! UISlider
print(slider.value)
},
for: .valueChanged
)
// UIStepper
let stepper = UIStepper()
stepper.addAction(
UIAction { action in
let stepper = action.sender as! UIStepper
print(stepper.value)
},
for: .valueChanged
)
// UISegmentedControl
let segmentedControl = UISegmentedControl()
segmentedControl.addAction(
UIAction { action in
let segmentedControl = action.sender as! UISegmentedControl
print(segmentedControl.selectedSegmentIndex)
},
for: .valueChanged
)
// UIPageControl
let pageControl = UIPageControl()
pageControl.addAction(
UIAction { action in
let pageControl = action.sender as! UIPageControl
print(pageControl.currentPage)
},
for: .valueChanged
)
// UIDatePicker
let datepicker = UIDatePicker()
datepicker.addAction(
UIAction { action in
let datepicker = action.sender as! UIDatePicker
print(datepicker.date)
},
for: .valueChanged
)
// UIRefreshControl
let tableView = UITableView(frame: UIScreen.main.bounds)
let refreshControl = UIRefreshControl()
refreshControl.addAction(
UIAction { action in
let refreshControl = action.sender as! UIRefreshControl
print(refreshControl.isRefreshing)
},
for: .valueChanged
)
tableView.refreshControl = refreshControl
複製代碼