Nếu bạn không hình dung và nắm bắt được những yếu tố thiết kế giao diện trong ứng dụng của bạn như ( font chữ, màu nền, kích cỡ khung viền..) thì việc chỉnh sửa chúng quả là một cực hình. Tin tôi đi, tôi nói điều này từ chính những kinh nghiệm mà mình từng trải qua. Do vậy, tôi đã nghĩ về một API giao diện chung cho tất cả các đối tượng UIView.
body {background-color: powderblue;}
h1 {color: blue;}
p {color: red;}
Trên nền tảng web, chúng ta có CSS, một khuôn mẫu chuẩn cho việc thiết kế giao diện. Nó cho phép bạn tạo ra những view classs, và áp dụng một mẫu thiết kế cho nhiều view và các subclass của chúng. Và tôi muốn cùng các bạn tạo ra một công cụ tuyệt vời như vậy trên iOS.
Công cụ của chúng ta cần phải thỏa mãn những thứ sau:
- Dễ khởi tạo, thay đổi và maintain.
- Tất cả đều được khai báo tại một nơi riêng biệt, và không động chạm gì đến code của project.
- |Một style có thể thừa kế, override từ style khác, đồng nghĩa với việc không có code lặp lại.
Đầu tiên là chúng ta đóng gói các style lại thành một struct, chứa những properties của UIView mà cần cho việc thiết kế giao diện:
struct UIViewStyle {
let backgroundColor: UIColor
let cornerRadius: CGFloat
}
Có một điều rất dễ nhận ra đó là chúng ta có rất nhiều những property dạng như vậy. Ví dụ như với UILabel, chúng ta lại phải khởi tạo một struct mới , và một function mới để apply vào đối tượng label đó. Như vậy sẽ rất mất công và khiến code cồng kềnh hơn.
Nó cũng rất khó để mở rộng. Nếu tôi muốn thiết kế ở một property mới, tôi phải thêm property đó vào tất cả struct. Việc này vi phạm vào quy tắc mở/đóng.
Khó khăn cuối cùng đó là không dễ để nhiều style tự động kết hợp lại với nhau một cách hoàn chỉnh. Chúng ta phải tạo nhiều struct, sau đó lại gán property của những struct đó vào thành một struct mới, rất phức tạp.
Do vậy tôi bắt đầu nghĩ về vấn đề một cách cơ bản hơn. Công việc của style là gì? Đi tới một subclass của UIView và thay đổi một số thuộc tính ở đó. Nói theo cách khác là thao tác làm ảnh hưởng đến UIView. Đến đây thì chắc có nhiều bạn đã liên tưởng đến sự tương đồng với function.
typealias UIViewStyle<T: UIView> = (T)-> Void
"Style" không khác gì một function áp dựng vào một đối tượng UIView. Ví dụ nếu chúng ta muốn thay đổi kich cỡ chữ của UILabel:
let smallLabelStyle: UIViewStyle<UILabel> = { label in
label.font = label.font.withSize(12)
}
Với cách này, chúng ta không phải khởi tạo property cho từng subclass của UIView. Với việc Function này sẽ nhận đúng kiểu mà chúng ta cần, và các property sẽ sẵn sàng được thay đổi.
Điểm hay của việc sử dụng một function này đó là một style có thể thừa kế từ những style khác một cách dễ dàng bằng việc chỉ cần gọi một function ngay sau đó.
let smallLabelStyle: UIViewStyle<UILabel> = { label in
label.font = label.font.withSize(12)
}
let lightLabelStyle: UIViewStyle<UILabel> = { label in
label.textColor = .lightGray
}
let captionLabelStyle: UIViewStyle<UILabel> = { label in
smallLabelStyle(label)
lightLabelStyle(label)
}
Để API của chúng ta dễ sử dụng hơn, chúng ta sẽ thêm một UIViewStyle struct chứa tất cả những function chỉnh sửa style.
struct UIViewStyle<T: UIView> {
let styling: (T)-> Void
}
Style của chúng ta sẽ nhìn khác một chút, nhưng về bản chất sẽ không khác gì cấu trúc ở trên.
let smallLabelStyle: UIViewStyle<UILabel> = UIViewStyle { label in
label.font = label.font.withSize(12)
}
let lightLabelStyle: UIViewStyle<UILabel> = UIViewStyle { label in
label.textColor = .lightGray
}
let captionLabelStyle: UIViewStyle<UILabel> = UIViewStyle { label in
smallLabelStyle.styling(label)
lightLabelStyle.styling(label)
}
Chúng ta chỉ cần làm 2 thay đổi nhỏ như sau:
Đầu tiên chúng ta tạo ra một instance của UIViewStyle, và truyền vào một closure như là một parameter trong hàm UIViewStyle.init. Sau đó, tại caption style, thay vì gọi style như một function, chúng ta gọi tới biến styling ở trong UIViewStyle instance.
Lúc này chúng ta có thể khai báo một compose function chưa một tập hợp các parameter( variadic parameter) và gọi chúng trong trường hợp success, từ đó trả về một UIViewStyle mới .
struct UIViewStyle<T: UIView> {
let styling: (T)-> Void
static func compose(_ styles: UIViewStyle<T>...)-> UIViewStyle<T> {
return UIViewStyle { view in
for style in styles {
style.styling(view)
}
}
}
}
Chúng ta có thể gọi đây là một factory method. Nó sẽ làm cho việc khai báo các kiểu style khác nhau trở nên sáng sủa và tường minh hơn.
let captionLabelStyle: UIViewStyle<UILabel> = .compose(smallLabelStyle, lightLabelStyle)
Bên cạnh đó, chúng ta cũng thêm vào một apply function thuộc kiểu UIView và gọi những phương thức styling trong UIView
struct UIViewStyle<T: UIView> {
//...
func apply(to view: T) {
styling(view)
}
}
Bây giờ chúng ta đã có một cách khai báo mẫu thiết kế gọn gàng, an toàn và tối ưu trong ứng dụng của chúng ta. Và cũng rất dễ dàng để áp dụng những style này vào trong các item của chúng ta tại UIViewController hoặc UIView.
class ViewController: UIViewController {
let captionLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
captionLabelStyle.apply(to: captionLabel)
}
}
Tham gia ngay khoá học lập trình iOS, hình thức học tập rất linh hoạt cho bạn lựa chọn và sẽ có mức học phí khác nhau tuỳ theo bạn chọn học Online, Offline hoặc FlipLearning(Kết hợp giữa Online và Offline). Ngoài ra bạn có thể tham gia thực tập toàn thời gian tại Techmaster để rút ngắn thời gian học và tăng cơ hội việc làm.
Khóa học lập trình di động tại Techmaster:
Để cài đặt MacOSX lên phần cứng không phải Apple liên hệ chuyên gia cài Hackintosh:
- Nguyễn Minh Sơn: 01287065634
- Huỳnh Minh Sơn: 0936225565
- Website: caidatmacos.com
Bình luận