Trong bài đăng này, chúng tôi sẽ cố gắng tạo lại bố cục màn hình chính Spotify trong Swift theo chương trình. Tại sao phải lập trình? Tôi nghĩ rằng luôn tốt nếu biết cách xây dựng mọi thứ theo những cách khác nhau và tôi thích viết mã để thực hiện mọi thứ theo lập trình. Những kỹ năng này đặc biệt hữu ích nếu bạn đang làm việc với nhóm hoặc sử dụng kiểm soát phiên bản.
Đây là màn hình chính thực tế của ứng dụng di động Spotify. Vì vậy, để đạt được loại bố cục này, chúng tôi sẽ sử dụng UICollectionView
và chúng tôi có thể sử dụng TabBarController
cũng như để tạo trình điều hướng tab.
Yêu cầu cơ bản:Trước tiên, hãy đảm bảo rằng bạn đã cài đặt Xcode +10 và nhanh chóng +4.
Hãy bắt đầu bằng cách tạo một dự án Xcode mới bằng Xcode:
Và điều đầu tiên chúng ta cần làm trong ViewController.swift
là thay đổi superClass thành UICollectionViewController
thay vì UIViewController
bởi vì lớp của chúng ta sẽ dựa trên collectionView
.
//
// ViewController.swift
// spotifyAutoLayout
//
// Created by admin on 10/31/19.
// Copyright © 2019 Said Hayani. All rights reserved.
//
import UIKit
class ViewController: UICollectionViewController {
override func viewDidLoad() {
super.viewDidLoad()
collectionView.backgroundColor = .purple
// Do any additional setup after loading the view.
}
}
Nếu bạn cố gắng chạy ứng dụng, bản dựng sẽ không thành công. Chúng tôi cần thêm một số mã vào AppDelegate.swift
tệp trong didFinishLaunchingWithOptions
chạy qua đoạn mã này trước return
tuyên bố:
let layout = UICollectionViewFlowLayout()
window = UIWindow()
window?.rootViewController = ViewController(collectionViewLayout: layout)
Và mã sẽ giố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 sẽ có thể chạy ứng dụng và xem backgroundColor
đã thay đổi thành purple
:
Bước tiếp theo là phân phối bố cục và chia đều không gian giữa các phần.
Hãy xác định các phương thức của CollectionView
của chúng tôi .
Các bước:
- Đăng ký một ô có thể sử dụng lại với số nhận dạng duy nhất
- Xác định số lượng các mục trong phần
- Sử dụng ô đã đăng ký
Để sử dụng một số CollectionView
chúng ta cần luôn tuân theo UICollectionViewDelegateFlowLayout
dưới dạng superClass và để nhận được tính năng Tự động hoàn thành của các phương thức. Vì vậy, hãy bắt đầu với việc đăng ký CollectionViewCell.
Bên trong View.DidLoad()
chúng tôi gọi là collectionView.register()
phương thức để đăng ký ô có thể sử dụng lại:
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
Sau đó, chúng tôi xác định số lượng ô mà chúng tôi sẽ có bên trong collectionView
sử dụng numberOfItemsInSection
. Hiện tại, chúng ta chỉ cần làm cho nó 5 mục:
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
Bước tiếp theo là xác định ô có thể sử dụng lại bằng cách sử dụng cellForItemAt
sẽ trả về UICollectionViewCell
và có một id duy nhất được gọi là cellId
. Mã trông như thế này:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
cell.backgroundColor = .red
return cell
}
Mã đầy đủ sẽ giố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ẽ có thể thấy 5 mục có nền màu đỏ trên màn hình:
Thêm chiều rộng và chiều cao tùy chỉnh vào các ô
Bây giờ chúng ta cần đặt các ô theo đúng thứ tự và cung cấp cho chúng một width
và height
. Mỗi ô sẽ lấy width
của màn hình dưới dạng width
.
Chúng tôi may mắn có sizeForItemAt
để chúng tôi có thể cung cấp cho các ô một width
tùy chỉnh và height
. Đây là một phương thức sẽ trả về CGSize
loại:
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ì vậy, chúng tôi đã tạo Cell
lấy width
của màn hình bằng cách sử dụng view.frame.width
và một height
tùy chỉnh với là CGFloat
loại.
Bây giờ bạn có thể thấy kết quả bên dưới trong Trình mô phỏng của mình:
Mọi thứ có vẻ tốt cho đến nay. Lần này, hãy tạo một ô tùy chỉnh có thể được sử dụng lại. Tạo một tệp Swift mới có tên CustomCell
:
CustomCell.swift
sẽ giố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ờ, điều tiếp theo chúng ta phải làm là sửa đổi hai phương thức để hỗ trợ ô có thể sử dụng lại, collectionView.register
và cellForItemAt
. Đầu tiên hãy sửa đổi phương thức đăng ký. Thay thế UICollectionViewCell.self
với CustomCell
:
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
Tiếp theo, chúng ta cần truyền cellForItemAt
để phù hợp với CustomCell
như bên dưới:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CustomCell
Nếu bạn chạy ứng dụng có thể bạn sẽ không nhận thấy bất kỳ thay đổi nào, vì vậy hãy cung cấp cho CustomCell một backgroundColor backgroundColor = .yellow
. Đừng quên xóa dòng cell.backgroundColor = .red
trong cellForItemAt
. Bạn sẽ thấy màu nền được thay đổi thành màu vàng?
Bây giờ đã đến lúc cho một ít muối vào CutomCell
:D
Nếu bạn nhìn vào màn hình chính Spotify, mỗi phần là một CustomCell
trong ví dụ của chúng tôi có chứa tiêu đề phần, các ô con và nằm ngang:
Thêm tiêu đề phần
Hãy thêm nhãn tiêu đề vào ô. Tạo titleLabel
phần tử bên trong CutomCell
lớp:
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 phần tử vào chế độ xem bên trong init()
khối:
addSubview(titleLabel)
Nếu bạn chạy ứng dụng, bạn sẽ không thấy bất kỳ thay đổi nào và đó là bởi vì chúng tôi chưa đặt bất kỳ ràng buộc nào cho phần tử. Vì vậy, hãy thêm một số ràng buộc - thêm thuộc tính này lb.translatesAutoresizingMaskIntoConstraints = false
đến titleLabel
để có thể áp dụng các ràng buộc cho phần tử:
Sau khi chúng tôi thêm titleLabel
đối với chế độ xem, chúng tôi xác định các ràng buộc:
addSubview(titleLabel)
titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = truetitleLabel.leftAnchor.constraint(equalTo: leftAnchor,constant: 8 ).isActive = true
Luôn đảm bảo thêm .isActive = true
tài sản - không có nó, ràng buộc sẽ không hoạt động!
Trước khi chuyển sang phần tiếp theo, trước tiên chúng ta hãy thay đổi màu nền của màn hình thành màu đen và cũng loại bỏ màu vàng cho các ô:
Bây giờ đến phần quan trọng:đặt các ô con vào mỗi ô. Để đạt được điều đó, chúng tôi sẽ thêm CollectionView
bên trong CustomCell
.
Để thêm CollectionView
bên trong UICollectionViewCell
chúng ta cần thêm thuộc tính UICollectionViewDelegate
, UICollectionViewDelegateFlowLayout
và UICollectionViewDataSource
dưới dạng superClass thành CustomCell
.
Hãy tạo collectionView
phần tử dưới dạng bất kỳ chế độ xem đơn giản nào:
let collectionView : UICollectionView = {
// init the layout
let layout = UICollectionViewFlowLayout()
// set the direction to be horizontal
layout.scrollDirection = .horizontal
// the instance of collectionView
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
// Activate constaints
cv.translatesAutoresizingMaskIntoConstraints = false
return cv
}()
Lưu ý rằng chúng tôi thêm layout
tới collectionView
dưới dạng lớp trong trình khởi tạo như chúng ta đã làm lần đầu tiên với viewController.swift
. Ở đây chúng tôi cũng chỉ định hướng của FlowLayout
trở thành .horizontal
.
Hãy thêm collectionView
phần tử cho chế độ xem dưới dạng subView.
Chúng tôi sẽ tạo một chức năng làm điều đó cho chúng tôi để làm cho mã sạch hơn một chút.
fileprivate func setupSubCells(){
// add collectionView to the view
addSubview(collectionView)
collectionView.dataSource = self
collectionView.delegate = self
// setup constrainst
// make it fit all the space of the 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 đặt ủy quyền thành self
cho collectionView
và cả dataSource:
collectionView.dataSource = self
collectionView.delegate = self
Sau đó gọi hàm trong init
khối.
Xcode sẽ hiển thị một số lỗi nếu bạn cố gắng tạo ứng dụng vì chúng tôi không tuân thủ UICollectionViewDelegate
và UICollectionViewDelegateFlowLayout
các giao thức. Để khắc phục điều đó, trước tiên chúng ta cần đăng ký ô con dưới dạng ô có thể sử dụng lại.
Tạo một biến ở đầu lớp và đặt tên cho nó là cellId
vì vậy chúng tôi có thể sử dụng nó khi chúng tôi cần số nhận dạng ô:
let cellId : String = "subCellID"
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
Bây giờ chúng tôi còn thiếu hai phương pháp nữa để làm cho lỗi biến mất:numberOfItemsInSection
xác định số lượng ô trong phần và cellForItemAt
xác định ô có thể sử dụng lại. Các phương pháp này là cần thiết cho collectionView
để hoạt động bình thường:
// number of cells
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ả sẽ như thế này:
Như bạn có thể thấy, collectionView
có màu tím làm nền và các ô phụ có màu vàng.
Điều cuối cùng chúng ta có thể làm trước khi kết thúc bài viết này là tạo subCells
có chiều cao của phần và chiều rộng. Một lần nữa, chúng tôi đang sử dụng sizeForItemAt
để xác định height
và width
của ô.
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à chúng tôi đây ?:
ĐẸP! Tôi sẽ dừng lại ở điểm này để bài viết này không quá dài. Tôi sẽ làm phần thứ hai, trong đó chúng ta sẽ thêm một số hình ảnh chế nhạo và điền vào đó một số dữ liệu.
Mã nguồn đầy đủ? đây
Vui lòng vui lòng nếu bạn có bất kỳ bổ sung, câu hỏi hoặc chỉnh sửa nào, hãy đăng nó trong phần bình luận bên dưới? hoặc đánh tôi trên Twitter.
Đăng ký vào danh sách email của tôi để được thông báo khi phần thứ hai của hướng dẫn này được xuất bản