在Xcode6中使用IBDesignable创建自定义控件(翻译)

英文原文地址

在 Xcode 的旧版本中,试图创建一个自定义控件,并不是很容易,因为在IB中,并不能实时预览到你的设计成果,只能在模拟器中测试。对于设计一个单一组件,可能需要花费大量时间。

Xcode6 的发布,苹果为开发者构建自定义控件推出了新功能IBDesignableIBInspectable,允许在IB中实时预览设计成果。很明显,这会给实际开发提升很高效率。

在本教程中,将介绍IBDesignable IBInspectable,以及展示如何利用这个新功能。除过创建demo示例没有更好地方式来阐述这一新特性,因此,创建一个"Rainbow"自定义界面。


效果图

IBDesignable和IBInspectable

使用IBDesignable和IBInspectable,开发者创建界面(或视图)可以实时呈现在IB中。一般来说,为了使用这个新特性,你需要做的是创建一个UIView或者UIControl的子类,然后在定义类的前面加上@IBDesignable关键字。如果是OC,使用IB_DESIGNABLE宏。下面是Swift示例代码:

@IBDesignable
class Rainbow: UIView {
}

在Xcode旧版本中,你可以在IB中编辑User Defined Runtime Attributes来改变一个对象的属性(例如:layer.cornerRadius),问题是你需要确切知道属性名。IBInspectable只需要一步,对一个可视化类的属性前面加上IBInspectable关键字前缀,该属性会在暴露在IB中,这就是一个更改属性值更简单的方法。


IB属性

你如果使用Swift开发app,你需要做的只是在你选择的属性前面加上@IBInspectable关键字,下面是个示例代码片段:

@IBInspectable var firstColor: UIColor = UIColor.blackColor() {
   // 值改变时更新UI
}

创建Xcode项目

创建一个新的Xcode项目,选择Single View Application模板,起名为RainbowDemo,在此项目中,将使用Swift语言,因此,创建项目时不要忘记勾选。

完成后,选择Main.storyboard文件,设置View Controller的根视图View的背景颜色Hex Color值为38334C(或者任何你想要的颜色)。然后从对象库中拖一个View放进View Controller,设置它的大小Width为600,Height为434,然后把它放在根视图的中心,设置新视图View和根视图相同背景颜色。

提示:如果想改变RGB颜色值,只需打开调色板和切换到滑块标签来改变RGB值


设置背景颜色

在Xcode6中,为了适配各个iOS设备,你必须为视图View配置自动布局约束。对于简单的约束,你可以在自动布局菜单单击Issues选项,选择Add Missing Contraints,Xcode将自动为View添加布局约束。


添加约束

创建自定义View类

现在,你已经在storyboard中创建了一个View,是时候创建自定义View类了。使用Cocoa Touch Class文件模板,创建自定义类文件,继承自UIView,起名为"Rainbow"。


创建自定义View类

在自定义类中插入以下代码:

import UIKit

class Rainbow: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

如前所述,这个可视化类是UIView的子类,让自定义类实时呈现,需要override上述两个方法。然后,打开辅助编辑器,更改新拖的View的自定义类为Rainbow类。



实现IBDesignable控制

为了实现实时预览,在自定义类前面加一个前缀@IBDesignable关键字

@IBDesignable 
class Rainbow: UIView {
    ...
}

这个关键字确实简单,但是这简单地关键字将使你的开发更加容易。接下来,添加一些设置颜色的属性。在Rainbow类中插入以下代码:

@IBInspectable var firstColor: UIColor = UIColor(red: (37.0/255.0), green: (252.0/255), blue: (244.0/255.0), alpha: 1.0)
@IBInspectable var secondColor: UIColor = UIColor(red: (171.0/255.0), green: (250.0/255), blue: (81.0/255.0), alpha: 1.0)
@IBInspectable var thirdColor: UIColor = UIColor(red: (238.0/255.0), green: (32.0/255), blue: (53.0/255.0), alpha: 1.0)

在这里,我们预先定义每个属性一个默认颜色,每次用户更改它们的值时会重绘视图。更重要的是,我们为每个属性加了一个@IBInspectable关键字前缀,现在去IB的属性检查器,你可以直观地发现这些属性:


IB中的属性

很酷,对吧?IBInspectable通过指示属性,你可以使用颜色选择器可视化地编辑它们。

在Rainbow类中,为了在屏幕上画一个圆,插入以下代码:

func addOval(lineWidth: CGFloat, path: CGPathRef, strokeStart: CGFloat, strokeEnd: CGFloat, strokeColor: UIColor, fillColor: UIColor, shadowRadius: CGFloat, shadowOpacity: Float, shadowOffset: CGSize) {

   let arc = CAShapeLayer()
   arc.lineWidth = lineWidth
   arc.path = path
   arc.strokeStart = strokeStart
   arc.strokeEnd = strokeEnd
   arc.strokeColor = strokeColor.CGColor
   arc.fillColor = fillColor.CGColor
   arc.shadowRadius = shadowRadius
   arc.shadowOpacity = shadowOpacity
   arc.shadowOffset = shadowOffset
   layer.addSublayer(arc)
}

为了保证代码的简洁和可读性,我们定义了依据方法调用者传入参数来绘制一个完整的圆或者半圆的公共方法。利用CAShapeLayer类可以很简单的画一个圆或圆弧。你可以使用strokeStart和strokeEnd属性控制渲染的开始和结束。通过改变strokeEnd的值在0.0到1.0之间,你可以绘制一个完整或者部分的圆。其余的属性是只是用于设置渲染颜色,阴影颜色等,在CAShaperLayer官方文档中可以查看更详细的所有可用属性。

接下来,添加以下方法:

override func drawRect(rect: CGRect) {
    // 添加圆弧
    addCircle(80, capRadius: 20, color: firstColor)
    addCircle(150, capRadius: 20, color: secondColor)
    addCircle(215, capRadius: 20, color: thirdColor)
}

func addCircle(arcRadius: CGFloat, capRadius: CGFloat, color: UIColor) {
    let x = CGRectGetMidX(bounds)
    let y = CGRectGetMidY(bounds)

    // 底部圆弧
    let pathBottom = UIBezierPath(ovalInRect: CGRectMake((x - (arcRadius/2)),
        (y - (arcRadius/2)), arcRadius, arcRadius)).CGPath
    addOval(20.0, path: pathBottom, strokeStart: 0, strokeEnd: 0.5,
        strokeColor: color, fillColor: UIColor.clearColor(),
        shadowRadius: 0, shadowOpacity: 0, shadowOffset: CGSizeZero)

    // 中间圆弧
    let pathMiddle = UIBezierPath(ovalInRect: CGRectMake((x - (capRadius/2)) - (arcRadius/2),
        (y - (capRadius/2)), capRadius, capRadius)).CGPath
    addOval(0.0, path: pathMiddle, strokeStart: 0, strokeEnd: 1.0,
        strokeColor: color, fillColor: color,
        shadowRadius: 5.0, shadowOpacity: 0.5, shadowOffset: CGSizeZero)

    // 顶部圆弧
    let pathTop = UIBezierPath(ovalInRect: CGRectMake((x - (arcRadius/2)),
        (y - (arcRadius/2)), arcRadius, arcRadius)).CGPath
    addOval(20.0, path: pathTop, strokeStart: 0.5, strokeEnd: 1.0,
        strokeColor: color, fillColor: UIColor.clearColor(),
        shadowRadius: 0, shadowOpacity: 0, shadowOffset: CGSizeZero)
}

drawRect:方法默认什么也不做,为了在自定义View中画圆,我们override此方法来实现自己的绘制代码。addCircle:方法有三个参数:arcRadius,capRadius和color。arcRadius是圆弧的半径,capRadius是圆弧边缘半径。

addCircle:方法利用UIBezierPath画圆弧的简单工作原理:

  1. 首先,在底部画了个半圆弧
  2. 接下来,在圆弧边缘画了一个完整的小圆
  3. 最后,画了另一半圆弧

drawRect:方法中,我们调用了addCircle:方法三次,传入的参数指定圆弧该怎样画:


画圆弧原理

利用IBInspectable属性,你可以在IB中自由改变每个圆弧的颜色,而不需要写代码:


显然,你可以进一步利用@IBInspectable暴露arcRadius属性,便可以在IB中修改绘制圆弧半径。


修改半径

总结

通过本教程后,你现在了解了在Xcode6中如何利用IBDesignable和IBInspectable实时预览界面。利用这个新特性,你可以更高效创建自定义组件。

RainbowDemo地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • 曾经想实现自定义的View,可以想系统自带那样拥有属性,并且实时渲染,动态更新内容,现在在Xcode6终于让你可以...
    Oneruofeng阅读 2,416评论 0 5
  • George Orwell. 《1984》DAY 7/20 Part2 Chapter1-2 这两个章节主要写了W...
    Jenner大江阅读 170评论 0 0
  • 社交,对绝大多数人来说,时时刻刻都在发生,但是对社交的重视和维护,并不见得人人都有重视。 小学,初...
    桃拾壹阅读 173评论 0 0
  • 证书有效性,一般要检查三点: 验证证书是否是否在有效期内?检查证书上有签发起始时间和过期时间 思考:如何保证取到的...
    Laok17阅读 5,823评论 0 0