Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> สมาร์ทโฟน >> iPhone

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

นี่คือภาคที่ 2 ของบทความสร้าง UI โคลน Spotify ด้วย AutoLayout แบบโปรแกรมมิง หากพลาดภาคแรก ไม่ต้องกังวล - โปรดไปอ่านก่อนครับ

ในบทความนี้ เราจะเพิ่มรูปภาพจำลอง (Mocked Pictures) และพยายามทำให้ UI ดูเหมือน Spotify จริงๆ

นี่คือสิ่งที่เราจะทำวันนี้ 👇

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

นี่คือจุดที่เราหยุดในภาคแรก:

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

ขั้นตอนต่อไปคือสร้าง Custom Cell เริ่มต้นด้วยการสร้างชื่อ SubCustomCell

ขั้นแรก สร้างไฟล์ Swift ใหม่ในโฟลเดอร์โปรเจกต์ ชื่อ SubCustomCell.swift ไฟล์นี้จะมี Custom Cell แทน Playlist หลังสร้างไฟล์ ใส่โค้ดด้านล่างและลอง initialize cell ด้วย backgroundColor เพื่อดูการเปลี่ยนแปลง UI เมื่อลงทะเบียน cell กับ collectionView

import UIKit
class SubCustomCell: UICollectionViewCell {
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .red
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

จากนั้นลงทะเบียน SubCustomCell ภายใน CustomCell.swift ในบล็อก init แทนที่ UICollectionViewCell.self ด้วย SubCustomCell ดังนี้

collectionView.register(SubCustomCell.self, forCellWithReuseIdentifier: cellId)

ต้องแก้ไขเมธอด cellForItemAt ให้สอดคล้องกับ SubCustomCell ด้วย

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SubCustomCell
    // cell.backgroundColor = .yellow
    return cell
}

ควรเห็น backgroundColor เปลี่ยนเป็นสีแดง

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์
Swift CustomCell

จนถึงตรงนี้ทุกอย่างควรเข้าใจง่ายและชัดเจน

ตอนนี้เราจะเติมรูปภาพจำลองลงใน Cell และสร้าง ImageView ภายในแต่ละ Cell ผมดาวน์โหลดรูปสุ่มจาก pexels.com แต่อยู่ที่คุณ ใช้รูปอะไรก็ได้ (รวมถึงรูปเหล่านี้) หาได้ในไฟล์โปรเจกต์บน GitHub

สร้าง UIImageView ใน SubCustomCell.swift และทำ Constraints

let ImageView: UIImageView = {
    let iv = UIImageView()
    iv.backgroundColor = .yellow
    return iv
}()

เพิ่มลงใน view ภายในบล็อก init ด้วย addSubView

override init(frame: CGRect) {
    super.init(frame: frame)
    addSubview(ImageView)
}

ทำให้ ImageView ครอบพื้นที่ทั้งหมดใน Cell ด้วย Constraints ด้านล่าง

ImageView.translatesAutoresizingMaskIntoConstraints = false
ImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
ImageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
ImageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
ImageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
  • LeftAnchor = จุดล็อกซ้ายของ Cell
  • RightAnchor = จุดล็อกขวาของ Cell
  • BottomAnchor = จุดล็อกล่างของ Cell
  • TopAnchor = จุดล็อกบนของ Cell

การตั้ง Anchor ของ ImageView เท่ากับ Anchor ของ Cell ทั้ง 4 ด้าน ทำให้ ImageView ขยายเต็มพื้นที่ของ SubCustomCell

หมายเหตุ: ต้องใช้ translatesAutoresizingMaskIntoConstraints ก่อน จึงจะใช้ Constraints ได้ และอย่าลืมตั้ง isActive = true ไม่งั้น Constraints จะไม่ทำงาน

ImageView ควรมีรูปภาพ ให้เพิ่มเข้าไป

let ImageView: UIImageView = {
    let iv = UIImageView()
    iv.backgroundColor = .yellow
    // มีไฟล์ image1 ในโปรเจกต์
    iv.image = UIImage(named: "image1")
    iv.contentMode = .scaleAspectFill
    iv.clipsToBounds = true
    return iv
}()

Build และ Run แอป ควรเห็นผลลัพธ์และรูปที่เพิ่มใน SubCustomCell

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

เยี่ยม 😎 ตอนนี้ยังมีองค์ประกอบที่ต้องเพิ่มใน SubCustomCell อีกหนึ่งอย่างคือ Title แทนชื่อ Playlist: UILabel

สำหรับ Title จะเป็นแบบนี้:

let TitleLabel: UILabel = {
    let lb = UILabel()
    lb.textColor = UIColor.lightGray
    lb.font = UIFont.systemFont(ofSize: 16)
    lb.font = UIFont.boldSystemFont(ofSize: 20)
    lb.text = "Evening Music"
    return lb
}()

ผมใส่ข้อความสุ่ม คุณใส่อะไรก็ได้ ขั้นตอนต่อไปคือเพิ่ม Element ลง View และให้ Constraints Title จะวางที่ด้านล่างของ ImageView

เพิ่มลง View:

addSubview(TitleLabel)

Constraints สำหรับ ImageView และ TitleLabel

ImageView.translatesAutoresizingMaskIntoConstraints = false
ImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
ImageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
ImageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
ImageView.heightAnchor.constraint(equalToConstant: 240).isActive = true
ImageView.bottomAnchor.constraint(equalTo: TitleLabel.topAnchor).isActive = true
TitleLabel.translatesAutoresizingMaskIntoConstraints = false
TitleLabel.topAnchor.constraint(equalTo: ImageView.bottomAnchor, constant: 10).isActive = true
TitleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 5).isActive = true
TitleLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -5).isActive = true

เสร็จแล้ว!

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

เราทำให้รูปครอบพื้นที่ส่วนใหญ่ ส่วนที่เหลือสำหรับ Title 如你所见 สามารถเลื่อนแนวนอนในแต่ละ Section และแนวตั้งในหน้าจอทั้งหมด

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

ตอนนี้ใส่ Mock Data ลง Cell ให้รู้สึกเหมือนจริง ผมสร้างไฟล์ JSON ที่มีข้อมูลสุ่มสำหรับ Sections และ Playlists

ขั้นแรก สร้าง Struct 2 ตัว: Section และ Playlist สร้างไฟล์แยกสำหรับแต่ละ Struct

section.swift

import Foundation
struct Section {
    var title: String
    var playlists: NSArray
    init(dictionary: [String: Any]) {
        self.title = dictionary["title"] as? String ?? ""
        self.playlists = dictionary["playlists"] as? NSArray ?? []
    }
}

playlist.swift

import Foundation
struct PlayList {
    var title: String
    var image: String
    init(dictionary: [String: Any]) {
        self.title = dictionary["title"] as? String ?? ""
        self.image = dictionary["image"] as? String ?? ""
    }
}

ใน ViewController.swift สร้างฟังก์ชันดึง JSON และเก็บผลลัพธ์ใน Array

print("attempt to fetch Json")
if let path = Bundle.main.path(forResource: "test", ofType: "json") {
    do {
        let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
        let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
        if let jsonResult = jsonResult as? [Any] {
            jsonResult.forEach { (item) in
                let section = Section(dictionary: item as! [String: Any])
                self.sections.append(section)
            }
            self.collectionView.reloadData()
        }
    } catch {
        // handle error
    }
}

ฟังก์ชัน fetchJson เรียกใน ViewDidLoad มีตัวแปร sections เก็บผลลัพธ์:

var sections = [Section]()

ขั้นตอนต่อไป ส่งข้อมูลจาก ViewController ไป CustomCell สร้างตัวแปรใน CustomCell รับข้อมูลแต่ละ Section:

var section: Section? {
    didSet {
        print("section ✅", self.section)
    }
}

ใช้ cellForItemAt ใน ViewController ส่งข้อมูลตรงไป CustomCell

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CustomCell
    cell.section = sections[indexPath.item]
    return cell
}

หมายเหตุ: เรียก self.collectionView.reloadData() ทุกครั้งที่ fetchJson ทำงาน บล็อกด้านล่างใน CustomCell จะถูกเรียก ดู Console: shift + command + C

var section: Section? {
    didSet {
        print("section ✅", self.section)
    }
}

แก้ไขแรกคือตั้งค่า Section Title:

var section: Section? {
    didSet {
        print("section ✅", self.section)
        guard let section = self.section else { return }
        self.titleLabel.text = section.title
    }
}

ควรเห็นแต่ละ Section มี Title เฉพาะตัวบนหน้าจอ 😊

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

ส่งข้อมูลต่อไป SubCustomCell ทำเหมือนเดิม ส่ง Array playlists สร้างตัวแปร playlists ใน CustomCell

var playlists: [PlayList]() // empty

Map ผ่าน playlists จาก JSON เพิ่มแต่ละ Playlist ลงตัวแปร playlists

var section: Section? {
    didSet {
        print("section ✅", self.section)
        guard let section = self.section else { return }
        self.titleLabel.text = section.title
        // append to playlists array
        self.section?.playlists.forEach({ (item) in
            let playlist = PlayList(dictionary: item as! [String: Any])
            self.playlists.append(playlist)
        })
        self.collectionView.reloadData()
    }
}

ระวัง! ถ้า Run อาจ Crash เพราะลืมตั้งจำนวน Sections ตอนรับข้อมูลจาก JSON จำนวนต้องเป็น Dynamic ตามจำนวน Sections ใน JSON ต้องแก้ numberOfItemsInSection ใน ViewController:

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return sections.count
}

ทำเหมือนกันใน CustomCell.swift แต่พิจารณาจำนวน playlists

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return self.playlists.count
}

ขั้นสุดท้าย ส่ง Playlist Object แต่ละตัวไป SubCustomCell ใน cellForItemAt ของ CustomCell.swift

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SubCustomCell
    // here ?
    cell.playlist = playlists[indexPath.item]
    return cell
}

รับข้อมูลใน SubCustomCell ผ่านตัวแปร playlist แสดง Title และ Image ของ Playlist

var playlist: PlayList? {
    didSet {
        print("Playlist ?", self.playlist)
        guard let playlist = self.playlist else { return }
        // The Image ?
        self.ImageView.image = UIImage(named: playlist.image)
        // the playlist title ?
        self.TitleLabel.text = self.playlist?.title
    }
}

คิดว่าทุกอย่างควรทำงานได้แล้ว 👇

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

อัปเดต UI สุดท้าย: เพิ่ม Padding และ Margin ให้ Section และ Playlist Title และทำให้ Playlist เล็กลงนิดหน่อย

ก่อนอื่น เพิ่ม Padding ให้ Section Title ใน CustomCell ภายใน setupSubCells:

collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 15).isActive = true

ถ้า CollectionView ติดกับ TitleLabel เกินไป ให้เพิ่ม Space 15

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

ต่อมา Title ของ Playlist ใน SubCustomCell เพิ่ม Space ใต้ ImageView

ImageView.bottomAnchor.constraint(equalTo: TitleLabel.topAnchor, constant: -15).isActive = true

มี Constant อยู่แล้ว ต้องเป็น -15 จึงจะทำงาน

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

สุดท้าย ทำ Playlist ให้เล็กลงง่ายๆ คือ ทำ Height และ Width ของ Playlist Cell เท่ากับ Section Cell Height หาร 2

CustomCell.swift

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let width = frame.height / 2
    let height = frame.height / 2
    return CGSize(width: width, height: height)
}

ตั้งค่า ImageView Height = 150

// SubCustomCell.swift
ImageView.heightAnchor.constraint(equalToConstant: 150).isActive = true

เสร็จแล้ว 😎

สร้างโคลน Spotify iOS ด้วย AutoLayout: เพิ่มรูปภาพและปรับ UI ด้วยโค้ดอย่างสมบูรณ์

พอดีครับ ไม่อยากทำยาวเกินไป จะมีภาคต่อเพิ่ม TabBar คำอธิบาย และไอคอน Playlist

ดู Full Source Code บน GitHub👇

ขอบคุณสำหรับเวลา หวังไม่ได้พลาดอะไร ถ้ามี @mention ผมที่ Twitter ได้เลย หรือมีคำถาม/เพิ่มเติม ประตูเปิดให้ทุกคน ขอบคุณครับ 🙏🙏

สมัครรับ อีเมลเพื่อรับแจ้งตอนเผยแพร่ภาคที่ 3 ของบทเรียนนี้

โดยดרך แค่เพิ่งทำงานกับกลุ่มวิศวกรซอฟต์แวร์ที่เก่งมากสำหรับแอปมือถือของผม องค์กรดีเยี่ยม ส่งมอบผลิตภัณฑ์เร็วมากกว่าบริษัทและฟรีแลนซ์อื่นๆ ที่เคยทำงาน ผมแนะนำพวกเขาได้เลย ส่งอีเมลมาที่ said@devsdata.com ถ้าอยากติดต่อ