用户界面控件是所有应用程序重要的组成部分之一。它们以图形组件的方式呈现给用户,用户可以通过它们与应用程序进行交互。苹果提供了一套控件, 例如 UITextField,UIButton,UISwitch。通过工具箱中的这些已有控件,我们可以创建各式各样的用户界面。
然而,有时候你希望界面做得稍微的与众不同,那么此时苹果提供的这些控件就无法满足你的需求。
自定义控件,除了是自己构建二外,与苹果提供的,没什么差别。也就是说,自定义控件不存在于 UIKit 框架。自定义控件跟苹果提供的标准控件一样,应该是通用,并且多功能的。你也会发现,互联网上有一些积极的开发者乐意分享他们自定义的控件。
本文中,你将实现一个自己的 RangeSlider 自定义控件。这个控件是一个两端都可以滑动的,也就是说,你可以通过该控件获得最小值和最大值。你将会接触到这样一些概念:对现有控件的扩展,设计和实现 自定义控件的 API,甚至还能学到如何分享你的自定义控件到开发社区中。
注意:本文截稿时,我们还不会贴出关于 iOS 8 beta 版本的截图。所有文中涉及到的截图都是在iOS 8之前的版本中得到的,不过结果非常类似。
目录:
开始
Images vs. CoreGraphics
添加默认的控件属性
添加交互逻辑
添加触摸处理
值改变的通知
结合 Core Graphics 对控件进行修改
处理控件属性的改变
何去何从?
开始
假设你在开发一个应用程序,该程序提供搜索商品价格列表。通过这个假象的应用程序允许用户对搜索结果进行过滤,以获得一定价格范围的商品。你可 能会提供这样一个用户界面:两个 UISlider 控件,一个用于设置最低价格,另外一个设置最高价格。然而,这样的设计,不能够让用户很好的感知价格的范围。要是能够提供一个 slider,两端可以分别设置用于搜索的最高和最低的价格范围,就更好了。
你可以通过创建一个 UIView 的子类,然后为可视的价格范围定做一个 view。这对于应用程序内部来说,是 ok的,但是要想移植到别的程序中,就需要花更多的精力了。
最好的办法是将构建一个新的尽可能通用的 UI 控件,这样就能在任意的合适场合中重用。这也是自定义控件的本质。
启动 Xcode,File/New/Project,选中 iOS/Application/Single View Application 模板,然后点击 Next。在接下来的界面中,输入 CustomSliderExample 当做工程名,然后是 Organization Name 和 Organization Identifier,然后,一定要确保选中 Swift 语言,iPhone 选中,Use Core Data 不要选。
最后,选择一个保存工程的地方并单击 Create。
首先,我们需要做出决定的就是创建自定义控件需要继承自哪个类,或者对哪个类进行扩展。
位了使自定义控件能够在应用程序中使用,你的类必须是 UIView 的一个子类。
如果你注意观察苹果的 UIKit 参考,会发现框架中的许多控件,例如 UILabel 和 UIWebView 都是直接继承自 UIView 的。然而,也有极少数,例如 UIButton 和 UISwitch 是继承自 UIControl 的,如下继承图所示:
注意:iOS 中 UI 组件的完整类继承图,请看 UIKit Framework 参考。
UIControl 实现了 target-action 模式,这是一种将变化通知订阅者的机制。UIControl 同样还有一些与控件状态相关的属性。在本文中的自定义空间中,将使用到 target-action 模式,所以从 UIControl 开始继承使用将是一个非常好的切入点。
在 Project Navigator 中右键单击 CustomSliderExample,选择 New File…,然后选择 iOS/Source/Cocoa Touch Class 模板,并单击 Next。将类命名位 RangeSlider,在 Subclass of 字段中输入 UIControl,并确保语言是 Swift。然后单击 Next,并在默认存储位置中 Create 出新的类。
虽然编码非常让人愉悦,不过你可能也希望尽快看到自定义控件在屏幕中熏染出来的模样!在写自定义控件相关的任何代码之前,你应该先把这个控件添加到 view controller中,这样就可以实时观察控件的演进程度。
在 Swift 中,structure 和 enumeration 被创建之后其值和属性都是不可变的,如果你需要在一个方法里面修改属性值,需要给这个方法添加 mutating 特性。
官方原文如下:
“Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.
However, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method. The method can then mutate (that is, change) its properties from within the method, and any changes that it makes are written back to the original structure when the method ends. The method can also assign a completely new instance to its implicit self property, and this new instance will replace the existing one when the method ends.
You can opt in to this behavior by placing the mutating keyword before the func keyword for that method:”
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 3).” iBooks.
举个栗子:
struct Person {
var name:String! = "Zhang"
mutating func setName( newName:String ) {
name = newName
}
}
var person = Person()
person.name
person.setName( "Wang" )
在上面例子中,setName 方法需要修改 immutable 属性 name,所以前面要加上 mutating。
首先,请确保PerfectLib已经在您的Swift源程序开始部分完成声明:
import PerfectLib
声明完成之后,即可开始使用File文件对象来实现在文件系统中的查询和文件操作。
配置File文件对象
使用File文件对象时,请指定文件的绝对或相对路径:
let thisFile = File("/path/to/file/helloWorld.txt")
如果您对文件路径还不熟悉,请先阅读目录与路径
打开文件用于读写操作
注意: 在写入文件操作之前(即使是个新文件)文件需要对应的权限才能打开。
打开一个文件:
try thisFile.open(OpenMode,permissions:PermissionMode)
写入文件的例子:
let thisFile = File("helloWorld.txt")
try thisFile.open(.readWrite)
try thisFile.write(string: "你好!")
thisFile.close()
对于文件打开的具体模式OpenMode 和文件权限模式 PermissionMode ,请参考本文附录的详细定义。
检查文件是否存在
请使用exists方法检查文件是否存在。该方法返回一个布尔值,真表示存在,假表示不存在。
thisFile.exists
获取文件修改时间
调用下面的函数将返回一个整数,其含义为自格林威治时间1970/01/01 00:00:00到最后一次修改文件的时间之间的秒数:
thisFile.modificationTime
文件路径
无论文件参考对象是如何定义的,文件所在的绝对路径和内部参考路径都可以通过以下访问获取具体信息:
返回系统内部参考路径"internal reference":
thisFile.path
返回文件的绝对路径(物理路径)方法(如果当前文件为符号链接,则同样其链接也会被解析为绝对路径):
thisFile.realPath
关闭一个文件
一旦文件被打开并执行读写操作,随时可以在程序内选择用close方法关闭,或使用defer方法挂起:
let thisFile = File("/path/to/file/helloWorld.txt")
// 在此处进行文件读写操作处理
thisFile.close()
删除一个文件
如果需要从文件系统中删除一个文件,请使用delete()方法。
thisFile.delete()
调用删除方法时会自动关闭文件,因此不需要提前进行额外的close()关闭操作。
查询文件大小尺寸
调用size方法可以返回文件大小的字节数,返回值为整数。
thisFile.size
判断文件是否为一个符号链接
用下面的方法来判断当前文件对象是否为一个符号链接,如果是符号链接则返回值为布尔类型的true,真值,反之为false假。
thisFile.isLink
判断当前文件对象是否为一个目录
用isDir 方法来判断当前文件对象是否为一个目录节点,如果是则返回值为布尔类型的true,真值,反之为false假。
thisFile.isDir
获取文件的UNIX权限信息
调用perms 函数可返回文件的权限信息,返回值为一个PermissionMode对象。
thisFile.perms
比如:
print(thisFile.perms)
PermissionMode(rawValue: 29092)
读取文件内容
readSomeBytes
根据指定的字节数量读取文件内容:
let thisFile = File("/path/to/file/helloWorld.txt")
let contents = try thisFile.readSomeBytes(count: Int)
参数说明
该方法的参数为计划读取的字节数量。比如,下面的例子说明了如何从文件中读取10字节数据:
let thisFile = File("/path/to/file/helloWorld.txt")
let contents = try thisFile.readSomeBytes(count: 10)
print(contents)
[35, 32, 80, 101, 114, 102, 101, 99, 116, 84]
readString
readString方法能够将整个文件的数据读取到一个字符串:
let thisFile = File("/path/to/file/helloWorld.txt")
let contents = try thisFile.readString()
文件写操作、拷贝和移动
注意 在写文件之前(即使是一个新文件)必须要确认文件操作具备响应的权限。
向文件内写入字符串
使用write方法以UTF-8编码格式向文件创建或写入一个字符串。如果写入成功,则返回具体写入的字节数。
注意该方法会使用@discardableResult属性,所以如果需要的话,即便没有对该属性赋值,也会在调用过程中被使用。
let bytesWritten = try thisFile.write(string: String)
将字节数组写入到一个文件
字节数组bytes同样可以直接写入到一个文件。该方法如果调用成功则返回实际写入的字节数。
注意该方法会使用@discardableResult属性,所以如果需要的话,即便没有对该属性赋值,也会在调用过程中被使用。
let bytesWritten = try thisFile.write(
bytes: [UInt8],
dataPosition: Int,
length: Int
)
参数说明
bytes: 待写入的无符号8位整型数组
dataPosition: 可选参数 在bytes对象中待写入字节的偏移量。如果该参数不为0,则写入时从字节数组的该参数指定字节处开始写入,之前内容会被忽略
length: 可选参数 需要写入的具体字节数量
移动一个文件
文件对象一旦定义成功,就可以随时调用moveto方法,将文件移动到一个新的路径位置上。该方法也可以用于给文件改名。操作完成后,该方法返回一个代表新位置的新的文件对象。
let newFile = thisFile.moveTo(path: String, overWrite: Bool)
参数说明
path: 移动的目标路径
overWrite: 可选参数 如果目标路径文件已经存在,则进行覆盖操作。默认值为假false
Swift语言使用类型名紧接中括号[]来简化标准库中定义的命名型类型Array。换句话说,下面两个声明是等价的: String[] = ["Alex", "Brian", "Dave"] Array = ["Alex", "Brian", "Dave"] 定义好以后就用普通传参的方法就可以了。
Swift和OC不一样,OC组要先取出控件的frame然后修改frame再赋值回去,而Swift中可以直接拿着frame修改
华为手机如何查看详细通话记录和通话时间? 您可以点击拨号或电话,在通话记录列表界面点击全部通话,即可显示全部通话记录及通话时间。华为手机怎么查通话记录? 您好,机子不显示通话记录,一般原因是开启了访客...
苹果手表怎样删除通话记录啊? 1、将苹果手机上的个人收藏进行取消,接着再点击Apple Watch里的联系人进行取消就可以了,加利福尼亚祝楼主生活愉快。2、方法/步骤 在 Apple Watch 主屏...
钉钉有人给我留言,在哪看? 钉钉留言在哪里查看 钉钉暂不支持留言功能。钉钉(DingTalk)是阿里巴巴集团专为中国企业打造的免费沟通和协同的多端平台,提供PC版,Web版和手机版,支持手机和电脑间...
苹果手机怎么找回通话记录 您好,一、10天内的通话记录1打开手机点击拨号按钮,2拨号界面点击最近通话,3最近通话界面可以看到10天以内的记录,4点击通话记录后面的感叹号计入详情,可以看到具体时间以及通...
移动网上营业厅怎么查看自己的通话记录 通过电信网上营业厅即可查询电信的通话记录,步骤如下:1、首先打开浏览器,输入中国电信网上营业厅然后搜索,然后点击进入中国电信网上营业厅并且登录自己的电信手机号。2...
苹果手机没有通话记录是怎么回事 品牌型号:iPhone13 系统:IOS15.2...