如何在Swift中c 创建自定义控件件

How to build a custom (and “designable”) control in Swift - Think & Build
Enjoy my Book
Latest articlesiOS开发实战:使用Swift语言自定义Pull To Refresh控件
发表于 14:18|
来源AppCoda|
作者Gabriel Theodoropoulos
摘要:让简单应用出类拔萃的秘籍是开发小组所使用的个性化技艺,用在大多数开发人员不做处理的小细节处。本文作者展示了使Pull To Refresh控件改头换面的方法。
CSDN移动将持续为您优选移动开发的精华内容,共同探讨移动开发的技术热点话题,涵盖移动应用、开发工具、移动游戏及引擎、智能硬件、物联网等方方面面。如果您想投稿、参与内容翻译工作,或寻求近匠报道,请发送邮件至tangxy#csdn.net(请把#改成@)。&
全世界有非常多的应用程序。要开发出新的应用,并且能够吸引用户的注意力,使应用能够脱颖而出。毫无疑问,有人会说使简单应用出类拔萃的秘笈是开发小组(开发人员和设计人员)所使用的个性化技艺,用在大多数开发人员不做处理的小细节处。其中之一就是从本文题目中可见一斑的pull-to-refresh控件。通过本文我会展示使该控件改头换面的方法。
你知道,pull-to-refresh控件是活动指示器(经常带有短小的信息),数据加载过程中,会出现在表视图的顶部。此时的表视图还未完成刷新。实际上,pull-to-refresh控件与“Please,
wait…”信息提示类似,当用户等待获取和显示新的内容时出现。于此最知名的应用就是电子邮箱。向底部拖拽邮件视图,邮件列表会得到刷新。该控件自iOS
6.0引入,之后在不计其数的应用软件中频繁地被使用。
如果想要在应用中使用pull-to-refresh控件的话,就要查找如何去用的相关信息,也一定会找到,文章很好地诠释了你想知道的一切。而本文要说说pull-to-refresh控件的另外一面,那就是如何自定义一个pull-to-refresh控件。这样一来,你就能够在这个不起眼儿但比较重要的细节上添加不同的风格,给应用赋予不同的视角。
长话短说,接下来看看添加自定义内容和动画的技巧,来使用任何你想要添加的对象“取代”默认的pull-to-refresh控件。要注意,下面的内容是展示你要跟着做的步骤,实际的自定义内容完全由你自己决定,更确切地说,由你的想象力决定。开始吧,用不了多久,就能创建出自定义的pull-to-refresh控件了!
示例应用概览
下面的动画就是本文中自定义的pull-to-refresh控件:
可以看到,表视图里面有一些模拟数据。我们的目的不是真地要从服务器获取数据,而是关注刷新的过程。活动指示器是不会出现的,取而代之的是与刷新过程持续时长相同的“APPCODA”动画。
想要知道模拟刷新的动作什么时候结束到话,我只能告诉你这里使用了计时器(NSTimer)对象。四秒钟后,该对象会结束刷新动作,将自定义的pull-to-refresh控件隐藏起来。示例中的四秒钟是随机选取的时间间隔,这当然是为了在本文中演示自定义控件的方法。很多情况下数据刷新时间都比这要短(特别是有高速英特网连接的情况下)。因此,在真实的应用中不要为了给用户头脑中留下印记而使用计时器来显示自定义的pull-to-refresh控件。要知道,特别是如果应用很棒,被用户经常使用的情况下,用户会很多机会看到这个控件。
正如你所看到的,要开发一个极其简单的项目。但没有必要从头开始,和往常一样,可以先。这是在故事板(storyboard)中所作的界面设计,还有一个Interface
Builder文件,叫做RefreshContents.xib。在界面中我加入了自定义的内容,用来取代普通pull-to-refresh控件来显示的内容。实际上,该自定义控件包含了七个标签(UILabel)对象。在一起组成了“APPCODA”字样。还有一个自定义视图(UIView)作为这些标签的容器。所以必要对字体格式都做好了,正确设置了约束。随后要做的就是在视图控制器中加载这些控件,并用适当的方式处理它们。
所以,先下载初始项目,用Xcode打开它。
默认的Pull-To-Refresh控件
对示例应用要做的第一件事就是显示表视图中的模拟数据。下载的初始项目中已经包含了叫做tblDemo的IBOutlet属性,用来连接故事板中的表视图。因此需要编写表视图所需的代理(delegate)方法和数据源(datasource)方法。但是,这样做之前需要指定表视图中要显示的数据。在ViewController.swift文件中,在类内添加下列代码行:
var dataArray: Array&String& = ["One", "Two", "Three", "Four", "Five"]
现在,如下所示,通过添加UITableViewDelegate和UITableViewDataSource协议修改类的第一行:class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource然后要将ViewController的类实例作为表视图的代理和数据源:
override func viewDidLoad() {
tblDemo.delegate = self
tblDemo.dataSource = self
现在添加表视图的方法,用来显示模拟数据:
func numberOfSectionsInTableView(tableView: UITableView) -& Int {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -& Int {
return dataArray.count
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -& UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("idCell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel!.text = dataArray[indexPath.row]
return cell
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -& CGFloat {
return 60.0
好啦!这些都没有啥难度,运行应用后就会看到表视图显示“One, Two, …”。
来看看如何显示和使用默认情况下的pull-to-refresh控件吧。我们现在这种情况是ViewController或其他什么类的子类,总之不是UITable
ViewController的子类。pull-to-refresh控件必须作为表视图的子类添加进来(,作为UITableViewController的子类添加进来的做法)。首先在类的开始处声明refreshControl。
var refreshControl: UIRefreshControl!
别忘了,尽管refreshControl由一组特别的控件组成,但声明和使用的方法与其他属性和对象别无两样。所以上面的做法很正常。
首先在viewDidLoad方法中初始化refreshControl,然后将它添加到表视图当中。
override func viewDidLoad() {
refreshControl = UIRefreshControl()
tblDemo.addSubview(refreshControl)
再一次运行应用,当表视图被拖拽到底部的时候,你会发现旋转的图标出现了。但不要指望这个控件再隐藏回去,这个功能不是自动产生的。必须要明确地结束刷新动作,但这是稍后要做的事情。目前的亮点是刷新指示运行良好。
提示一下,这个带有刷新功能的控件,其背景色和控件颜色都可以修改。例如,下面的两行代码运行后的效果就是底色是红色,旋转图标是黄色。
override func viewDidLoad() {
refreshControl = UIRefreshControl()
refreshControl.backgroundColor = UIColor.redColor()
refreshControl.tintColor = UIColor.yellowColor()
tblDemo.addSubview(refreshControl)
自定义控件的内容
自定义pull-to-refresh控件背后的关键点是给控件本身添加自己想要的任何额外内容,所添加的内容将作为子视图。示例程序中所谓的额外内容就是RefreshContents.xib文件。更具体地说,Interface
Builder文件的内容是这个样子的:
如你所见,视图对象包含了依次七个标签。每个标签与“APPCODA”字母相对应。
接下来要做的事情非常简单:通过编程的方式将.xib文件的内容赋值给属性。更确切地说,将视图对象复制给UIView属性,所有标签都会被依次放到一个数组当中。这样做就可以把这些视图做成任何我们想要的动画效果。
现在深入到细节。首先,在类的开始处添加下列两行声明语句:
var customView: UIView!
var labelsArray: Array&UILabel& = []
有了上面新声明的两个属性,我们来创建一个新的自定义方法,用来加载.xib文件所有的内容:
func loadCustomRefreshContents() {
let refreshContents = NSBundle.mainBundle().loadNibNamed("RefreshContents", owner: self, options: nil)
我们会继续改进上面的自定义函数。下一步要做的是给customView分配上面代码加载的视图对象。注意,像上面的这种方法,从一个外部.xib文件中获取子视图,获得的是包含所有这些子视图的数组。在这里,数组只包含自定义的视图对象,也就是作为自定义视图子视图的那些标签,而不是.xib中自定义视图之外单独存在的视图对象。还要注意下面的几行代码,使自定义视图的框架与带有刷新功能旧有控件的框架要相吻合。
func loadCustomRefreshContents() {
customView = refreshContents[0] as! UIView
customView.frame = refreshControl.bounds
拖动表视图后刷新动作被触发,上面代码中的最后一行使自定义控件尺寸的变化与已知的约束相一致。
现在将所有的标签加载到labelsArray数组中。也许你已经注意到了,RefreshContents.xib文件中的每个标签都被分配了一个标号。从左侧开始,标号范围从1到7。我们将会利用这些标号单独访问每个标签。
func loadCustomRefreshContents() {
for var i=0; i&customView.subviews. ++i {
labelsArray.append(customView.viewWithTag(i + 1) as! UILabel)
最后,把自定义视图作为刷新控件的子视图添加进来:
func loadCustomRefreshContents() {
refreshControl.addSubview(customView)
搞定!还有一件事就是调用上面的函数,当然是在viewDidLoad方法中调用:
override func viewDidLoad() {
loadCustomRefreshContents()
最后要做一些重要的且必须要做的修改。在viewDidLoad方法中,将刷新控件的背景色和控件颜色设置成透明色。下面是修改后最终的代码。
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tblDemo.delegate = self
tblDemo.dataSource = self
refreshControl = UIRefreshControl()
refreshControl.backgroundColor = UIColor.clearColor()
refreshControl.tintColor = UIColor.clearColor()
tblDemo.addSubview(refreshControl)
loadCustomRefreshContents()
测试一下应用,拉动刷新时,可以看到带有标签的自定义视图取代了默认情况下的图标。当然还没有动画效果,下面我们就要实现动画效果。
初始化自定义动画
这就是最终要实现的动画效果:
如果仔细观察,你会发现整个动画过程由两个子过程组成:
从第一个开始,每个标签略微旋转(45度),与此同时,标签文本的颜色发生变化。下一个标签开始旋转前,当前旋转的标签状态复原。所有标签旋转过程完成后恢复原状,然后一起按比例放大,再按比例缩小。
我们把每个部分的动画作为单独的自定义函数来实现,尽量保持简单易懂。动手之前,要声明一些随后要用到的新属性。
var isAnimating = false
var currentColorIndex = 0
var currentLabelIndex = 0
下面对每个属性做简单的介绍:
isAnimating标志动画过程是否发生。使用该属性用来告知是否能够开始一个新的动画过程(很明显,当一个动画开始后,我们不希望开始第二个动画)。currentColorIndex属性会被用在实现的另一个自定义函数中。该函数拥有一个表示颜色(控件文本的颜色)的数组,这个属性表示下一个会被用到的标签文本颜色。currentLabelIndex属性代表动画效果的第一个子过程里标签的索引。这样不仅可以确定下一个要旋转和着色的标签,还可以确定动画效果的第二个子过程(按比例放大)何时应该开始。
现在来处理动画效果的第一部分。使用一个叫做animateRefreshStep1()的函数完全实现了该功能:
func animateRefreshStep1() {
isAnimating = true
UIView.animateWithDuration(0.1, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -& Void in
self.labelsArray[self.currentLabelIndex].transform = CGAffineTransformMakeRotation(CGFloat(M_PI_4))
self.labelsArray[self.currentLabelIndex].textColor = self.getNextColor()
}, completion: { (finished) -& Void in
UIView.animateWithDuration(0.05, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -& Void in
self.labelsArray[self.currentLabelIndex].transform = CGAffineTransformIdentity
self.labelsArray[self.currentLabelIndex].textColor = UIColor.blackColor()
}, completion: { (finished) -& Void in
++self.currentLabelIndex
if self.currentLabelIndex & self.labelsArray.count {
self.animateRefreshStep1()
self.animateRefreshStep2()
我们来说说上面这段代码的核心部分。一开始,isAnimating标志被置为true,因此认定没有要开始的动画过程。随后会看到判断过程。接下来你会注意到,有两个产生动画效果的代码块。第二个代码块在第一个代码块执行结束的时候开始。其中的原因有两点:
我们在第一个代码块中对当前标签执行旋转和更改标签文本颜色的操作(参见关于currentLabelIndex属性的描述)。动画效果的子过程结束时,想要将标签的状态复原,这个过程要优雅平缓,而不能显得突兀不自然。很明显,第二段起到动画效果的代码块起了作用。
在产生动画效果的代码块内,completion handler(完成处理程序)检查currentLabelIndex属性值是否有效。如果有效,就再次重复调用相同的函数。这样下一个标签就产生了动画效果。另外,所有标签都执行完动画过程后,就调用动画过程的第二个子过程的自定义方法(animateRefreshStep2())。
你肯定注意到了getNextColor()函数(在第一个动画效果代码块中)。之前说过,通过这个函数会得到当前带有动画效果控件的文本颜色。一会儿再看这部分。
我们现在解决动画效果第二个子过程,实现animateRefreshStep2()函数:
func animateRefreshStep2() {
UIView.animateWithDuration(0.35, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -& Void in
self.labelsArray[0].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[1].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[2].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[3].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[4].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[5].transform = CGAffineTransformMakeScale(1.5, 1.5)
self.labelsArray[6].transform = CGAffineTransformMakeScale(1.5, 1.5)
}, completion: { (finished) -& Void in
UIView.animateWithDuration(0.25, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { () -& Void in
self.labelsArray[0].transform = CGAffineTransformIdentity
self.labelsArray[1].transform = CGAffineTransformIdentity
self.labelsArray[2].transform = CGAffineTransformIdentity
self.labelsArray[3].transform = CGAffineTransformIdentity
self.labelsArray[4].transform = CGAffineTransformIdentity
self.labelsArray[5].transform = CGAffineTransformIdentity
self.labelsArray[6].transform = CGAffineTransformIdentity
}, completion: { (finished) -& Void in
if self.refreshControl.refreshing {
self.currentLabelIndex = 0
self.animateRefreshStep1()
self.isAnimating = false
self.currentLabelIndex = 0
for var i=0; i&self.labelsArray. ++i {
self.labelsArray[i].textColor = UIColor.blackColor()
self.labelsArray[i].transform = CGAffineTransformIdentity
我们使用了两个产生动画效果的代码块。在第一个代码块中,等比例放大了所有标签。请注意,这里无法使用循环结构完成任务(例如:for语句)。循环结构的执行过程与动画过程无关,这样在所有标签等比例放大执行完毕前循环结构早就执行结束了。
在程序执行“完成处理”部分,所有标签都完成了初始化处理。因此,这些标签再一次回到了初始状态。动画效果代码块内部的“完成处理”部分使用了if语句,刷新过程还在进行中,我们就做好了重新开始整个动画的准备。通过给currentLabelIndex属性简单地设置初始值(0)就能完成这个任务,调用第一个自定义方法来执行动画。下一步我们再来处理刷新结束后的事情。但是如果刷新结束了,可以通过修改isAnimating标志表示不再执行任何动画,而通过给所有的属性(和视图)赋初值来参与动画过程。这样一来,动画过程要在下一次拉动表视图的时候重新开始。
问题出来了,自定义动画应该在哪里开始呢?如果你仔细观察过上面的动画,就会发现每次表视图拖动完成,动画就开始一次。从编程的角度说,表视图是滚动视图(scroll
view)的子类,我们所关心的代理方法是scrollViewDidEndDecelerating(_:)。每次表视图滚动停止时,该方法都会被调用。这个方法起初会检查刷新过程是否在进行。就我们这里的情况而言,就是要检查isAnimating标志的值。如果没有动画在进行中,就要调用之前实现的第一个函数来做初始化。就像下面这样的代码:
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if refreshControl.refreshing {
if !isAnimating {
animateRefreshStep1()
值得注意的是,上述滚动视图代理方法的使用并非强制性的,这取决于自定义pull-to-refresh控件的代码逻辑。也可以考虑其他代理方法,比如scrollViewDidScroll(_:)。
还落一部分没有说,那就是getNextColor()函数的实现:
func getNextColor() -& UIColor {
var colorsArray: Array&UIColor& = [UIColor.magentaColor(), UIColor.brownColor(), UIColor.yellowColor(), UIColor.redColor(), UIColor.greenColor(), UIColor.blueColor(), UIColor.orangeColor()]
if currentColorIndex == colorsArray.count {
currentColorIndex = 0
let returnColor = colorsArray[currentColorIndex]
++currentColorIndex
return returnColor
这非常简单!首先将一些预定义的颜色(顺序完全随机)放到数组当中。然后确认currentColorIndex属性的值。如果不具有有效的值,就要赋初值(0)。使用currentColorIndex表示颜色,然后累加其值,因此,再次getNextColor()的时候后就不会得到相同的颜色。函数最后将选定的颜色返回。
现在可以再次尝试运行应用。拖动后刷新,会看到动画效果。当然,刷新控件并不会消失。这一部分还没有实现。随便怎么去用,动画的任何一部分都可以修改。
自定义动画之外的事情
为pull-to-refresh控件创建自定义动画很有趣,但不要忘了,用户刷新不是光为了观看控件有多好看,用户需要获得新的内容。这也是自定义pull-to-refresh控件时你的主旨思想。因此,完成了上面这些内容以后,下一步就要实现真正获取数据的过程。
显然,本文并未涉及获取任何数据的操作,也没有对表视图更新内容的操作。但是,这些都无法阻止我们实施之前所描述的逻辑。所以要继续完成其余的任务,那就是创建一个新的自定义函数,名为doSomething()(蛮滑稽的名字,是不是觉得是个啥也干不了的函数)。我们要在该函数中初始化一个计时器(NSTimer)对象。4秒钟的时间间隔后,就会发出刷新过程结束的信号。在真实的应用软件中,没有必要这样做。当获取数据的过程结束时,刷新过程也就结束了。
首先,回到类定义的开始,(最后一次)声明一个对象:
var timer: NSTimer!
现在来“do something”:
func doSomething() {
timer = NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: "endOfWork", userInfo: nil, repeats: true)
4秒钟已经足够了,这样可以不止一次地看到动画效果。在上面的方法中可以看到仅有的一行代码,预设的时间间隔过后endOfWord()就会被调用。这样就会停止刷新过程,使计时器失效:
func endOfWork() {
refreshControl.endRefreshing()
timer.invalidate()
timer = nil
这个时候我们几乎大功告成了。唯一要做的就是调用doSomething()函数,要在动画过程开始前调用。因此需要再次修改滚动视图的代理方法:
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if refreshControl.refreshing {
if !isAnimating {
doSomething()
animateRefreshStep1()
示例程序做好了,这回再体验一把!
你也看到了,自定义一个pull-to-refresh控件一点儿都不难。只是把好的创意用图形表现出来,仅此而已。正如我在最后的部分所讲的,主旨在于真实数据的获取过程,而不是炫耀所创建的可视化效果。还要注意的是数据一旦更新完毕,就不要惦记着延长时间而阻止刷新控件隐藏。这样做会导致你不愿意看到的用户体验,很糟糕。如果应用软件对用户非常有帮助的话,就会有很多机会让用户领略软件的自定义效果,所以不要试图更新完毕后还阻止刷新控件隐藏。文中示例程序所自定义的内容比较简单,但足以说明问题。你知道,这是编程方面的问题,可以接受很多自定义的内容和即兴创作。当然,最终的应用软件甚至可能会彼此各不相同。自定义的pull-to-refresh控件要与不同的应用相匹配。总之,本文就此告一段落,真心希望能对你有所帮助。能够帮助你愉快地开发出自定义的pull-to-refresh控件!
作为参考,可以从下载整个项目。
(翻译/白云鹏 友情审校/张挥戈)
原文链接:
作者简介:Gabriel Theodoropoulos:拥有20年的编程经验,2010年下半年以来,一直专注于iOS开发,长期使用多种语言在不同平台实现软件架构解决方案。
译者简介:白云鹏,移动应用开发者,个人博客:
将于10月15-16日在北京新云南皇冠假日酒店召开。大会特设五大技术专场:平台与技术iOS、平台与技术Android、产品与设计、游戏开发、企业移动化、虚拟现实专场。此外,大会更是首次举办国内极具权威影响力的IoT技术峰会,特设硬件开发技术与嵌入式开发两大专场。大会将聚集国内最具实力的产品技术团队,与开发者一道进行最前沿的探讨与交流。&
第一时间掌握最新移动开发相关信息和技术,请关注mobilehub公众微信号(ID: mobilehub)。
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章  &今天还是重复昨天做的事情--敲代码,但唯一的不同就是所学的知识不同了,我们又进一步往深得层次学习了,感觉越来越有意思了,虽然临近结束了看着大家积极性越来越低了,但是我知道我不能这样,我要比别人付出的更多,更加的踏实才行,因为我知道我的基础不如别人,目标和动力也和他们不同,看着大家有的说是只要找到工作就好,还有的说只要每个月够花就好,担着真的是大家来这里学习的最终目的吗,如果是这样,真的还不如随便找个工作将就一下,也比这个整天做到这好多了,还交了那么贵得费用,所以何必呢,既然选择了这条路,既然当初抱着那么的憧憬,那么大的希望来到这里,走上这条路,那么我们就要坚定不移的走下去,美好的明天只有自己可以创造,也只有自己能够为自己负责,世界上没有卖后悔药,如果等到结局已经落定再去后悔,哪还有什么用,所以在这里望毅然选择程序道路的朋友们(不管是iOS,.Net,JAVA....)还是什么,都不要轻言放弃,要学会对自己负责,对关心在乎你的人负责,现在我想对自己和关心我的人说:加油加油!!!!!!
   今天就来为大家讲解下我们今天所学习的知识点,以及我自学的部分知识,希望可以和大家共同进步,共同努力,下面就来附上代码供大家参考,学习提意见等:
   一、函数的学习
  1.函数结构
   在Swift语言中,函数的基本结构是这样的,具体结构如下:
   func 函数名(参数列表)-&(返回值类型) {
   & & & & & & & & & & & &执行的代码块
& & & & &} 
   2.函数的基本示例
func sayHello(name: String) -& (String) {
return "Hello" + name
func sayByeBye(name:String, name1: String) -& (String) {
return "WoJiao " + name + name1
   以上函数名为sayHello (name:String, name1:String)对应的是参数列表, (String)指的是函数的返回值类型,大括号内部的便是函数要执行的代码块了,相信大家看到后会对函数有个最最初步的了解了吧,下面再为大家附上今天所作的小小练习了
var letter = "aeibcd1234"
func getNumbers (letter: String) -& (Int, Int, Int) {
var count : Int = 0
var count1 : Int = 0
var count2 : Int = 0
for oneChar in letter {
var str = String(oneChar).lowercaseString
switch oneChar {
case "a", "i", "b":
case "e", "c", "d":
return (count, count1, count2)
getNumbers(letter)      
   首先需要定义字符串,(很明显这些都和OC及UI中的不同)var letter = "aeibcd1234", 接下来定义三个整形的数用来计数,相信下面的switch,case大家都可以看懂的吧,这就是简单地分支结构了,我通过这个来判断内部有多少个'a','i','b'和'e','c','d'以及多少个数字了通过每进一次count(count1,count2)自加来表示,同时,在说明下,我注释掉的那一句是用来进行大小写转换的,如果所定义的字符串内部有字符串的话我们可以通过这个方法让其变为小写,以便我们后面对其进行计数处理,好了这个简单地函数就到这里了,如果有哪里不对了或者哪里不懂了都可以提出来哦,嘿嘿。
&  3.外部参数的使用
   有些时候我们需要引入一个外部参数来实现我们的需求,但是需要注意的是,尽管有时间使用外部参数会使我们所编写的程序看起来很炫,但是外部参数是不可以在函数内部进行使用的,就比如我们要平常所写的就是类似下面的做法,如图所示:
但是有时间你会发现我们在手机中碰到的或者所见源码中会有和上面不一样的实例,就比如:
   接下来下伙伴门肯定会有疑问吧(知道的要低调哈)那么我就来慢慢为大家解释下把,其实实现起来并不是太难,只需要一行代码就可以搞定了,总共方案有三种吧,下面就一一为大家附上代码供大家参考吧!
&   & 现附上源码作为对比
func personInfou( personName: String, sex: String,
age:String) -& String {
return personName + " " + sex + age
   方案一:
func personInfou(name personName: String, sex sex: String, age age:String) -& String {
return personName + " " + sex + age
&就是在每个参数前加上一个外部参数名,想必大家经过对比都可以看出来的。
   方案二:
func personInfou(#personName: String, #sex: String, #age:String) -& String {
return personName + " " + sex + age
   方案三:
func personInfou(name personName: String, #sex: String, age:String = "25") -& String {
return personName + " " + sex + age
以上就是实现的三种方法,是不是很神奇呢,说实在的,以前我也不知道可以这样写,不过现在算是知道了,可以说是get了一个新技能。
   4.函数的嵌套
   不过说真的,函数的嵌套和C语言的函数回调十分相似,不过由于在Swift中不存在.h文件和.m文件之分,所以为了保证文件源码的安全性,开发者做出了一下的调整,那就是将嵌套的函数体写在同一个函数内部,也可以说是充当了代码块来实现的,下面就为大家展示下Swift中的函数嵌套:
//函数类型作为返回值
// 隐藏 不希望别人看到
func changeValue (isOne: Bool) -& Int -& Int {
func plusOne(number: Int) -& Int {
return number + 1;
func plusTwo(number: Int) -& Int {
return number - 1;
return isOne ? plusOne : plusTwo
var cc : Int -& Int = changeValue(true)
   在以上代码中,参数列表为(isOne:Bool)他是一个Bool类型的,通过下面的return isOne ? plusOne : plusTwo来进行函数的回调,如果传参为真,则开始回调一地个函数,反之回调第二个, 在下面最后一行进行函数的调用,var cc : Int -& Int = changeValue(true)传入一个true时通过return返回一个函数体,即为plusOne然后在对函数cc加以调用,传入参数20,来执行函数,这便是函数的简单嵌套,至于复杂的本博客将不断更新,敬请期待。
   二、Swift中闭包的简单学习
&&  1.闭包的简单结构
   & & & & (参数列表)-&返回值 in
      闭包的实现
   其实Swift中闭包跟OC中的block类似,下面就为大家附上闭包的简单应用,不要错过哦,逐层加深哦,嘿嘿。
  (1)第一种实现方式   &
var names = ["Qiaoming", "kan", "taobao"]
var sortedNames1: () = sort(&names, {
(stringA: String, stringB: String) -&Bool in
return stringA & stringB
   &第一种其实没有什么好说的,只是套用结构而已,不过下面博友门就要看清楚了,是紧密联系的,一一演变而来的。
   &(2)第二种实现方式   
var sortedNames2:() = sort(&names, {
(stringA, stringB) -& Bool in
return stringA & stringB
在这里去掉类型让系统去自行推断出stringA,stringB的类型,相比上一种是不是感动有少许的简单快捷呢,不过不要大意哈,下面的终极版马上就要来了。
   & (3)第三种实现方式   
var sortedName3: () =
sort(&names,{
return $0 & $1
是不是看上去更简单了,这里用$0来表示第一个参数 $1来表示第二个参数。
   (4)第四种实现方式
var sortedName4:() = sort(&names, &)
这便是第四种的实现方式,慢慢的看着似乎脱离了block,但是只用一句话就可以实现我们前面的需求了(就是对一个数组进行排序),需要说明的是这些都是又限制的,在Swift语言中,由于数组中存放的必须是同一种数据类型,所以参数类型可以省略不写,还有每个方法中的names只是为了用来验证是不是满足我们的需求,其实可以完全不用写的,当然是在我们写的比较多的时候。
    三、类 跟 结构体
    1.相同点
    (1)都可以定义属性&(2)都可以定义方法 (3)他们都可以定义便利构造器(初始化方法) (4)都可以遵循协议 (5)都可以被扩展
    2.不同点
     (1)类 可以被继承, 而结构体就不能&(2)类 可以被类型推断 &(3)类 可以通过析构(即dealloc)释放内存 &(4)类 它是引用类型 结构体是值类型
    以上就是我们今天所学习的只是点了,虽然不多,但是确实是新知识,感觉也挺有用的,毕竟是刚出来的,总有一天会派上用处的,所以还是要争取把它学好。下面的是附赠品哦(自己通过课余时间来学习了用Swift如何创建简单控件),下面就为大家附上代码,供大家参考研究:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -& Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
// Override point for customization after application launch.
self.window!.backgroundColor = UIColor.whiteColor()
self.window!.makeKeyAndVisible()
//lebel的创建
let textLabel = UILabel(frame: CGRectMake(self.window!.frame.size.width / 2 - 150, 200, 300, 100))
textLabel.text = ""
textLabel.backgroundColor = UIColor(red:0.5,green:0.5,blue:0.5,alpha:1.0)
textLabel.textColor = UIColor(red:0.5,green:0.2,blue:0.6,alpha:1.0)
textLabel.textAlignment = NSTextAlignment.Center
self.window!.addSubview(textLabel)
//UIImageView的创建及添加图片
let imageView = UIImageView(frame: CGRectMake(self.window!.frame.size.width / 2 - 150, 50, 300, 100))
imageView.backgroundColor = UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 1.0)
let image = UIImage(named: "1.png")
imageView.image = image
self.window!.addSubview(imageView)
return true
   &相信大家通过看这些肯定会看出来和UI中的创建方法完全不同,并且会感觉到不太上手,不过确实是这样的,当我这样写的时候自己都感觉不太对,也有点不可思议,竟然是这样写的,不过最终还是出来了,感到非常高兴,希望这些可以帮到大家,如果对简单控件的创建还有什么疑问的话,欢迎前来与我商讨,顺便说下,这个是在空模板中写的,语言不再试以前选择的OC了,而要改写为Swift了,哈哈。
   & 好了,今天就先写到这里了,感觉虽然东西不是很多,但还是需要慢慢消化的,毕竟是刚接触的,最后还是要重复我刚开始说的话,选择了这条路的亲朋好友们,还有你你你, 我们共同努力,一起揭开属于我们美好的明天,坚持就是胜利,更何况几个月已经走过来了,剩下的难道我们还会怕吗,加油加油喽,come on!&
阅读(...) 评论()

我要回帖

更多关于 vb2015创建自定义控件 的文章

 

随机推荐