0

Using IBDesignable and IBInspectable to make awesome UI components in iOS

1. User Defined Runtime Attributes

Dùng IBInspectable chúng ta có thể sử dụng 1 tính năng rất hay của iOS: user-defined runtime attributes(UDRA). Tính năng này cho phép chúng ta thay đổi trực tiếp các thông số của component trên iOS trên file Xib hay Storyboard Trước khi có IBInspectable để sử dụng UDRA chúng ta phải khai báo các key path, type và value trên file Xib hay Storyboard, và các keypath này phải chính xác tương ứng với các thuộc tính. Để bo góc cho view ta có thể set như sau:

Hạn chế của việc dùng trên là chúng ta không thể nhìn thấy trực tiếp sự thay đổi khi set, các keyPath phải nhớ chính xác vì nó là thuộc tính của component trong ios.

2. IBInspectable

Với IBInspectable chúng ta có thể dễ dàng chỉnh sửa các thông số thông qua Interface Builder’s inspector panel mà không cần quan tâm đến keypath.

Chúng ta tạo 1 class kế thừa từ UIView đặt tên là CustomView, trong CustomView chúng ta khai báo 1 thuộc tính cornerRadius

@IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            layer.cornerRadius = cornerRadius
            layer.masksToBounds = cornerRadius > 0
        }
    }

Tương tự như vậy chúng ta có thể chỉnh rất nhiều thông số của component UIView như: borderWidth, borderColor, opacity …

3. IBDesignable

Nếu chỉ dùng mỗi IBInspectable ta chỉ thấy được sự thay đổi khi chạy app lên còn trên file UI mọi thứ vẫn không thay đổi. Khi đó chúng ta có thể dùng IBInspectable để Xcode có thể render sự thay đổi trực tiếp lên component mà không cần phải build hay chạy lại app. Để làm việc này chúng ta chỉ cần thêm IBInspectable vào trước tên class chúng ta đã tạo.

@IBDesignable class MyCustomView: UIView {
    ...
}

Việc sử dụng IBInspectable và IBDesignable giúp chúng ta tiết kiệm rất nhiều thời gian trong việc tạo và chỉnh sửa layout trên ios, lập trình viên có thể dễ dàng chỉnh các thông số thuộc tính của component và sẽ nhìn thấy trực tiếp sự thay đổi đó.

4. 1 số ứng dụng IBInspectable và IBDesignable trong lập trình:

4.1 Tính khoảng cách giữa các component theo các màn hình khác nhau:

khi tạo layout sử dụng autolayout, chúng ta có thể tự động tính chiều cao, căn lề trái phải, nhưng không thể auto khoảng các giữa các component. Ví dụ trên màn hình chúng ta có 10 item thì khi tạo layout ta phải fix cứng khoảng cách giữa các 10 items này, dẫn đến trên các màn hình iphone kích thước khác nhau khoảng các giữa các item và chiều cao là không tương xứng. Để giải quyết việc này chúng ta có thể dùng IBInspectable và IBDesignable để set khoảng cách giữa các item theo từng kích thước màn hình. Chúng ta tạo file LayoutConstraint:

@IBInspectable
    var 📱3¨5_insh: CGFloat = 0 {
        didSet {
            if UIScreen.mainScreen().bounds.maxY == 480 {
                constant = 📱3¨5_insh
            }
        }
    }
    
    @IBInspectable
    var 📱4¨0_insh: CGFloat = 0 {
        didSet {
            if UIScreen.mainScreen().bounds.maxY == 568 {
                constant = 📱4¨0_insh
            }
        }
    }
    
    @IBInspectable
    var 📱4¨7_insh: CGFloat = 0 {
        didSet {
            if UIScreen.mainScreen().bounds.maxY == 667 {
                constant = 📱4¨7_insh
            }
        }
    }
    
    @IBInspectable
    var 📱5¨5_insh: CGFloat = 0 {
        didSet {
            if UIScreen.mainScreen().bounds.maxY == 736 {
                constant = 📱5¨5_insh
            }
        }
    }

Từ đó chúng ta có thể dễ dàng chỉnh khoảng cách các item tuỳ theo các màn hình mong muốn

4.2 Sửa lỗi font mất chữ “g” và “y” với 1 số font tiếng nhật:

Làm việc với tiếng nhật chắc mọi người đều quen 1 số font như "HiraKakuProN-W3", "HiraKakuProN-W6", "HiraginoSans-W3", "HiraginoSans-W6", 1 số font này hiển thị tiếng nhật rất đẹp nhưng oái oăm là với 2 ký tự "y" và "g" thì không như vậy nó làm label của chúng ta bị mất nét dưới 1 cách rất khó hiểu, tất nhiên nếu chúng ta chỉnh height của label cao hơn bình thường 1 chút thì chả có vấn đề gì để nói nhưng thử tưởng tượng xem bạn đang làm 1 cái cell autoheight theo chiều dài của text nhập vào thì lỗi này sẽ xảy ra.

Để fix lỗi này ta tạo 1 subclass của UILabel với 1 thuộc tính increaseHeight là IBInspectable

@IBDesignable class CTLabel: UILabel {
    @IBInspectable var increaseH: CGFloat = 0 {
        didSet {
            self.setNeedsDisplay()
        }
    }
    
    override func intrinsicContentSize() -> CGSize {
        var size = super.intrinsicContentSize()
        size.height += increaseH
        return size
    }
}

4.3 Lỗi tương tự với UIButton

Vì title của uibutton vẫn là title nên lỗi trên UILabel vẫn xảy ra tương tự. Cách fix cũng tương tự như với UILabel, chúng ta tạo 1 subclass của UIButton

@IBDesignable class CTButton: UIButton {
    @IBInspectable var increaseH: CGFloat = 0 {
        didSet {
            self.setNeedsDisplay()
        }
    }
    
    // layoutSubviews
    override func layoutSubviews() {
        super.layoutSubviews()
        
       self.titleLabel?.sizeToFit()
            if let titleLabel = self.titleLabel {
                
                var frame = titleLabel.frame
                frame.size.height += self.increaseH
                self.titleLabel?.frame = frame
            }
    }

5. Demo:

https://github.com/pqhuy87it/MonthlyReport/tree/master/IBDesignableAndIBInspectable


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí