Computer >> Hướng Dẫn Máy Tính >  >> Điện Thoại Thông Minh >> iPhone

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Trong bài viết này, chúng ta sẽ cố gắng tái tạo màn hình home của Spotify bằng Swift theo cách lập trình. Tại sao lại lập trình? Tôi nghĩ luôn tốt khi biết cách xây dựng thứ gì đó theo nhiều cách khác nhau, và tôi thích viết mã để làm việc theo cách lập trình. Những kỹ năng này đặc biệt hữu ích nếu bạn làm việc nhóm hoặc dùng version control.

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Đây là màn hình home thực tế của ứng dụng di động Spotify. Để đạt được bố cục kiểu này, chúng ta sẽ dùng UICollectionView, và có thể dùng TabBarController để tạo trình điều hướng tab.

Yêu cầu cơ bản: Trước hết hãy chắc chắn bạn đã cài Xcode 10+ và Swift 4+.

Hãy bắt đầu bằng cách tạo dự án Xcode mới:

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Và điều đầu tiên cần làm trong ViewController.swift là đổi superClass thành UICollectionViewController thay vì UIViewController vì class của chúng ta sẽ dựa trên collectionView.

import UIKit

class ViewController: UICollectionViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.backgroundColor = .purple
        // Thiết lập thêm sau khi load view
    }
}

Nếu bạn chạy app, build sẽ fail. Cần thêm mã vào file AppDelegate.swift trong hàm didFinishLaunchingWithOptions trước câu lệnh return:

let layout = UICollectionViewFlowLayout()
window = UIWindow()
window?.rootViewController = ViewController(collectionViewLayout: layout)

Mã sẽ trông như sau:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    let layout = UICollectionViewFlowLayout()
    window = UIWindow()
    window?.rootViewController = ViewController(collectionViewLayout: layout)
    return true
}

Bây giờ bạn có thể chạy app và thấy backgroundColor đổi thành purple:

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Bước tiếp theo là phân phối bố cục và chia đều không gian giữa các section.

Hãy định nghĩa các phương thức của CollectionView.

Các bước:

  • Đăng ký reusable cell với identifier duy nhất
  • Định nghĩa số lượng item trong section
  • Sử dụng cell đã đăng ký

Để dùng một số phương thức CollectionView, chúng ta cần luôn tuân theo UICollectionViewDelegateFlowLayout làm superClass và để có autoComplete các phương thức. Hãy bắt đầu với việc đăng ký CollectionViewCell.

Trong viewDidLoad(), gọi collectionView.register() để đăng ký reusable cell:

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

Sau đó định nghĩa số cell trong collectionView dùng numberOfItemsInSection. Hiện tại chỉ cần 5 item:

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

Bước tiếp theo là định nghĩa reusable cell dùng cellForItemAt trả về UICollectionViewCell và có id duy nhất cellId. Mã như sau:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
    cell.backgroundColor = .red
    return cell
}

Toàn bộ mã trông như sau:

import UIKit

class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
    let cellId: String = "cellId"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.backgroundColor = .purple
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
    }
    
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 5
    }
    
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
        cell.backgroundColor = .red
        return cell
    }
}

Bạn sẽ thấy 5 item với background đỏ trên màn hình:

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Thêm chiều rộng và chiều cao tùy chỉnh cho cell

Bây giờ cần đặt cell đúng thứ tự và cho chúng width và height. Mỗi cell sẽ lấy width của màn hình làm width.

Chúng ta may mắn có phương thức sizeForItemAt để cho cell width và height tùy chỉnh. Đây là phương thức trả về kiểu CGSize:

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

Vậy chúng ta làm Cell lấy width màn hình bằng view.frame.width và height tùy chỉnh kiểu CGFloat.

Kết quả trong Simulator:

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Mọi thứ trông tốt. Lần này tạo một custom cell có thể tái dùng. Tạo file Swift mới tên CustomCell:

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

CustomCell.swift trông như sau:

import UIKit

class CustomCell: UICollectionViewCell {
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Bây giờ cần sửa hai phương thức để hỗ trợ reusable cell: collectionView.register và cellForItemAt. Hãy sửa register method trước. Thay UICollectionViewCell.self bằng CustomCell.self:

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

Tiếp theo cần ép cellForItemAt tuân theo CustomCell như sau:

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CustomCell

Nếu chạy app có lẽ bạn không thấy thay đổi, hãy cho CustomCell backgroundColor = .yellow. Đừng quên xóa dòng cell.backgroundColor = .red trong cellForItemAt. Bạn sẽ thấy background đổi thành vàng.

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Bây giờ là lúc "cho muối" vào CustomCell :D

Nếu nhìn màn hình home Spotify, mỗi section là một CustomCell trong ví dụ của chúng ta chứa tiêu đề section, sub cell, và cuộn ngang:

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Thêm tiêu đề section

Hãy thêm nhãn tiêu đề vào cell. Tạo element titleLabel bên trong class CustomCell:

let titleLabel: UILabel = {
    let lb = UILabel()
    lb.text = "Section Title"
    lb.font = UIFont.boldSystemFont(ofSize: 14)
    lb.font = UIFont.boldSystemFont(ofSize: 14)
    return lb
}()

Sau đó thêm element vào view trong khối init():

addSubview(titleLabel)

Nếu chạy app bạn không thấy thay đổi, vì chưa đặt ràng buộc cho element. Hãy thêm ràng buộc – thêm thuộc tính lb.translatesAutoresizingMaskIntoConstraints = false cho titleLabel để áp dụng ràng buộc:

Sau khi thêm titleLabel vào view, định nghĩa ràng buộc:

addSubview(titleLabel)
titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = true
titleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 8).isActive = true

Luôn chắc chắn thêm .isActive = true – nếu không ràng buộc không hoạt động!

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Trước khi sang phần tiếp theo, hãy đổi background màu màn hình thành đen và bỏ màu vàng cho cell:

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Bây giờ đến phần lớn: đưa sub cell vào mỗi cell. Để làm được, chúng ta sẽ thêm CollectionView bên trong CustomCell.

Để thêm CollectionView vào UICollectionViewCell, cần thêm properties UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, và UICollectionViewDataSource làm superClass cho CustomCell.

Hãy tạo element collectionView như một view đơn giản:

let collectionView: UICollectionView = {
    // khởi tạo layout
    let layout = UICollectionViewFlowLayout()
    // set hướng cuộn ngang
    layout.scrollDirection = .horizontal
    // instance của collectionView
    let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
    // kích hoạt constraints
    cv.translatesAutoresizingMaskIntoConstraints = false
    return cv
}()
Tham khảo: https://stackoverflow.com/questions/44614743/add-uicollectionview-in-uicollectionviewcell

Chú ý chúng ta thêm layout vào collectionView như layer trong initializer như lần đầu với ViewController.swift. Ở đây cũng chỉ định hướng FlowLayout là .horizontal.

Thêm element collectionView vào view như subView. Chúng ta tạo hàm làm việc đó để code gọn hơn.

fileprivate func setupSubCells() {
    // thêm collectionView vào view
    addSubview(collectionView)
    collectionView.dataSource = self
    collectionView.delegate = self
    
    // setup constraints
    // làm cho nó vừa toàn bộ không gian CustomCell
    collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor).isActive = true
    collectionView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
    collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    collectionView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
}

Đảm bảo set delegate là self cho collectionView và dataSource:

collectionView.dataSource = self

collectionView.delegate = self

Sau đó gọi hàm trong khối init.

Xcode sẽ báo lỗi nếu build vì chưa tuân theo protocol UICollectionViewDelegate và UICollectionViewDelegateFlowLayout. Để fix, cần đăng ký sub cell reusable trước.

Tạo biến đầu class đặt tên cellId để dùng khi cần cell identifier:

let cellId: String = "subCellID"

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

Bây giờ còn thiếu hai phương thức để lỗi biến mất: numberOfItemsInSection định nghĩa số cell trong section và cellForItemAt định nghĩa reusable cell. Các phương thức này cần thiết cho collectionView hoạt động:

// số cell
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 4
}

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

Kết quả trông như sau:

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

Như bạn thấy, collectionView nền tím và sub cell vàng.

Điều cuối cùng trước khi kết thúc bài: làm subCells có chiều cao bằng section và làm width. Lại dùng sizeForItemAt định nghĩa height và width của cell.

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

Và đây là kết quả:

Xây dựng ứng dụng iOS lấy cảm hứng từ Spotify với Swift & AutoLayout

TUYỆT! Tôi dừng ở đây để bài không quá dài. Sẽ có phần hai thêm hình ảnh mẫu và điền dữ liệu.

Mã nguồn đầy đủ tại đây

Rất mong nếu bạn có bổ sung, câu hỏi, hoặc sửa lỗi, hãy đăng bình luận bên dưới hoặc nhắn tin Twitter cho tôi.

Đăng ký danh sách email để được thông báo khi phần hai hướng dẫn này xuất bản.