一、任务
初步了解的UIKit框架的基本组件和Swift语法,想尝试下综合使用。
下图是MAC上的简易计算器
想实现一个类似的计算器小应用
二、项目创建和第三方库引入
- 项目创建
2.
Autolayout界面布局,使用了第三方库SnapKit。
# 安装 cocoapods
gem install cocoapods
# 初始化
pod init
# 修改Podfile文件
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '13.0'
target 'CalculatorZero' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
pod 'SnapKit', '~> 5.0.1'
# Pods for CalculatorZero
end
# 安装第三方库
pod install
安装成功后会提醒你重新打开项目
这里要点击.xcworkspace结尾的文件打开项目才行,目录结构如下图
在需要的类中import SnapKit就可以使用了
cocoapods用于管理引入第三方库的,ruby写的。想要了解的可以参考 Cocoapods 或 Cocoapods Guide
三、布局划分
如图可以将计算机界面拆解为三部分
第1部分为显示板screen部分
第2部分为操作板board部分
第3部分为操作funcbutton按钮
四、封装
- 按钮组件
FuncButton,新建一个类文件FuncButton,继承自UIButton类
**class** FuncButton: UIButton {
**init** () {
**super**.init(frame: CGRect.zero)
**self**.layer.borderWidth = 0.5
**self**.layer.backgroundColor = UIColor(red:219/255.0,green: 219/255.0,blue: 219/225.0,alpha: 1).cgColor
**self**.setTitleColor(UIColor.orange, for: UIControl.State.normal)
**self**.titleLabel?.font = UIFont.systemFont(ofSize: 25)
**self**.setTitleColor(UIColor.black, for: UIControl.State.highlighted)
}
**required** **init**?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
- 操作面板
Board,新建一个类文件Board,继承自UIView类
// 布局的第三方库
**import** SnapKit
**protocol** BoardButtonInputDeletegate {
**func** boardButtonClick(content:String)
}
**class** Board: UIView {
**var** deletegate:BoardButtonInputDeletegate?
**var** dataArray = ["0",".","%","="
,"1","2","3","+"
,"4","5","6","-"
,"7","8","9","*"
,"AC","Del","^","/"]
**override** **init** (frame: CGRect) {
**super**.init (frame: frame)
installUI ()
}
**required** **init**?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
**func** installUI() {
**var** fronBtn:FuncButton!
**for** index **in** 0..<20{
**let** btn = FuncButton()
**self**.addSubview(btn)
btn.snp.makeConstraints { make **in**
**if** index%4 == 0 {
make.left.equalTo(0)
}**else**{
make.left.equalTo(fronBtn.snp.right)
}
**if** index/4 == 0 {
make.bottom.equalTo(0)
}**else** **if** index%4 == 0 {
make.bottom.equalTo(fronBtn.snp.top)
}**else**{
make.bottom.equalTo(fronBtn.snp.bottom)
}
make.width.equalTo(btn.superview!.snp.width).multipliedBy(0.25)
make.height.equalTo(btn.superview!.snp.height).multipliedBy(0.2)
}
btn.tag = index + 100
btn.addTarget(**self**, action: **#selector**(btnClick(button:)), for: .touchUpInside)
btn.setTitle(dataArray[index], for: .normal)
fronBtn = btn
}
}
**@objc** **func** btnClick(button: FuncButton) {
**if** deletegate != **nil** {
deletegate?.boardButtonClick(content: button.currentTitle!)
}
print(button.title(for: .normal))
}
}
- 显示面板部分
Screen,新建一个类文件Screen,继承自UIView类
**class** Screen: UIView {
**var** inputLabel: UILabel?
**var** historyLabel: UILabel?
**var** inputString = ""
**var** historyString = ""
**let** figrueArray:Array<Character> = ["0","1","2","3","4","5","6","7","8","9","."]
**let** funcArray:Array<Character> = ["+","_","*","/","%","^"]
**init**() {
inputLabel = UILabel()
historyLabel = UILabel()
**super**.init(frame: .zero)
installUI()
}
**func** installUI() {
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(historyLabel!.superview!.snp.height).multipliedBy(0.5).offset(-10)
})
}
**func** inputContent(content:String) {
**if** !figrueArray.contains(content.last!) && !funcArray.contains(content.last!) {
**return**;
}
**if** inputString.count > 0 {
**if** figrueArray.contains(inputString.last!) {
inputString.append(content.last!)
inputLabel?.text = inputString
}**else**{
**if** figrueArray.contains(content.last!) {
inputString.append(content.last!)
inputLabel?.text = inputString
}
}
}**else**{
**if** figrueArray.contains(content.last!) {
inputString.append(content.last!)
inputLabel?.text = inputString
}
}
}
**func** refreshHistory() {
historyString = inputString
historyLabel?.text = historyString
}
**required** **init**?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
五、 Board的用户输入与Screen显示的关联
Board类可以接受用户的输入,将其获取到的数据向外传递,使用代理设计模式可以实现这个功能。即Board将协议中的方法委托给遵守BoardButtonInputDeletegate协议的类
- 需要给Board.swift增加一个协议
**protocol** BoardButtonInputDeletegate {
**func** boardButtonClick(content:String)
}
在Board.swift中添加代理属性
**var** deletegate:BoardButtonInputDeletegate?
修改Board.swift中点击事件
**@objc** **func** btnClick(button: FuncButton) {
**if** deletegate != **nil** {
deletegate?.boardButtonClick(content: button.currentTitle!)
}
print(button.title(for: .normal))
}
- 在使用的ViewController类中遵守
BoardButtonInputDeletegate协议,实现协议中的方法boardButtonClick
**class** ViewController: UIViewController, BoardButtonInputDeletegate
**func** boardButtonClick(content: String) {
**if** content == "AC" || content == "Del" || content == "=" {
screen.refreshHistory()
}**else**{
screen.inputContent(content: content)
}
}
六、 总结展示
在viewcontroller 中引入上面的组件并添加到view上,Board占屏幕的2/3,Screen占屏幕的1/3。 这是一个简单的单页面应用,尝试了横屏竖屏适配、封装独立视图控件、视图控件交互传值。
运行效果如图