Fork me on GitHub

iOS tutorial 8:使用IBInspectable 和 IBDesignable定制UI

例子代码:https://github.com/andyRon/LearniOSByProject/tree/master/77

理解IBInspectable 和 IBDesignable

简单地说,IBInspectable 就是允许开发者在IB的属性检查器中添加额外的选项。IBDesignable 能够让 IBInspectable 添加的额外选项产生的变化在IB中实时显示。以Button的圆角为例说明。

  • 正常情况下,Button的圆角需要代码:
    1
    2
    button.layer.cornerRadius = 10.0
    button.layer.masksToBounds = true

或者直接在IB的Identity检查器user defined runtime attributes中添加:

注意到,这种修改不是实时,在IB中Button还是直角,只有运行后才是圆角。

  • IBInspectable的方式。定义个继承至UIButton的类。
    1
    2
    3
    4
    5
    6
    7
    8
    class RoundedCornerButton: UIButton {
    @IBInspectable var cornerRadius: CGFloat = 0.0 {
    didSet {
    layer.cornerRadius = cornerRadius
    layer.masksToBounds = cornerRadius > 0
    }
    }
    }

然后把button的class属性修改成RoundedCornerButton:

发现这个button的属性检查器中多了Corner Radius

注意: cornerRadius属性变成了Corner RadiusRoundedCornerButton类变成了 Rounded Corner Button,这是Xcode自动转变的,开发者只需要依照swift的命名规范就可以了(类名是大写开头的驼峰命名规则,属性名是小写开头的驼峰命名规则)

cornerRadius的类型是CGFloat,在属性检查器中就对应数字的选择。当然不是所有类型都可以添加属性检查器中的,IBInspectable支持如下类型:

1
2
3
4
5
6
7
8
9
10
Int
CGFloat
Double
String
Bool
CGPoint
CGSize
CGRect
UIColor
UIImage

如果在类RoundedCornerButton前添加@IBDesignable,那在属性检查器中自定义的属性变化就可以在IB中实时显示了。

1
2
3
4
5
6
7
8
@IBDesignable class RoundedCornerButton: UIButton {
@IBInspectable var cornerRadius: CGFloat = 0.0 {
didSet {
layer.cornerRadius = cornerRadius
layer.masksToBounds = cornerRadius > 0
}
}
}

创建Fancy Button

创建Fancy Button来更加深入的了解IBInspectable 和 IBDesignable

  • 创建新项目FancyButton
  • 下载图标,也可以随意图标,拖进asset catalog
  • 新建类FancyButton,继承至UIButton
  • 圆角,边宽,边的颜色。 更新FancyButton
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @IBDesignable
    class FancyButton: UIButton {
    @IBInspectable var cornerRadius: CGFloat = 0.0 {
    didSet {
    layer.cornerRadius = cornerRadius
    layer.masksToBounds = cornerRadius > 0
    }
    }
    @IBInspectable var borderWidth: CGFloat = 0.0 {
    didSet {
    layer.borderWidth = borderWidth
    }
    }
    @IBInspectable var borderColor: UIColor = .black {
    didSet {
    layer.borderColor = borderColor.cgColor
    }
    }
    }

  • Title
    FancyButton继续添加属性:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @IBInspectable var titleLeftPadding: CGFloat = 0.0 {
    didSet {
    titleEdgeInsets.left = titleLeftPadding
    }
    }
    @IBInspectable var titleRightPadding: CGFloat = 0.0 {
    didSet {
    titleEdgeInsets.right = titleRightPadding
    }
    }
    @IBInspectable var titleTopPadding: CGFloat = 0.0 {
    didSet {
    titleEdgeInsets.top = titleTopPadding
    }
    }
    @IBInspectable var titleBottomPadding: CGFloat = 0.0 {
    didSet {
    titleEdgeInsets.bottom = titleBottomPadding
    }
    }

  • 通过圆角可创建圆形button

  • Image Padding
    添加图片边距的属性:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @IBInspectable var imageLeftPadding: CGFloat = 0.0 {
    didSet {
    imageEdgeInsets.left = imageLeftPadding
    }
    }
    @IBInspectable var imageRightPadding: CGFloat = 0.0 {
    didSet {
    imageEdgeInsets.right = imageRightPadding
    }
    }
    @IBInspectable var imageTopPadding: CGFloat = 0.0 {
    didSet {
    imageEdgeInsets.top = imageTopPadding
    }
    }

    @IBInspectable var imageBottomPadding: CGFloat = 0.0 {
    didSet {
    imageEdgeInsets.bottom = imageBottomPadding
    }
    }

  • 图片靠右对齐
    根据下图关系,应有imageEdgeInsets.left = self.bounds.width - imageView.bounds.width - imageRightPadding

FancyButton中添加如下代码:

1
2
3
4
5
6
7
8
9
@IBInspectable var enableImageRightAligned: Bool = false

override func layoutSubviews() {
super.layoutSubviews()

if enableImageRightAligned, let imageView = imageView {
imageEdgeInsets.left = self.bounds.width - imageView.bounds.width - imageRightPadding
}
}

+ `enableImageRightAligned`属性又来自动计算 `imageEdgeInsets.left`

  • 颜色渐变
    添加三个@IBInspectable属性,并更新layoutSubviews:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @IBInspectable var enableGradientBackground: Bool = false
    @IBInspectable var gradientColor1: UIColor = UIColor.black
    @IBInspectable var gradientColor2: UIColor = UIColor.white

    override func layoutSubviews() {
    super.layoutSubviews()

    if enableImageRightAligned, let imageView = imageView {
    imageEdgeInsets.left = self.bounds.width - imageView.bounds.width - imageRightPadding
    }

    if enableGradientBackground {
    let gradientLayer = CAGradientLayer()
    gradientLayer.frame = self.bounds
    gradientLayer.colors = [gradientColor1.cgColor, gradientColor2.cgColor]
    gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
    self.layer.insertSublayer(gradientLayer, at: 0)
    }
    }

渐变色需要运行后才能看到

参考:appcode网站的书《Intermediate iOS Programming with Swift》 的Chapter 36

坚持原创技术分享,您的支持将鼓励我继续创作!