前言:
师弟要毕业设计,就敲了swift版的计算器给他参考下。现在把代码放上来,通过这个计算器,可以学习简单的封装:将逻辑与界面分离并提供接口的编程方式,这也是我们学习面向对象的必要点。
基于 xcode 9.0 swift4.0
一、先引用SnapKit框架
利用其来约束组件
二、新建一个继承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
运行项目,如下图:
界面部分我们已经基本开发完,接下来进行逻辑处理类的封装。
三、计算器计算逻辑:
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
本文由 投稿者 创作,文章地址:https://blog.isoyu.com/archives/swiftfengzhuang-jisuanqikaifa.html
采用知识共享署名4.0 国际许可协议进行许可。除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为:11 月 23, 2018 at 11:34 下午