【iOS开发】iw01 科学计算器
iOS assignment 1: Calculator App.
姓名:可弟WZ Kekwy
用 swift & storyboard 实现一个计算器APP(包括科学计算器)。
项目仓库:https://github.com/Kekwy/iwork1-Calculator
一、界面设计
静态布局
0x0. StackView
大体分为上下两部分,上方为计算器的显示区域,下方为按键区域。
0x00. 主要约束
1 | Stack View.top = Safe Area.top |
使当前控件大小与父控件大小一致,即填充满父控件。
0x01. 显示区域(View1)
View:为该区域提供指定的背景色。
Stack View:管理两个主要的UILabel。
Exp Label:显示表达式;
Res Label:显示表达式的运算结果;
主要约束:纵向填充,左右边缘与 View 始终存在10的间隔。
0x02. 按键区域(View2)
VIew:为按键区域提供指定的背景色。
Stack View:管理附加按键区与常规按键区。
主要约束:将按键区的高设置为屏幕高的70%:
View.height = 0.7 × height
0x020. 常规按键区
前四行按钮:
- 填充策略为
Fill Equally
; - 每行四个按钮由一个
Stack View
管理,填充策略同样为Fill Equally
; - 通过约束将其高度设置为整个按键区高度的66%。
- 填充策略为
后两行按钮:
包含两个
Stack View
。位于左侧的Stack View
管理左侧六个按钮,排成两行,其中每行三个按钮又由一个Stack View
管理;位于右侧的Stack View
中只有作为等于操作键的一个按钮,可使其高度约为其他按钮的两倍。通过设置约束,将左侧
Stack View
的宽约束为整个常规按键区宽度的75%。
0x021. 附加按键区
在切换为科学计算器(设备横屏)时自动显示
- 与常规按键区类似,每行三个按钮由一个
Stack View
管理,该部分所有Stack View
的填充方式均为Fill Equally
。 - 设置约束,将管理整个附加按键区的
Stack View
的宽设置为整个按键区宽的3/7。
0x022. 按钮细节
通过设置按钮属性 layer.cornerRadius
设置按钮圆角的弧度。竖屏状态设置为20,横屏状态设置为40.
0x1. D/R Show Label
用于显示当前的计算模式是弧度制(Rad)还是角度制(Deg)。横屏模式下显示于显示区域的左上角(通过约束实现),竖屏模式自动隐藏,可通过相关功能按键进行切换。
二、功能实现
0x0. 基础功能
0x00. 用户输入处理
用户每次点击按钮时,计算器会执行其运行逻辑。对于非功能按钮,用户输入会在 ViewController 中被追加在当前表达式之后,然后整个表达式会被传入 Calculator 进行解析。
若用户点击功能性按钮,将在 ViewController 中调用相应的函数进行处理。
0x01. 主要运算逻辑
良好的支持多优先级操作符
使用中缀表达式转后缀表达式的计算思路,参考《数据结构》。为每个操作符设置栈中优先级和栈外优先级,天然的支持多优先级运算,即良好的支持了科学计算器中出现的多个复杂操作符。
1 | let isp = ["#": 0, |
同时设置两个栈结构,一个用于保存操作数,另一个用于保存操作符,当有操作符退栈时,根据其运算规则从操作数栈中退出若干操作数,进行运算后将结果压入操作数栈。
1 | private func calSubExp(opt: String) -> Bool{ |
0x02. memery 操作
主要处理 memery 中出错和 memery 为空的情况:
1 | public func memeryRead() -> String { |
0x03. 角度制与弧度制的切换
计算三角函数时,根据当前计算器的模式对操作数进行转换(浮点数精度可能导致误差):
1 | if !isRad { // 表示处于角度制模式 |
0x04. 按钮功能切换(函数与反函数之间的互换)
当使用者点击 inv
按钮时,会更改部分按钮的 title。被更改 title 的按钮被点击时,在根据新的 title 在 buttonTouched
中执行对应的分支。再次点击 inv
会复原这些按钮之前的 title,即实现按钮功能的切换。
1 | func doInv() { |
0x05. 转动设备时的界面切换
重写 didRotate
对设备旋转时的事件进行处理:
1 | override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) { |
设备旋转为横屏时,调用
launchScienceMode
:显示附加按键区,更改按钮 title 的字号,更改按钮四个角的弧度。
设备旋转为竖屏时,调用
launchNormalMode
:隐藏附加按键区,恢复按钮 title 的字号,恢复按钮四个角的弧度。
0x1. 辅助功能
0x10. 等于操作的作用
自动显示运算结果的工作模式下,等于操作符的作用
使用者点击等于操作符时,会将当前的待计算表达式替换为当前的运算结果。
0x11. 更好的删除操作
一般状态下使用者点击删除按钮会删除表达式中前一个字符,但当前一个字符与其之前的若干字符为一个整体时,会将其一同删除。(如 sin(
会作为一个整体同时删除)
0x12. 面向用户的报错机制
当计算过程中遇到任何语法错误无法向下计算时,会返回运算结果“ERROR”提示用户更改表达式,而不会继续解析格式错误的表达式。
三、问题与解决
0x0. 使 Stack View
中的空间按比例布局
tags: Swift; StoryBoard; Stack View; xcode; iOS; 比例; 布局; 控件; UIKit;
首先将 Stack View
的属性 Distribution
更改为 Fill Proportionally
。
选中需要布局的控件,按住 command
键拖到该 Stack View
上,
选择 Equal Widths
(若需要纵向成比例布局,则选择 Equal Heights
)添加约束。
Additional Buttons.width = 0.4285 × width
即表示控件 Additional Buttons
的宽为 Stack View
宽度的42.85%。
0x1. Swift获取当前设备的状态
tags: Swift; StoryBoard; xcode; iOS; 横屏; 竖屏; 设备状态;
1 | let device = UIDevice.current // 获取当前设备对象 |
0x2. 代码实现修改Button字体大小
tags: Swift; xcode; iOS; UIButton; 字体大小;
1 | // 获取指定大小的字体 |
0x3. 设置圆形的Button
在 xcode 中为 Button 添加如下属性:
代码实现:
1 | dotButton.layer.cornerRadius = 40.0 |
该属性为 Button 四角的弧度,经调整后即可实现圆形的 Button。
四、成果展示
0x00. 完整流程
https://blog.kekwy.com/media/iw1/01.mp4