计算器仿写
文章目录

UI界面
- 按钮部分
对于这些均匀布局的按钮我使用的是UIStackView,这是一个自动布局容器,可以按照一定的方向排列多个子视图,写起来会很简单
前四行的distribution使用UIStackViewDistributionFillEqually模式,会让按钮均等分布
最后一行使用UIStackViewDistributionFill(在保留子视图自身固有尺寸的同时让子视图伸缩)然后用Masonry规定0的宽度是小数点的两倍,小数点和等号宽度一样即可
注意圆角要在计算出按钮大小之后进行设置
再对这5行使用一个UIStackViewDistributionFillEqually模式即可
对于AC按钮要特殊处理多加一个长按的手势,并且添加是否有输入的状态布尔值,在用户按其他按钮时将按钮的内容换成删除图标,在删除图标的状态下就是退一格,长按会清空并且变回AC按钮
- 输出部分
这里本来打算使用UITextField,但是要关闭他的交互功能避免用户其他方式输入以及光标,这样的话也就无法在长文本的情况下实现手指滑动查看的功能
所以最后采用UIScrollView叠加UILabel的方式,并且在每次更新用户输入的时候对字体大小进行判断,保证在一定的字号区间内该字号的文本可以完整展示在整个屏幕里,做一个while循环在一定字号区间内挨个判断即可实现长文本逐渐减小的过程
最后添加一个滚动功能,因为长文本超出屏幕他可能给你显示在了最左边的开头,但是我们要的是右边,添加回滚即可
Model部分
在ViewController部分我只做了UI,点击相应按钮后会调用Model的对应函数去处理按下不同按钮的逻辑,之后返回一个字符串用于显示在输出Label
在这里首先要定义一些值
objc
@interface CalculatorModel ()
@property (nonatomic, strong) NSMutableArray<NSString *> *tokens;
/// 正在输入的完整数字
@property (nonatomic, strong) NSMutableString *currentNumber;
/// 是否刚刚计算结束
@property (nonatomic, assign) BOOL isJustCalculated;
/// 尚未匹配右括号的左括号数量
@property (nonatomic, assign) NSInteger unmatchedLeftCount;
@end
static NSString * const CalculatorNegateOperator = @"NEG";
@interface CalculatorModel : NSObject
@property (nonatomic, copy) NSString *expression;
- (NSString *)inputDigit:(NSString *) digit;
- (NSString *)inputPoint;
- (NSString *)inputOperator:(NSString *) operatorSymbol;
- (NSString *)inputLeft;
- (NSString *)inputRight;
- (NSString *)deleteLastInput;
- (NSString *)clearAll;
- (NSString *)calculateResult;
- (BOOL)hasInput;
@end
由于我的计算部分是打算用中缀表达式转后缀表达式来进行计算,所以我这里的tokens就是用来保存中缀表达式的,并且只要中缀表达式合法保存,后面计算部分就不会出现太大问题
例如8+3=11在tokens里保存为@@"8", @"+", @"3", @"=", @"11",不可以按一次按钮就添加到tokens里,否则11就会被分割成两个1,这个时候我们要保存到currentNumber,在用户按下运算符的时候再将currentNumber
添加到tokens里,并且将刚刚输入的运算符添加到currentNumber里
在currentNumber这个过程中,我们会不断的判断,比如用户在按下 + 之后按下 . 小数点,我们需要给currentNumber自动转换成"0.",类似的情况很多,我们要一一进行判断进而在用户按下按钮后返回正确表达式,这也能保证我们的中缀表达式不会出现错误
有的时候用户输入的右括号会少于左括号,我们在按下等于的那一刻自动进行补全,这个时候就要用到unmatchedLeftCount做一个while循环补一个右括号就减1
最后返回正确字符串的时候我们可以单独做一个函数去将tokens的每一个元素拼接成完整的字符串,最后再加上currentNumber
另外一个一个比较麻烦的就是负号,我们可以在保存到tokens的时候将负号替换成一个字符串,这样我们就可以轻松判断是减号还是负号,不过在展示的时候还是要用负号,以及最后计算环节还是要变成负号
计算部分
这部分主要就是中缀表达式转后缀表达式来进行计算,详细可以参考这篇文章《数据结构》:中缀表达式转后缀表达式 + 后缀表达式的计算
代码详情:计算器仿写