本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。
这一节,继续为大家提供一个Demo,用来说明Swift中的各种语法及在UIView中的基本使用。效果图如下:
看起来,这个Demo非常的简单。但是为了进行详细的语法说明,它的实现,均是用代码实现的,并且下方的进度条都是"组装"起来的。
结构分析:
1. 有一个根控制器ViewController.swift, 它只是用来展示上面显示的文字(秋恨雪)。
2. 然后下面的文字大小切换及进度条这个整体是一个自定义的View(LFFontView.swift)
3. 进度条部分又有三部分内容组成:(底部的灰色的总进度View,进度条上面的滑块View,实时显示进度的红色的View)。
大致的结构图如下:
1. 初始化相关的属性
lazy private var buttons: [UIButton] = [UIButton]()
private var selectedButton: UIButton?
lazy private var bottomLine = UIImageView(image: UIImage(named: "正文字号-滑条"))
lazy private var topLine = UIImageView(image: UIImage(named: "正文字号-滑条红"))
lazy private var slider = UIImageView(image: UIImage(named: "正文字号-滑块"))
2) 属性selectedButton 用来存放当前选中了哪一个"Aa"。
3) 三个ImageView就是上面3D图中的前三个内容,即他们组成滑动条。
2. 初始化相关的View
convenience init() {
self.init(frame: CGRectZero)
}
override init(frame: CGRect) {
super.init(frame: frame) // init(frame: CGRect)是UIView的默认构造方法
self.frame = CGRectMake(0, kFontViewY, UIScreen.mainScreen().bounds.width, kFontViewH)
initDetailViews()
}
2) initDetailViews方法进行具体的子View的初始化工作。
3. 具体子View的设置及事件处理
func initDetailViews() {
// Init Buttons
createButton(normal: "正文字号-小(默认)", selected: "正文字号-小", itemStyle: .Small)
createButton(normal: "正文字号-中(默认)", selected: "正文字号-中", itemStyle: .Middle)
createButton(normal: "正文字号-大(默认)", selected: "正文字号-大", itemStyle: .Big)
createButton(normal: "正文字号-大+(默认)", selected: "正文字号-大+", itemStyle: .SuperBig)
// Init Others
addSubview(bottomLine)
addSubview(topLine)
addSubview(slider)
}
func createButton(#normal: String, selected: String, itemStyle: LFFontViewItemStyle) {
let fontBtn = UIButton()
fontBtn.adjustsImageWhenHighlighted = false
fontBtn.tag = itemStyle.rawValue
fontBtn.setImage(UIImage(named: normal), forState: UIControlState.Normal)
fontBtn.setImage(UIImage(named: selected), forState: UIControlState.Selected)
fontBtn.addTarget(self, action: "buttonClick:", forControlEvents: UIControlEvents.TouchDown)
fontBtn.imageView?.contentMode = UIViewContentMode.ScaleAspectFit
fontBtn.backgroundColor = UIColor.grayColor()
buttons.append(fontBtn)
addSubview(fontBtn)
}
func buttonClick(sender: UIButton) {
selectedButton?.selected = false
sender.selected = true
selectedButton = sender
setNeedsLayout()
}
override func layoutSubviews() {
super.layoutSubviews()
let btnY: CGFloat = 0
let btnW = frame.size.width / 4
let btnH: CGFloat = 68
let count = buttons.count
for i in 0..
let kFontViewH: CGFloat = 100
let kFontViewY: CGFloat = UIScreen.mainScreen().bounds.height - kFontViewH
enum LFFontViewItemStyle : Int {
case Small
case Middle
case Big
case SuperBig
}
这些代码书写完毕后,效果就像文章开头贴出的效果,只是点击按钮切换的时候,文字大小不会发生改变。在解决这个问题之前,我先对上面所涉及到的知识点进行归纳总结。
1) Swift中没有了宏的概念,所以定义常量,我们可以直接使用let关键字,如上面的kFontViewH 常量。
2) Swift中枚举的定义与objective-c有了很大的不同,如上面的LFFontViewItemStyle 枚举成员直接都用case标识,并且在使用枚举的时候,有两种写法:
LFFontViewItemStyle.Small 或者 .Small。
3) 代码中使用到的成员或者属性等最好使用let修饰符,除非这些成员或者属性需要进行赋值变化等操作。例如:在layoutSubviews方法中,很多的成员都是用了let修饰符,而在属性定义的地方,很多都使用的var修饰符,因为它们要么是需要动态计算或者有赋值等操作,要么涉及到懒加载操作。
4) 在objective-c中,对属性的调用,我们一般使用“self.属性” 的写法。在Swift中可以直接使用属性名称进行操作,也就是“self.”可以省略。例如:addSubview(bottomLine), buttons.append(fontBtn), selectedButton?.selected 等。 但有一些self的地方是不可以省略的,例如:
self.frame = CGRectMake(0, kFontViewY, UIScreen.mainScreen().bounds.width, kFontViewH)
如果这里直接写frame的话,会和init(frame: CGRect) 中的frame产生歧义。
5) 文章中还出现了很多的 "?" 及 "!" 的使用,如果有什么不清楚的,请参考《Swift:可选类型(Optional) 》。
6) 文章中涉及到了方法形参的修饰符问题,例如:
func createButton(#normal: String, selected: String, itemStyle: LFFontViewItemStyle) {
形参normal的前面加上#,如有疑问的,请参考《Swift:函数与方法》。
好的,基本知识已经讲解完毕,下面我们来看看点击按钮后,怎样使得文字的大小随之发生变化。
由于LFFontView.swift是ViewController.swift的子View,所以我们应该可以想到使用代理或者闭包。
代理的实现方式
1)定义代理
protocol LFFontViewDelegate : NSObjectProtocol {
func fontView(fontView: LFFontView, didSelectedItem item: LFFontViewItemStyle)
}
var delegate: LFFontViewDelegate?
3)在buttonClick方法中执行代理方法
delegate?.fontView(self, didSelectedItem: LFFontViewItemStyle(rawValue: sender.tag)!)
class ViewController: UIViewController,LFFontViewDelegate {
@IBOutlet weak var testLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let fontView = LFFontView()
fontView.delegate = self
view.addSubview(fontView)
}
func fontView(fontView: LFFontView, didSelectedItem item: LFFontViewItemStyle) {
switch(item){
case .Small:
testLabel.font = UIFont.systemFontOfSize(13)
case .Middle:
testLabel.font = UIFont.systemFontOfSize(16)
case .Big:
testLabel.font = UIFont.systemFontOfSize(18)
case .SuperBig:
testLabel.font = UIFont.systemFontOfSize(25)
}
}
}
var delegate: LFFontViewDelegate? {
didSet {
buttonClick(buttons[0])
}
}
大家注意代理定义的时候,是继承自 NSObjectProtocol的,说明它还是沿用了objective-c时候的语法。其实我们定义的protocol完成可以不继承自任何内容。但有时候会出现问题。因为在Swift中的协议与objective-c的协议有所不同。在objective-c中的协议的实现者必须是类;而Swift中协议的实现者既可以是类,也可以是enum或者struct。所以为了严谨起见,我们定义的协议,可以直接指明实现者是类,所以改写协议的定义如下:
protocol LFFontViewDelegate : class {
func fontView(fontView: LFFontView, didSelectedItem item: LFFontViewItemStyle)
}
1) 定义闭包
var textClosure: (LFFontViewItemStyle -> ())?
2) 在buttonClick中调用闭包
func buttonClick(sender: UIButton) {
selectedButton?.selected = false
sender.selected = true
selectedButton = sender
textClosure?(LFFontViewItemStyle(rawValue: sender.tag)!)
setNeedsLayout()
}
3) 在ViewController中实现闭包方法
override func viewDidLoad() {
super.viewDidLoad()
let fontView = LFFontView()
//fontView.delegate = self
fontView.textClosure = {
[unowned self]
(FontStyle: LFFontViewItemStyle) -> () in
switch(FontStyle){
case .Small:
self.testLabel.font = UIFont.systemFontOfSize(13)
case .Middle:
self.testLabel.font = UIFont.systemFontOfSize(16)
case .Big:
self.testLabel.font = UIFont.systemFontOfSize(18)
case .SuperBig:
self.testLabel.font = UIFont.systemFontOfSize(25)
}
}
view.addSubview(fontView)
}
在LFFontView.swift 中的 init(frame: CGRect) 中添加下面的最后一句代码即可。
override init(frame: CGRect) {
//super.init() init是NSObject的默认构造方法
super.init(frame: frame) // init(frame: CGRect)是UIView的默认构造方法
self.frame = CGRectMake(0, kFontViewY, UIScreen.mainScreen().bounds.width, kFontViewH)
initDetailViews()
buttonClick(buttons[0])
}