UIKit實作100#2-自訂表格cell

自訂表格cell質感看起來會好一些

使用UITableViewController與UITableViewDifableDataSource來建立表格。

新增TableViewController

新增檔案後,都會有預設的storyboard跟關聯swift檔案,把這兩個刪除,然後另外新增一個storyboard跟關聯swift檔案。

is Initial View Controller記得要打勾
才能會是第一個畫面

新增關聯檔案

新增檔案
檔名:RestaurantTableViewController

選擇Cocoa Touch Class,後按Next

Subclass of 要撰”UITableViewController”

接下來都預設

成功新增後會出現新增檔案的內容

裡面的程式是我們在使用TableViewController時可能會用到的

新增的TableViewController跟新增的檔案做聯結

數字3按下去就會看到剛剛新增的檔案,按下去就聯結了。
如果沒有你要的檔案,可能Subclass of選錯了。

cell設定Identifier名稱為datacell

要使用cell都要設Identifier

如果要選定某個元表,選數字1的部份會比較好選,不容易選錯。

Style 要選擇 Basic

接下來要寫程式了…

點開 RestaurantTableViewController.swift

點開後會看到這二個func

因為要使用UITableViewDiffableDataSoure

所以就不用用到這二個func了

可以先刪除或註解掉

宣告變數

宣告變數來存放表格資料

放在viewDidLoad()上面

var restaurantNames = ["Cafe Deadend", "Homei", "Teakha", "Cafe Loisl", "Petite Oyster", "For Kee Restaurant", "Po's Atelier", "Bourke Street Bakery", "Haigh's Chocolate", "Palomino Espresso", "Upstate", "Traif", "Graham Avenue Meats And Deli", "Waffle & Wolf", "Five Leaves", "Cafe Lore", "Confessional", "Barrafina", "Donostia", "Royal Oak", "CASK Pub and Kitchen"]

宣告列舉

因為沒有了上面那兩個方法,無法告訴程式要放什麼資料,
所以我們要使用NSDiffableDataSourceSnapshot
要使用就要宣告列舉

enum Section {
        case all
    }
    

寫在restaurantNames變數的上方

這個列舉是用來定義一個新的 Section 型別。

只有一個case是因為表格只有一個區塊、

而case命名為all,表示為所有的資料。

建立 UITableViewDiffableDataSoure的實列

程式碼可以寫在viewDidLoad()底下

func configureDataSource() -> UITableViewDiffableDataSource<Section, String>{
        let cellIdentifier = "datacell"
        let dataSource = UITableViewDiffableDataSource<Section, String>(
            tableView: tableView,
            cellProvider: { tableView, indexPath, restaurantNames in
                let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
                
                cell.textLabel?.text = restaurantNames
                cell.imageView?.image = UIImage(named: "restaurant")
                
                return cell
            }
        )
        return dataSource
    }

第一行是函數宣告方式

->這個符號表示回傳

後面接著的是回傳物件的型別

configureDataSource是這個函數的名稱

所以是建立了一個名為configureDataSource()的函數,

回傳一個UITableViewDiffableDataSource<Section, String>的實例。

以上是資料來源的函數

使用資料來源的函數-lazy修飾器

資料來源的函數寫好了,接著就要使用它。

lazy var dataSource = configureDataSource()

如果沒有加上”lazy”會出現錯誤訊息:Cannot use instance member ‘configureDataSource’ within property initializer; property initializers run before ‘self’ is available

更新viewDidLoad

    override func viewDidLoad() {
    super.viewDidLoad()
    
    tableView.dataSource = dataSource
    
    var snapshot = NSDiffableDataSourceSnapshot<Section, String>()
    snapshot.appendSections([.all])
    snapshot.appendItems(restaurantNames, toSection: .all)
    
    dataSource.apply(snapshot, animatingDifferences: false)
}

現在測試一下

因為只有放一張照片,所以只有一張照片。

放不同的照片

新增新的陣列

var restaurantImages = ["Cafe Deadend", "Homei", "Teakha", "Cafe Loisl", "Petite Oyster", "For Kee Restaurant", "Po's Atelier", "Bourke Street Bakery", "Haigh's Chocolate", "Palomino Espresso", "Upstate", "Traif", "Graham Avenue Meats And Deli", "Waffle & Wolf", "Five Leaves", "Cafe Lore", "Confessional", "Barrafina", "Donostia", "Royal Oak", "CASK Pub and Kitchen"]

因為是陣列,所以要修改一下程式碼。

cell.imageView?.image = UIImage(named: "restaurant")

改成

cell.imageView?.image = UIImage(named: self.restaurantImages[indexPath.row])

設計Prototype Cell

更改cell樣式-Custom

上面在設定cell的樣式是用 Basic

如果要自訂的話要用 Custom

變更cell高度

拉出元件放到cell內

先拉一個圖片物件
大小為120*120

到它的屬性檢閱器,把 「Content Mode」改為 Aspect Fill

接著拉出三個Label

分別作用:
Name-餐廳名稱
Location-餐廳位置
Type-餐廳類型

屬性檢閱器有一些設定可以改

將三個label選取起來,要把它們群組起來

在佈局列中點選 Embed in 按鈕

選取「Stack View」

接著再跟圖片做一次群組

寫程式。。。。

為cell建立類別

與cell做聯結

宣告Outlet變數

@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var locationLabel: UILabel!
@IBOutlet weak var typeLabel: UILabel!
@IBOutlet weak var thumbnailImageView: UIImageView!

更新cell提供者

找出這一行程式碼:

let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)

改成

let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! RestaurantTableViewCell

接著

cell.textLabel?.text = restaurantNames
cell.imageView?.image = UIImage(named: self.restaurantImages[indexPath.row])

換成

cell.nameLabel.text = restaurantNames
cell.thumbnailImageView.image = UIImage(named: self.restaurantImages[indexPath.row])

測試後發現高度不能調高

剛剛我是從storyboard做高度的更改。。。無效

現在我用程式改高:

tableView.rowHeight = 140

寫在viewDidLoad()裡面

就可以了

將縮圖變成圓形

  • 背景顏色(Background Color)
  • 邊框(Border)
  • 邊框寛度(Border Width)
  • 陰影顏色(Shadow Color)
  • 陰影寛度(Width)
  • 透明度(Opacity)
  • 圓角半徑(Corner Radius)

以介面建構器來修改

加號按下去之後:

“key Path” 改成 “cornerRadius” 然後Enter

Type 屬性選 Number

最後值設定為 20

另外記得 Clip to Bounds 要打勾

這個功能是可以該圖形修為圓角

也可以用程式修改圖片

@IBOutlet weak var thumbnailImageView: UIImageView!{
        didSet{
            thumbnailImageView.layer.cornerRadius = 20
            thumbnailImageView.clipsToBounds = true
        }
    }

didSet就是swift的屬性觀察者。
在didSet區塊中,每次設定屬性值時會被呼叫。

使用深色模式測試APP


將 Location 跟 Type 顯示上去

var restaurantLocations = ["Hong Kong", "Hong Kong", "Hong Kong", "Hong Kong", "Hong Kong", "Hong Kong", "Hong Kong", "Sydney", "Sydney", "Sydney", "New York", "NewYork", "New York", "New York", "New York", "New York", "New York", "London", "London", "London", "London"]
    
    var restaurantTypes = ["Coffee & Tea Shop", "Cafe", "Tea House", "Austrian / Causual Drink", "French", "Bakery", "Bakery", "Chocolate", "Cafe", "American / Seafood", "American", "American", "Breakfast & Brunch", "Coffee & Tea", "Coffee & Tea", "Latin American", "Spanish", "Spanish", "Spanish", "British", "Thai"]

另外,加上這兩行

cell.locationLabel.text = restaurantLocations[indexPath.row]
cell.typeLabel.text = restaurantTypes[indexPath.row]

這樣就好看了

移除cell分隔線

在viewDidLoad()裡加入下行程式:


tableView.separatorStyle = .none

重新設計cell