源码

Swift封装 – 计算器开发

1.png

前言:

师弟要毕业设计,就敲了swift版的计算器给他参考下。现在把代码放上来,通过这个计算器,可以学习简单的封装:将逻辑与界面分离并提供接口的编程方式,这也是我们学习面向对象的必要点。

基于 xcode 9.0 swift4.0

一、先引用SnapKit框架

SnapKit自己看git引入

利用其来约束组件

二、新建一个继承UIButton类的类文件

命名为DWFuncButton,对其设置字体、颜色、风格代码如下:

class DWFuncButton: UIButton {

    init() {
        super.init(frame: CGRect.zero)
        //为按钮添加边框
        self.layer.borderWidth = 0.5;
        self.layer.borderColor = UIColor(red: 219/255.0, green: 219/255.0, blue: 219/255.0, alpha: 1).cgColor
        //设置字体与字体颜色
        self.setTitleColor(UIColor.orange, for: .normal)
        self.titleLabel?.font = UIFont.systemFont(ofSize: 25)
        self.setTitleColor(UIColor.black, for: .highlighted)

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

三、创建一个继承UIView的类

命名为DWBoard,将其用作计算器的操作面板

首先引入SnapKit框架

import SnapKit

先创建一个数组属性,存放操作面板上的所有功能按钮标题

var dataArray = ["0"".""%""="
                , "1""2""3""+"
                , "4""5""6""-"
                , "7""8""9""*"
                 , "AC""DEL""^""/"]

重写父类的构造方法,在其中进行界面的加载操作:

override init(frame: CGRect{
        super.init(frame: frame)
        setupUI()
    }
//对界面进行布局
func setupUI() {
    //创建一个变量 用于保存当前布局按钮的上一个按钮
    var frontBtn: DWFuncButton!
    //进行功能按钮的循环创建
    for index in 0..<20 {
        //创建一个功能按钮
        let btn = DWFuncButton()
        self.addSubview(btn)
        //约束
        btn.snp.makeConstraints({ (make) in
            //当按钮每一行的第一个时,将其靠左侧摆放
            if index%4 == 0 {
                make.left.equalTo(0)
            }else { //否则将按钮的左边考上一个右侧进行摆放
                make.left.equalTo(frontBtn.snp.right)
            }
            //当按钮为第一行,将其靠父视图底部摆放
            if index/4 == 0 {
                make.bottom.equalTo(0)
            }else if index%4 == 0 { //当按钮不在第一行且为每行的第一个时,将其底部与上一个按钮的顶部对齐
                make.bottom.equalTo(frontBtn.snp.top)
                //否则将其底部与上一个按钮底部对齐整
            }else {
                make.bottom.equalTo(frontBtn.snp.bottom)
            }
            //约束宽度为父视图宽度的0.25倍
            make.width.equalTo(btn.superview!.snp.width).multipliedBy(0.25)
            //约束高度为父视图宽度的0.2倍
            make.height.equalTo(btn.superview!.snp.height).multipliedBy(0.2)
        })

        //设置tag值
        btn.tag = index + 100
        //添加点击事件
        btn.addTarget(self, action: #selector(btnClick(_:)), for: .touchUpInside)
        //设置标题
        btn.setTitle(dataArray[index], for: .normal)
        //对上一个按钮更新保存
        frontBtn = btn
    }

}

上面就构建了一个简单的键盘界面,约束代码大家可以看一下,排版为5行4列,布局顺序为从下向上、从左向右依次布局

创建上述代码的点击方法

@objc func btnClick(_ button:DWFuncButton) {
        print(button.currentTitle as Any)
    }

用户在操作面板上进行输入操作,在计算器的显示屏上还需要显示输入的内容,同时,显示屏还兼有计算结果的功能。

首先在DWCalculator工程上新建一个名为DWScreen的类文件,继承自UIView,作为计算器的显示器控件。显示屏分成两部分,一部分用于计算结果,一部分用于显示用户输入的计算过程,所以用两个UILabel来处理。

class DWScreen: UIView {

    var inputLabel:UILabel?
    //用于显示历史记录信息
    var historyLabel:UILabel?
    //用户输入表达式或者计算结果字符串
    var inputString = ""
    //历史表达式字符串
    var historyString = ""
    //所有数字字符 用于进行检测匹配
    let figureArray:Array = ["0""1""2""3""4""5""6""7""8""9""."]
    //所有运算功能字符 用于进行检测匹配
    let funcArray = ["+""-""*""/""^"]
    init() {
        super.init(frame: CGRect.zero)
        inputLabel = UILabel()
        historyLabel = UILabel()
        setupUI()
    }

    func setupUI() {
        //设置文字的对其方式为右对齐
        inputLabel?.textAlignment = .right
        historyLabel?.textAlignment = .right
        //设置字体
        inputLabel?.font = UIFont.systemFont(ofSize: 34)
        historyLabel?.font = UIFont.systemFont(ofSize: 30)
        //设置文字颜色
        inputLabel?.textColor = UIColor.orange
        historyLabel?.textColor = UIColor.black
        //设置文字大小根据字数进行适配
        inputLabel?.adjustsFontSizeToFitWidth = true
        inputLabel?.minimumScaleFactor = 0.5  //最小字体为当前字体的一半
        historyLabel?.adjustsFontSizeToFitWidth = true
        historyLabel?.minimumScaleFactor = 0.5
        //设置文字的截断方式
        inputLabel?.lineBreakMode = .byTruncatingHead
        historyLabel?.lineBreakMode = .byTruncatingHead
        //设置文字的行数
        inputLabel?.numberOfLines = 0
        historyLabel?.numberOfLines = 0

        self.addSubview(inputLabel!)
        self.addSubview(historyLabel!)
        //进行自动布局
        inputLabel?.snp.makeConstraints({ (make) in
            make.left.equalTo(10)
            make.right.equalTo(-10)
            make.bottom.equalTo(-10)
        make.height.equalTo(inputLabel!.superview!.snp.height).multipliedBy(0.5).offset(-10)
        })
        historyLabel?.snp.makeConstraints({ (make) in
            make.left.equalTo(10)
            make.right.equalTo(-10)
            make.top.equalTo(10)
            make.height.equalTo(inputLabel!.superview!.snp.height).multipliedBy(0.5).offset(-10)
        })
    }

    //提供一个输入信息的接口
    func inputContent(content:String) {
        inputString.append(content)
        inputLabel?.text = inputString
    }

    //提供一个刷新历史记录的方法
    func refreshHistory() {
        historyString = inputString
        historyLabel?.text = historyString
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

DWBoard类可以接收用户的输入,DWScreen需要获取用户的输入,他们之间的关联是需要通过ViewController类来完成的。使用代理设计模式完成此功能。

在DWBoard.swift添加协议代码

protocol DWBoardButtonInputDelegate {
    func boardButtonClick(content:String)
}

在DWBoard类添加一个代理属性:

var delegate:DWBoardButtonInputDelegate?

修改DWBoard类中的点击事件

@objc func btnClick(_ button:DWFuncButton) {
    if delegate != nil {
        //通过协议方法将值传递出去
        delegate?.boardButtonClick(content: button.currentTitle!)
    }
}

ViewController类也需要将DWBoard类实例和DWScreen类实例作为自己的属性,相互调用

let board = DWBoard()
let screen = DWScreen()

在viewDidLoad()方法添加setupUI(),并且setupUI代码如下

var dataArray = ["0"".""%""="
                , "1""2""3""+"
                , "4""5""6""-"
                , "7""8""9""*"
                 , "AC""DEL""^""/"]

0

viewController需要遵守DWBoardButtonInputDelegate协议:

var dataArray = ["0"".""%""="
                , "1""2""3""+"
                , "4""5""6""-"
                , "7""8""9""*"
                 , "AC""DEL""^""/"]

1

并且实现协议方法:

var dataArray = ["0"".""%""="
                , "1""2""3""+"
                , "4""5""6""-"
                , "7""8""9""*"
                 , "AC""DEL""^""/"]

2

运行项目,如下图:

2.png

界面部分我们已经基本开发完,接下来进行逻辑处理类的封装。

三、计算器计算逻辑:

DWScreen类需要继续完善。例如当用户点击清空按钮时,输入的计算表达就应该被清空。当用户点击回退按钮时,上一次输入的字符就应该被清空。在DWScreen类添加如下代码:

var dataArray = ["0"".""%""="
                , "1""2""3""+"
                , "4""5""6""-"
                , "7""8""9""*"
                 , "AC""DEL""^""/"]

3

在项目中新建一个继承于NSObject的类文件,并命名为DWCalculatorEngine。将其作为计算引擎工具类,代码如下:

var dataArray = ["0"".""%""="
                , "1""2""3""+"
                , "4""5""6""-"
                , "7""8""9""*"
                 , "AC""DEL""^""/"]

4

在ViewController类中添加两个属性:一个计算工具类:

var dataArray = ["0"".""%""="
                , "1""2""3""+"
                , "4""5""6""-"
                , "7""8""9""*"
                 , "AC""DEL""^""/"]

5

isNew属性主要作用是标记本次输入是否需要将显示屏已有的内容清除。当用户完成一次计算后,计算结果会显示在显示屏上。此时如果用户继续输入,则进行下一轮的计算,显示屏的上次结果应该被清空。

修改ViewController类中的协议方法

var dataArray = ["0"".""%""="
                , "1""2""3""+"
                , "4""5""6""-"
                , "7""8""9""*"
                 , "AC""DEL""^""/"]

6

大功告成!代码传送门

作者:Dwyane_Coding

链接:https://www.jianshu.com/p/92a07bca77b0

(0)

本文由 投稿者 创作,文章地址:https://blog.isoyu.com/archives/swiftfengzhuang-jisuanqikaifa.html
采用知识共享署名4.0 国际许可协议进行许可。除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为:11 月 23, 2018 at 11:34 下午

热评文章

发表回复

[必填]

我是人?

提交后请等待三秒以免造成未提交成功和重复