Ví dụ về lớp con UIView tùy chỉnh
Tôi thường tạo ứng dụng iOS mà không sử dụng bảng phân cảnh hoặc ngòi. Tôi sẽ chia sẻ một số kỹ thuật tôi đã học được để trả lời câu hỏi của bạn.
Ẩn các init
phương pháp không mong muốn
Đề xuất đầu tiên của tôi là khai báo một cơ sở UIView
để ẩn các bộ khởi tạo không mong muốn. Tôi đã thảo luận chi tiết về cách tiếp cận này trong câu trả lời của mình cho "Cách ẩn Bảng phân cảnh và Bộ khởi tạo cụ thể Nib trong Lớp con giao diện người dùng" . Lưu ý: Cách tiếp cận này giả định rằng bạn sẽ không sử dụng BaseView
hoặc con cháu của nó trong bảng phân cảnh hoặc ngòi vì nó cố tình khiến ứng dụng gặp sự cố.
class BaseView: UIView {
// This initializer hides init(frame:) from subclasses
init() {
super.init(frame: CGRect.zero)
}
// This attribute hides `init(coder:)` from subclasses
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
Lớp con UIView tùy chỉnh của bạn sẽ kế thừa từ BaseView
. Nó phải gọi super.init () trong bộ khởi tạo của nó. Nó không cần phải thực hiện init(coder:)
. Điều này được chứng minh trong ví dụ dưới đây.
Thêm một UITextField
Tôi tạo thuộc tính được lưu trữ cho các lượt xem phụ được tham chiếu bên ngoài init
phương thức. Tôi thường làm như vậy cho một UITextField. Tôi thích subviews thuyết minh trong việc kê khai tài sản như thế này subview: let textField = UITextField()
.
UITextField sẽ không hiển thị trừ khi bạn thêm nó vào danh sách lượt xem phụ của chế độ xem tùy chỉnh bằng cách gọi addSubview(_:)
. Điều này được chứng minh trong ví dụ dưới đây.
Bố cục có lập trình không có bố cục tự động
UITextField sẽ không hiển thị trừ khi bạn đặt kích thước và vị trí của nó. Tôi thường làm bố cục trong mã (không sử dụng Bố cục Tự động) trong phương thức layoutSubviews .layoutSubviews()
được gọi ban đầu và bất cứ khi nào một sự kiện thay đổi kích thước xảy ra. Điều này cho phép điều chỉnh bố cục tùy thuộc vào kích thước của CustomView. Ví dụ: nếu CustomView xuất hiện toàn bộ chiều rộng trên các kích thước khác nhau của iPhone và iPad và điều chỉnh để xoay, thì nó cần phải phù hợp với nhiều kích thước ban đầu và thay đổi kích thước động.
Bạn có thể tham khảo frame.height
và frame.width
bên trong layoutSubviews()
để lấy kích thước của CustomView để tham khảo. Điều này được chứng minh trong ví dụ dưới đây.
Lớp con UIView mẫu
Một lớp con UIView tùy chỉnh chứa UITextField không cần triển khai init?(coder:)
.
class CustomView: BaseView {
let textField = UITextField()
override init() {
super.init()
// configure and add textField as subview
textField.placeholder = "placeholder text"
textField.font = UIFont.systemFont(ofSize: 12)
addSubview(textField)
}
override func layoutSubviews() {
super.layoutSubviews()
// Set textField size and position
textField.frame.size = CGSize(width: frame.width - 20, height: 30)
textField.frame.origin = CGPoint(x: 10, y: 10)
}
}
Bố cục có lập trình với Bố cục tự động
Bạn cũng có thể triển khai bố cục bằng cách sử dụng Bố cục Tự động trong mã. Vì tôi không thường xuyên làm điều này, tôi sẽ không đưa ra một ví dụ. Bạn có thể tìm thấy các ví dụ về việc triển khai Bố cục Tự động trong mã trên Stack Overflow và các nơi khác trên Internet.
Khung bố cục có lập trình
Có các khung công tác mã nguồn mở thực hiện bố cục trong mã. Một cái tôi quan tâm nhưng chưa thử là LayoutKit . Nó được viết bởi nhóm phát triển LinkedIn. Từ kho lưu trữ Github: "LinkedIn đã tạo LayoutKit vì chúng tôi nhận thấy rằng Bố cục Tự động không đủ hiệu quả đối với các cấu trúc phân cấp chế độ xem phức tạp trong các chế độ xem có thể cuộn."
Tại sao lại đưa fatalError
vàoinit(coder:)
Khi tạo các lớp con UIView sẽ không bao giờ được sử dụng trong bảng phân cảnh hoặc nib, bạn có thể giới thiệu các trình khởi tạo với các tham số và yêu cầu khởi tạo khác nhau mà init(coder:)
phương thức này không thể gọi được . Nếu bạn không init (coder :) với a fatalError
, nó có thể dẫn đến các vấn đề rất khó hiểu ở dòng nếu vô tình được sử dụng trong storyboard / nib. FatError khẳng định những ý định này.
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
Nếu bạn muốn chạy một số mã khi lớp con được tạo bất kể nó được tạo bằng mã hay bảng phân cảnh / nib thì bạn có thể làm như sau (dựa trên câu trả lời của Jeff Gu Kang )
class CustomView: UIView {
override init (frame: CGRect) {
super.init(frame: frame)
initCommon()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initCommon()
}
func initCommon() {
// Your custom initialization code
}
}