您的位置:首页 > 移动开发 > Swift

Swift:UIKit中Demo(二)

2015-08-29 10:31 363 查看
这一节,继续为大家提供一个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: "正文字号-滑块"))


1) 数组buttons用来存放 "Aa" 这四个按钮。

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()
}


1) 便利的无参构造方法调用了直接的有参构造方法,并且进行View的frame的设置。

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..<count {
            var btn = buttons[i]
            var btnX = CGFloat(i) * btnW
            btn.frame = CGRectMake(btnX, btnY, btnW, btnH)
        }
        
        // self.bottomLine
        let bottomLineX: CGFloat = btnW * 0.5
        let bottomLineY: CGFloat = 80
        let bottomLineW: CGFloat = frame.size.width - btnW
        let bottomLineH: CGFloat = 3
        bottomLine.frame = CGRectMake(bottomLineX, bottomLineY, bottomLineW, bottomLineH)
        
        // self.slider
        let sliderCenterX = selectedButton == nil ? bottomLineX : selectedButton?.center.x;

        slider.center.x = sliderCenterX!
        slider.center.y = bottomLine.center.y
        
        // self.topLine
        topLine.frame = bottomLine.frame;
        topLine.frame.size.width = sliderCenterX! - bottomLineX
    }


代码中使用到了常量及枚举,他们的定义如下:

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的地方是不可以省略的,例如:

<span style="font-family:SimSun;font-size:18px;">self.frame = CGRectMake(0, kFontViewY, UIScreen.mainScreen().bounds.width, kFontViewH)</span>
如果这里直接写frame的话,会和init(frame: CGRect) 中的frame产生歧义。

5) 文章中还出现了很多的 "?" 及 "!" 的使用,如果有什么不清楚的,请参考《Swift:可选类型(Optional) 》

6) 文章中涉及到了方法形参的修饰符问题,例如:

<span style="font-family:SimSun;font-size:18px;">func createButton(#normal: String, selected: String, itemStyle: LFFontViewItemStyle) {</span>
形参normal的前面加上#,如有疑问的,请参考《Swift:函数与方法》

好的,基本知识已经讲解完毕,下面我们来看看点击按钮后,怎样使得文字的大小随之发生变化。

由于LFFontView.swift是ViewController.swift的子View,所以我们应该可以想到使用代理或者闭包。



代理的实现方式

1)定义代理

protocol LFFontViewDelegate : NSObjectProtocol {
    func fontView(fontView: LFFontView, didSelectedItem item: LFFontViewItemStyle)
}


2)在LFFontView.swift定义代理属性

var delegate: LFFontViewDelegate?
3)在buttonClick方法中执行代理方法

delegate?.fontView(self, didSelectedItem: LFFontViewItemStyle(rawValue: sender.tag)!)


4)在ViewController.swift中遵守代理协议及实现代理方法

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)
        }
    }
}


这样就可以完成点击按钮,使得文字大小随之变化的效果了。但是程序刚启动的时候,应该选中第一个"Aa" 按钮并显示对应大小的文字,所以我们可以考虑使用“属性监听器”来完成第一次的点击事件。如果对属性监听器不怎么了解的朋友,可以参考《Swift:面向对象(属性)》。所以我们改造代理属性的定义,完成属性监听的工作,改造后的代码如下:

var delegate: LFFontViewDelegate? {
        didSet { 
            buttonClick(buttons[0])
        }
    }


这里的didiSet在初始化的时候并不会执行,而是等到有具体的控制器成为它的代理的时候才会触发,也就是在ViewController中执行fontView.delegate = self 的时候会触发didSet的执行。

大家注意代理定义的时候,是继承自 NSObjectProtocol的,说明它还是沿用了objective-c时候的语法。其实我们定义的protocol完成可以不继承自任何内容。但有时候会出现问题。因为在Swift中的协议与objective-c的协议有所不同。在objective-c中的协议的实现者必须是类;而Swift中协议的实现者既可以是类,也可以是enum或者struct。所以为了严谨起见,我们定义的协议,可以直接指明实现者是类,所以改写协议的定义如下:

protocol LFFontViewDelegate : class {
    func fontView(fontView: LFFontView, didSelectedItem item: LFFontViewItemStyle)
}


闭包的实现方法 (闭包的知识如果有什么不理解,请参考《Swift:闭包(Closures)》)。

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)
    }


4) 首次加载时候触发

在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])
    }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: