🖥️
iOS App with Pop
Swift 4
Swift 4
  • iOS App development
  • Create New Project
  • Introduction to Xcode
  • App's life cycle
  • UIViewController
  • Storyboard
  • First Run
  • Display todo list
  • Basic Auto Layout
  • MVC
  • Model
  • Binding TableView
  • Binding TableViewCell
  • TableViewDelegate
  • Add navigationBar with + button
  • Add new item page
  • TextField and Switch
  • Binding action
  • Add mock item to todo list
  • Finish add item
  • Delete todo item
  • Edit todo item
  • Custom new layout
  • Adding new delegate
  • Refactor
  • Save data
  • Pushing edit view
  • Large navigation
  • Drag item
  • Drop item (in app)
  • Where to go from here?
Powered by GitBook
On this page
  • ดูไม่ค่อยสวยเลย
  • เพิ่มรูปไอคอนติ๊กถูกอันใหม่
  • เปลี่ยนมาแสดงค่าที่ปุ่มกับ Label ใหม่
  • refactor หน่อย

Custom new layout

PreviousEdit todo itemNextAdding new delegate

Last updated 6 years ago

ดูไม่ค่อยสวยเลย

เครื่องหมายติ๊กถูกอยู่ข้างหลังไม่ค่อยสวยเลย ดูแล้วนึกว่าหน้า Setting เรามาทำให้ติ๊กถูกได้โดยไม่ต้องเข้าไป Edit ข้างใน และทำให้มันดูออกว่า กดที่รายการจะเปิดหน้า Edit มาดู Detail และแก้ไขได้ แบบนี้

เริ่มจากการ custom TableViewCell มาแทน Cell แบบ Basic กันดีกว่า ให้เราสร้างไฟล์ใหม่ เลือกเป็น Cocoa Touch Class

จากนั้นตั้งชื่อเป็น TodoItemTableViewCell เป็น Subclass ของ UITableViewCell

เมื่อสร้างเสร็จ เราต้องบอก TableViewCell ใน Main.storyboard ด้วยว่าให้ใช้ class นี้

เลือกที่ todoItemCell ใน storyboard แล้วเปิด Attributes Inspector เปลี่ยน Style จาก Basic เป็น Custom จากนั้นให้เราเปิด Identity Inspector แล้วเลือก class เป็น TodoItemTableViewCell ที่เราสร้างเมื่อกี้ กด Enter

จากนั้นเราอยากให้ด้านขวาเป็นเครื่องหมายลูกศร ให้เราเปลี่ยน Accessory เป็น Disclosure Indicator

ถ้าลองรันดู จะพบว่าไม่เกิดอะไรขึ้น

TodoItemTableViewCell เป็น Subclass ของ UITableViewCell จึงทำให้โค้ดของเราที่ใช้ textLabel ใน tableView(_:cellForRowAt:) ยังใช้งานได้เหมือนเดิม แถมโค้ดเรายังเปลี่ยน Accessory เป็น Checkmark กับ None อยู่

เพิ่มรูปไอคอนติ๊กถูกอันใหม่

ก่อนที่เราจะทำปุ่มติ๊กถูกอันใหม่ เราก็ต้องเอารูปมาใส่ในโปรเจคของเราก่อน

ให้เราเปิด Assets.xcassets เหมือนกับตอนที่เราใส่รูปไอคอนแอพ แล้วให้เราลากรูปใหม่ทั้งหมดเข้ามา เราจะได้กลุ่มของรูปขึ้นมาใหม่ 2 กลุ่มคือ check กับ uncheck

จากนั้นเรากลับไปที่ Storyboard ลากปุ่มกับ Label มาใส่ที่ Cell ของเรา แล้วใส่รูปให้ปุ่มโดยใส่ชื่อรูปที่ property image ของปุ่มใน Attributes Inspector

จากนั้นเหมือนเดิมให้เราใส่ Auto layout โดยกรุ๊ปเข้าใน StackView แนวนอนก่อน ตั้ง Spacing เป็น 4 เพื่อให้ปุ่มกับ Label มันไม่ติดกัน จากนั้นตั้ง Constraint เทียบกับ container ของ Cell ทั้ง 4 ด้าน

จากนั้นกำหนดขอบเขตของ layout ใหม่เพื่อให้ StackView แสดงเต็ม Cell

จากนั้นเราต้องกำหนดให้ปุ่มเป็นสี่เหลี่ยมจตุรัส โดยกำหนด Constraint raio เป็น 1:1 ใส่ width ให้กว้างแค่ 35 point

ลองรันดูใหม่ จะพบว่าปุ่มกับ Label ที่เราสร้างโผล่ขึ้นมาแล้ว

เปลี่ยนมาแสดงค่าที่ปุ่มกับ Label ใหม่

เพื่อให้เราอ้างถึง ปุ่มกับ Label ได้ให้เราสร้าง Outlet เหมือนเดิมในคลาส TodoItemTableViewCell

TodoItemTableViewCell.swift
import UIKit

class TodoItemTableViewCell: UITableViewCell {

    @IBOutlet weak var checkboxButton: UIButton?
    @IBOutlet weak var titleLabel: UILabel?

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }
}

จากนั้นเราก็ผูกใน Storyboard เหมือนเดิม แต่คราวนี้เนื่องจากเราสร้าง Outlet ในคลาสของ TableViewCell ให้เราคลิ๊กขวาที่ TableViewCell แทนที่จะเป็น ViewController ของหน้า

แล้วผูก Outlet ทั้งปุ่มและ Label

จากนั้นให้เราแก้โค้ด tableView(_:cellForRowAt:) เป็นแบบนี้

ViewController.swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "todoItemCell", for: indexPath) as! TodoItemTableViewCell
    let item = todo.item(at: indexPath.row)
    cell.titleLabel?.text = item.title
    cell.checkboxButton?.setImage(UIImage(named: item.isDone ? "check": "uncheck"), for: .normal)
    return cell
}

เมื่อรันเราจะได้แบบนี้แล้ว

refactor หน่อย

จะเห็นว่าใน tableView(_:cellForRowAt:) เขียนโค้ด Set ค่าให้ปุ่มกับ Label เต็มเลย ให้เราย้ายไปที่ TodoItemTableViewCell ดีกว่า

เพิ่มโค้ดนี้ใน TodoItemTableViewCell

TodoItemTableViewCell.swift
func configure(item: TodoItem) {
    titleLabel?.text = item.title
    checkboxButton?.setImage(UIImage(named: item.isDone ? "check": "uncheck"), for: .normal)
}

เราจะได้โค้ดออกมาแบบนี้

TodoItemTableViewCell.swift
import UIKit

class TodoItemTableViewCell: UITableViewCell {

    @IBOutlet weak var checkboxButton: UIButton?
    @IBOutlet weak var titleLabel: UILabel?

    func configure(item: TodoItem) {
        titleLabel?.text = item.title
        checkboxButton?.setImage(UIImage(named: item.isDone ? "check": "uncheck"), for: .normal)
    }

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }
}

จากนั้นแก้ tableView(_:cellForRowAt:) ให้เรียก configure(item:) แบบนี้แทน

ViewController.swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "todoItemCell", for: indexPath) as! TodoItemTableViewCell
    let item = todo.item(at: indexPath.row)
    cell.configure(item: item)
    return cell
}

เมื่อเรารันก็ใช้ได้ละ แต่ดูเหมือน cell มันจะเล็กไปหน่อยดูเบียด ๆ กัน มาทำให้มันสูงขึ้นหน่อยดีกว่า

กลับมาที่ StackView ใน Cell ของเรา เพิ่ม Constraint Top กับ Bottom space จาก 4 เป็น 8 ดีกว่า แล้วเราจะเห็นสีแดงเกิดขึ้น นั่นคือ Constraint เรามีปัญหา

แต่พอเรารันก็ปกติดี Cell ก็สูงขึ้นด้วย นั่นเพราะเวลารัน Auto layout จะถูกคำนวณและทำให้ Cell ของเราจะเปลี่ยนขนาดสูงขึ้นเพื่อให้ได้ constraint ตามที่เรากำหนด แต่ใน storyboard ขนาดของ Cell ไม่ได้ยืดให้เราอัตโนมัติ จึงดูเหมือนว่า Constraint ที่กำหนด ไม่สามารถทำได้อย่างถูกต้อง จึงแสดง Error

เพื่อความสบายใจ ให้เราตั้งความสูงของ cell ใน storyboard เป็น 52 ใน Size Inspector แต่เวลารันมันจะไม่ได้ใช้นะ

จากนั้นกำหนดให้ StackView จัดของ Align Center เพียงเท่านี้ Error แดง ๆ ก็จะหายไป

ดาวน์โหลดรูปได้

การที่ Cell เปลี่ยนขนาดตาม content ภายในจากการตั้ง Constraint เรียกว่า เดิมต้องกำหนดให้ TableView รู้ว่าเราต้องการให้ Cell ปรับขนาดเอง แต่ตั้งแต่ iOS 11 TableView จะถูกตั้งให้ทำ self-sizing โดยอัตโนมัติ

ที่นี่
Self-sizing Table View Cells
ทำให้ติ๊กว่าทำเสร็จแล้ว ด้วยปุ่ม ด้านหน้า
เลือก class ของ TableViewCell เป็น TodoItemTableViewCell ที่เราเพิ่งสร้าง
ทุกอย่างยังเหมือนเดิม
ลากรูปเข้ามาเลย
เพิ่มปุ่มและ Label
ผูก Outlet ทั้งปุ่มและ Label