實作 Table View 功能 - Mamamoo成員 solo 歌曲列表

Julia
彼得潘的 Swift iOS / Flutter App 開發教室
10 min readJan 21, 2022

HW #51 實作TableView的基本公能

這次嘗試模仿了 Spotify 的排版還有他的愛心功能,連圖片都是從 Spotify 上截圖的喔

下面是短短的 gif demo

私心附上有 mv 片段的 App錄屏

這個月,我的本命帶著快時隔兩年的solo 專輯回歸囉 ! 主打歌又是我超愛的psycho 主題,快點擊下面一起欣賞超好聽的音樂 (到底是哪一個psycho 可以上一秒可愛下一秒又那麼帥氣啦 !!!!!)

建立客製化的 TableViewCell

  • 把 TableViewCell 換成custom 並幫他取一個 identifier
  • 在裡面放好想要的物件後,建一個 subclass 是 UITableViewCell 的file 幫物件拉 IBOutlet

幫放進cell裡的資料建立 struct

  • like variable 決定有沒有按愛心按鈕,會隨著使用者操作變換,所以 like, 裝有 songInfo 的 songList, 和裝有singerInfo 的 playList都要用 var
struct songInfo{
let singerName :String
let songTitle: String
let imageName : String
let url : String
var like : Bool
}
struct singerInfo {
let singerName :String
var songList : Array<songInfo>
}
  • 再以套娃的方式把每一個歌手的資料放進Array裡,就能擁有 section 和 row 資料

設定要有幾個section 和 row

override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return playList.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return playList[section].songList.count
}

連結到tableViewController

把之前幫 tableViewCell 取的 identifier 放進 dequeueReusableCell(withIdentifier: propertyKey.songCell, for: indexPath) 然後用 as?轉成 剛剛幫tableViewCell 建立的class

struct propertyKey {
static let songCell = "songCell"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: propertyKey.songCell, for: indexPath) as? playListTableViewCell else {return UITableViewCell()}
let song = playList[indexPath.section].songList[indexPath.row]
cell.singerLabel.text = song.singerName
cell.songTitleLabel.text = song.songTitle
cell.songImageView.image = UIImage(named: song.imageName)
if song.like == true {
cell.heartButton.setImage(UIImage(systemName: "heart.fill"), for: .normal)
cell.heartButton.tintColor = .green
}else {
cell.heartButton.setImage(UIImage(systemName: "heart"), for: .normal)
cell.heartButton.tintColor = .lightGray
}

return cell
}

模仿 Spotify 設定愛心按鈕

  • 因為 tableViewCell 會重複利用 (dequeueReusableCell),所以按完按鈕後,要將改變後的值存回 songInfo,不然會複製到後面的 cell
  • 用下面的方把找到按鈕在 tableView 上的座標,並對應得到第幾個row,在把值案照row number 給存回 songInfo
let point = sender.convert(CGPoint.zero, to: tableView)
if let indexPath = tableView.indexPathForRow(at: point){
...
}
@IBAction func heartButtonChange(_ sender: UIButton) {
let point = sender.convert(CGPoint.zero, to: tableView)
if let indexPath = tableView.indexPathForRow(at: point){
if sender.imageView?.image == UIImage(systemName: "heart"){
playList[indexPath.section].songList[indexPath.row].like = true
sender.setImage(UIImage(systemName: "heart.fill"), for: .normal)
sender.tintColor = .green
} else if sender.imageView?.image == UIImage(systemName: "heart.fill"){
playList[indexPath.section].songList[indexPath.row].like = false

sender.setImage(UIImage(systemName: "heart"), for: .normal)
sender.tintColor = .lightGray
}

}

}

幫每個section 設定header

  • 設定 section 裡的內容
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return playList[section].singerName
}
  • 設定背景顏色還有字型
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let headerView = view as! UITableViewHeaderFooterView
headerView.contentView.backgroundColor = .black
headerView.textLabel?.textColor = .white
headerView.textLabel?.font = .systemFont(ofSize: 26, weight: .bold)
headerView.textLabel?.sizeToFit()
}
  • 設定header 的高度
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
}

用IBSegueAction 將要傳的資料傳過去

  • Segue 要從 table cell 連到下一個View (不是從 View 連到下一個 View )
@IBSegueAction func showWebSite(_ coder: NSCoder) -> playListWebViewController? {
guard let section = tableView.indexPathForSelectedRow?.section else {return nil}
guard let row = tableView.indexPathForSelectedRow?.row else {return nil}
let song = playList[section].songList[row]
return playListWebViewController(coder: coder, song: song)
}

顯示對應的 YouTube MV 網頁

  • 將WebView 連IBOutlet
  • 記得要 import WebKit
@IBOutlet weak var youtubeWebView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()

let request = URLRequest(url: URL(string: song.url)!)
youtubeWebView.load(request)
}

Github:

Link:

--

--