【iOS】计算器实现

仿写iOS的计算器,使用了MVC模式和masonry库。

绘制界面

  1. 建立一个button的循环,统一设置属性,添加约束。
  2. 将括号按钮的tag设成100+,运算符按钮的tag设成200+,数字按钮的tag设成300+,用于之后分类。
  3. 设置不同按钮的颜色。
  4. 在按钮上方添加一个UITextField,关掉它的用户交互,并打开自调整宽度。
  5. 单独建立AC,小数点,等于号的按钮。
    下面是计算器的界面:
    在这里插入图片描述
    Calculate_View.h
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface Calculate_View : UIView

@property (nonatomic, strong) NSMutableArray* butArray;

@property (nonatomic, strong) UITextField* Caltextfiled;

@property (nonatomic, strong) UIButton* ACBut;
@property (nonatomic, strong) UIButton* pointBut;
@property (nonatomic, strong) UIButton* equalBut;

- (void) addUI;

@end

Calculate_View.m

#import "Calculate_View.h"
#import "Masonry.h"
#define Maxsize 85
#define Width 375
@implementation Calculate_View

- (void) addUI {
    NSArray* arr1 = [NSArray arrayWithObjects: @"AC", @"(", @")", @"/", @"*", @"-", @"+", @"=", nil];
    
    self.backgroundColor = UIColor.blackColor;
    self.butArray = [[NSMutableArray alloc] init];
    
    self.Caltextfiled = [[UITextField alloc] init];
    self.Caltextfiled.backgroundColor = UIColor.blackColor;
    self.Caltextfiled.textColor = UIColor.whiteColor;
    self.Caltextfiled.textAlignment = NSTextAlignmentRight;
    self.Caltextfiled.font = [UIFont systemFontOfSize:60];
    self.Caltextfiled.userInteractionEnabled = NO;
    self.Caltextfiled.adjustsFontSizeToFitWidth = YES;
    //self.Caltextfiled.text = @"0";
    [self addSubview:self.Caltextfiled];
    
    [self.Caltextfiled mas_makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(self).offset(-600);
        make.width.equalTo(@Width);
    }];
    
    
    for (int i = 0; i< 4; i++) {
        for (int j = 0;j < 4; j++) {
            UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
            button.layer.cornerRadius = Maxsize/2;
            button.titleLabel.font = [UIFont systemFontOfSize:42];
            [self addSubview:button];
            
            [button mas_makeConstraints:^(MASConstraintMaker *make) {
                make.bottom.equalTo(self).offset(-(70 + (Maxsize + 15)* (i + 1)));
                make.left.equalTo(self).offset (3 + (Maxsize + 15)*j);
                make.size.equalTo (@Maxsize);
                
            }];
            if (i == 3 && j < 3) {
                button.backgroundColor = UIColor.grayColor;
                [button setTitle:arr1[i+j-3] forState:UIControlStateNormal];
                [button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
                button.tag = 100 + j;
                if (j == 0) {
                    _ACBut = button;
                } else {
                    [self.butArray addObject:button];
                }
            } else if (j == 3) {
                button.backgroundColor = UIColor.orangeColor;
                [button setTitle:arr1[i+j] forState:UIControlStateNormal];
                [button setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
                button.tag = 200 + i;
                [self.butArray addObject:button];
                
            } else {
                button.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1];
                NSString* str = [NSString stringWithFormat:@"%d", j + 3 * i + 1];
                [button setTitle:str forState:UIControlStateNormal];
                [button setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
                button.tag = 300 + i * 3 + j;
                [self.butArray addObject:button];
                
            }
            
        }
    }
    for (int i = 0; i < 3; i++) {
        UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        button.titleLabel.font = [UIFont systemFontOfSize:42];
        button.layer.cornerRadius = Maxsize/2;
        [button setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
        
        [self addSubview:button];
        if (i == 0) {
            [button mas_makeConstraints:^(MASConstraintMaker *make) {
                make.bottom.equalTo(self).offset(-70);
                make.left.equalTo(self).offset(0);
                make.width.equalTo(@(Maxsize * 2 + 15));
                make.height.equalTo(@Maxsize);
            }];
            [button setTitle:@"0" forState:UIControlStateNormal];
            button.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1];
            button.tag = 310;
            [self.butArray addObject:button];
            
        } else {
            [button mas_makeConstraints:^(MASConstraintMaker *make) {
                make.bottom.equalTo(self).offset(-70);
                make.left.equalTo(self).offset(200 + (Maxsize + 15) * (i - 1));
                make.size.equalTo(@Maxsize);
            }];
            if (i == 1) {
                [button setTitle:@"." forState:UIControlStateNormal];
                button.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1];
                button.tag = 311;
                self.pointBut = button;
                
                
            } else {
                [button setTitle:@"=" forState:UIControlStateNormal];
                button.backgroundColor = UIColor.orangeColor;
                button.tag = 400;
                self.equalBut = button;
                
            }
        }
    }

}

@end

添加事件

  1. MVC模式要求我们在ViewController里实现并添加事件。
  2. 在ViewController中单独为小数点,AC,等于号添加点击事件。
	[self.mView.ACBut addTarget:self action:@selector(pressAC:) forControlEvents:UIControlEventTouchUpInside];
    [self.mView.equalBut addTarget:self action:@selector(pressequal:) forControlEvents:UIControlEventTouchUpInside];
    [self.mView.pointBut addTarget:self action:@selector(presspoint:) forControlEvents:UIControlEventTouchUpInside];
  1. 为便利存储在数组中的按钮,为它们添加点击事件。
for (UIButton* button in self.mView.butArray) {
        [button addTarget:self action:@selector(press:) forControlEvents:UIControlEventTouchUpInside
        ]; 
    }
  1. 设置一个总事件按钮,根据按钮的tag值,对不同的按钮添加事件。
- (void) press: (UIButton*) button {
    if (button.tag/100 == 1) {
        [self pressbrac:button];
    }
    if (button.tag/100 == 2) {
        [self pressoper:button];
    }
    if (button.tag/100 == 3) {
        [self pressnum: button];
    }
}
  1. 实现这些事件。

输入判错

对于用户的一些错误的输入进行判别,例如:小数点数量问题,括号数量以及匹配问题等不符合计算要求的输入方式。

for (i = 0; i < len; i++) {
        
        if (t[i] == '(') {
            count3++;
        }
        if (t[i] == ')') {
            count3--;
        }
        if (count3 < 0) {
            self.mView.Caltextfiled.text = fail;
            return;
        }
        
        if (t[i] == '/' && t[i+1] == '0' && t[i+2] != '.') {
            self.mView.Caltextfiled.text = fail;
            
            return;
        }
        
        if (t[i] == '.') {
            self.count2++;
        }
        
        if ((t[i] == '+' || t[i] == '-' || t[i] == '*'|| t[i] == '/') && (self.count2 == 1 || self.count2 == 0 )){
            self.count2 = 0;
            
        }
        if (self.count2 > 1) {
            self.mView.Caltextfiled.text = fail;
            
            return;
        }
        if ((t[i] == '+' || t[i] == '-' || t[i] == '*'|| t[i] == '/') && self.count2 > 1) {    //数字格式错误
            //NSLog(@"%d", self.count2);
            self.mView.Caltextfiled.text = fail;
            
            return;
        }
        
        if ((t[i] == '+' || t[i] == '-' || t[i] == '*'|| t[i] == '/') && (t[i+1] == '+' || t[i+1] == '-' || t[i+1] == '*' || t[i+1] == '/')) {
            
            self.mView.Caltextfiled.text = fail;
            
            return;
        }
        
        if ((t[i] == '+' || t[i] == '-' || t[i] == '*'|| t[i] == '/') && (t[i+1] <'(' || t[i+1] > '9')) {
            
            self.mView.Caltextfiled.text = fail;
            
            return;
        }
        
        if (t[i] == '(' && t[i+1] == ')') { //直接左右括号
            
            self.mView.Caltextfiled.text = fail;
            
            return;
        }
        
        if (t[i] == '(' && (t[i+1] == '+' || t[i+1] == '-' || t[i+1] == '*'|| t[i+1] == '/') && t[i+2] == ')') {
            
            self.mView.Caltextfiled.text = fail;
            return;
        }
        
        if (self.count1 != 0  && t[i] == ')') {

            self.mView.Caltextfiled.text = fail;
            
            return;
        }
        
        if ((t[i] > '0' && t[i] <= '9') && t[i+1] == '(') {
            self.mView.Caltextfiled.text = fail;
            return;
        }
    }

ViewController全部代码:

ViewController.h

#import <UIKit/UIKit.h>
#import "Calculate_View.h"
#import "Calculate_Model.h"
@interface ViewController : UIViewController

@property (nonatomic, strong) Calculate_View* mView;
@property (nonatomic, strong) Calculate_Model* mModel;
@property int count1;
@property int count2;

@end

ViewController.m

#import "ViewController.h"
#import "Calculate_View.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.mView = [[Calculate_View alloc] initWithFrame:self.view.bounds];
    [self.mView addUI];
    [self.view addSubview:self.mView];
    
    self.count1 = 0;
    self.count2 = 0;
    [self.mView.ACBut addTarget:self action:@selector(pressAC:) forControlEvents:UIControlEventTouchUpInside];
    [self.mView.equalBut addTarget:self action:@selector(pressequal:) forControlEvents:UIControlEventTouchUpInside];
    [self.mView.pointBut addTarget:self action:@selector(presspoint:) forControlEvents:UIControlEventTouchUpInside];
    
    for (UIButton* button in self.mView.butArray) {
        [button addTarget:self action:@selector(press:) forControlEvents:UIControlEventTouchUpInside
        ];
        
    }
}

- (void) press: (UIButton*) button {
    if (button.tag/100 == 1) {
        [self pressbrac:button];
    }
    if (button.tag/100 == 2) {
        [self pressoper:button];
    }
    if (button.tag/100 == 3) {
        [self pressnum: button];
    }
}
//括号的处理
- (void) pressbrac: (UIButton*) button {
    
    NSString* old = self.mView.Caltextfiled.text;
    NSString* new1 = button.titleLabel.text;
    
    if ([button.titleLabel.text isEqualToString:@"("]) {
        _count1++;
        
    } else {
        _count1--;
    }
    NSLog(@"%d", _count1);
    NSString* new2 = [NSString stringWithFormat:@"%@%@", old,new1];
    
    self.mView.Caltextfiled.text = new2;
    
    
}
//运算符号的处理
- (void) pressoper: (UIButton*) button {
    if (button.tag > 201) {
        [self pressbut1:button];
    } else {
        [self pressbut2: button];
    }
}

- (void) pressbut1: (UIButton*) button {//加减法
    
    NSString* old = self.mView.Caltextfiled.text;
    NSString* new1 = button.titleLabel.text;
    NSString* new2 = [NSString stringWithFormat:@"%@%@", old,new1];
    
    self.mView.Caltextfiled.text = new2;
        
        
}

- (void) pressbut2: (UIButton*) button {//乘除法
    NSString* old = self.mView.Caltextfiled.text;
    NSString* new1 = button.titleLabel.text;
    NSString* new2 = [NSString stringWithFormat:@"%@%@", old,new1];
    
    self.mView.Caltextfiled.text = new2;
}

//数字的处理
- (void) pressnum: (UIButton*) button {
    NSString* old = self.mView.Caltextfiled.text;
    NSString* new1 = button.titleLabel.text;
    NSString* new2 = [NSString stringWithFormat:@"%@%@", old,new1];
    self.mView.Caltextfiled.text = new2;
    NSLog(@"%@", self.mView.Caltextfiled.text);
    
}

- (void) pressAC: (UIButton*) button {
    self.mView.Caltextfiled.text = nil;
    self.count1 = 0;
    self.count2 = 0;
}

- (void) presspoint: (UIButton*) button {
    NSString* old = self.mView.Caltextfiled.text;
    NSString* new1 = button.titleLabel.text;
    NSString* new2 = [NSString stringWithFormat:@"%@%@", old,new1];
    
    self.mView.Caltextfiled.text = new2;
    
}

//等于号部分
- (void) pressequal: (UIButton*) button {
    NSString* fail = @"错误";
    const char* q = [self.mView.Caltextfiled.text UTF8String];
    char* t = strdup(q);
    NSLog(@"%s", t);
    int i = 0;
    int len = (int) strlen (t);
    //括号数量
    if (self.count1 != 0) {
        self.mView.Caltextfiled.text = fail;
        printf("100");
        return;
    }
    int count3 = 0;
    
    for (i = 0; i < len; i++) {
        
        if (t[i] == '(') {
            count3++;
        }
        if (t[i] == ')') {
            count3--;
        }
        if (count3 < 0) {
            self.mView.Caltextfiled.text = fail;
            return;
        }
        
        if (t[i] == '/' && t[i+1] == '0' && t[i+2] != '.') {
            self.mView.Caltextfiled.text = fail;
            printf("200");
            return;
        }
        
        if (t[i] == '.') {
            self.count2++;
        }
        
        if ((t[i] == '+' || t[i] == '-' || t[i] == '*'|| t[i] == '/') && (self.count2 == 1 || self.count2 == 0 )){
            self.count2 = 0;
            
        }
        if (self.count2 > 1) {
            self.mView.Caltextfiled.text = fail;
            printf("300");
            return;
        }
        if ((t[i] == '+' || t[i] == '-' || t[i] == '*'|| t[i] == '/') && self.count2 > 1) {    //数字格式错误
            //NSLog(@"%d", self.count2);
            self.mView.Caltextfiled.text = fail;
            printf("400");
            return;
        }
        
        if ((t[i] == '+' || t[i] == '-' || t[i] == '*'|| t[i] == '/') && (t[i+1] == '+' || t[i+1] == '-' || t[i+1] == '*' || t[i+1] == '/')) {
            
            self.mView.Caltextfiled.text = fail;
            printf("500");
            return;
        }
        
        if ((t[i] == '+' || t[i] == '-' || t[i] == '*'|| t[i] == '/') && (t[i+1] <'(' || t[i+1] > '9')) {
            
            self.mView.Caltextfiled.text = fail;
            printf("600");
            return;
        }
        
        if (t[i] == '(' && t[i+1] == ')') { //直接左右括号
            
            self.mView.Caltextfiled.text = fail;
            printf("700");
            return;
        }
        
        if (t[i] == '(' && (t[i+1] == '+' || t[i+1] == '-' || t[i+1] == '*'|| t[i+1] == '/') && t[i+2] == ')') {
            
            self.mView.Caltextfiled.text = fail;
            return;
        }
        
        if (self.count1 != 0  && t[i] == ')') {

            self.mView.Caltextfiled.text = fail;
            printf("800");
            return;
        }
        
        if ((t[i] > '0' && t[i] <= '9') && t[i+1] == '(') {
            self.mView.Caltextfiled.text = fail;
            printf("900");
            return;
        }
    }
    
    if (t[0] == '-') {
        t[0] = '!';
    }
    self.mView.Caltextfiled.text = [NSString stringWithUTF8String:t];
    
    self.mModel = [[Calculate_Model alloc] init];
    self.mModel.str1 = self.mView.Caltextfiled.text;
    self.mView.Caltextfiled.adjustsFontSizeToFitWidth = YES;
    [self.mModel Calculation];
    self.mView.Caltextfiled.text = self.mModel.ptf;
}
@end

运算

采取的是数组模拟一个栈的思想,将正确的数学计算表达式转化为逆波兰表达式,再通过计算逆波兰表达式得出计算的结果。

Calculate_Model.h

#import <Foundation/Foundation.h>
#import"Calculate_View.h"
NS_ASSUME_NONNULL_BEGIN

@interface Calculate_Model : NSObject
@property (nonatomic, strong) NSString* str1;
@property char* str;
@property (nonatomic, strong) NSString* ptf;
@property (nonatomic, strong) Calculate_View* view;

- (void) Calculation;

@end

NS_ASSUME_NONNULL_END

Calculate_Model.m

#import "Calculate_Model.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
@implementation Calculate_Model

int Compare (char ch) {
    if (ch == '(' || ch == ')') {
        return 0;
    } else if (ch == '+' || ch == '-') {
        return 1;
    } else if (ch == '*' || ch == '/' || ch == '!') {
        return 2;
    } else if (ch == '.') {
        return 3;
    } else {
        return -1;
    }
}
    
- (void) Calculation {
    
    //将NSString的对象a中的字符串转化为C语言中的字符串。
    const char* Cstring = [self.str1 UTF8String];
    //使用了strdup函数来复制Cstring字符串到另一个内存区域。
    self.str = strdup(Cstring);
    
    char stack1[1000];
    int Top1 = -1;
    char charstack[1000];
    int charTop = -1;

    int i = 0;
    int len = (int) strlen (self.str);
    while (i < len) {
        if (_str[i] >= '0' && _str[i] <= '9') {
            stack1[++Top1] = _str[i++];
            if (_str[i] < '0' || _str[i] > '9') {
                stack1[++Top1] = ' ';
            }
        } else if (_str[i] == '(') {
            charstack[++charTop] = _str[i++];
        } else if (_str[i] == ')') {
            while (charstack[charTop] != '(') {
                stack1[++Top1] = charstack[charTop--];
                stack1[++Top1] = ' ';
            }
            
            if (stack1[Top1-1] == '-') {
                stack1[Top1-1] = '!';
            }
            
            charTop--;
            i++;
        } else {
            if (Compare(_str[i]) > Compare(charstack[charTop]) || charTop == -1) {
                charstack[++charTop] = _str[i++];
                
            } else {
                while (Compare(charstack[charTop]) >= Compare(_str[i]) && charTop != -1) {
                    stack1[++Top1] = charstack[charTop--];
                    stack1[++Top1] = ' ';
                }
                charstack[++charTop] = _str[i++];
            }
        }
    }
    while (charTop != -1) {
        stack1[++Top1] = charstack[charTop--];
        stack1[++Top1] = ' ';
    }
    stack1[++Top1] = '\0';
    printf("%s", stack1);
    printf("\n");
    
    double realstack[1000];
    int realtop = -1;//初始化一个栈来存储数字
    i = 0;
    double x = 0;
    while (i < Top1) {
        if (stack1[i] >= '0' && stack1[i] <= '9') {
            while (stack1[i] >= '0' && stack1[i] <= '9') {
                x = x * 10 + stack1[i] - '0';
                i++;//获取多位数
            }
            realstack[++realtop] = x;
            x = 0;
            i++;
        } else if (stack1[i] == '+') {
            double b = realstack[realtop--];
            double a = realstack[realtop--];
            double c = a + b;
            realstack[++realtop] = c;
            i = i+2;
        } else if (stack1[i] == '-') {
            double b = realstack[realtop--];
            double a = realstack[realtop--];
            double c = a - b;
            realstack[++realtop] = c;
            i = i+2;
        } else if (stack1[i] == '*') {
            double b = realstack[realtop--];
            double a = realstack[realtop--];
            double c = a * b;
            realstack[++realtop] = c;
            i = i+2;
        } else if (stack1[i] == '/') {
            double b = realstack[realtop--];
            double a = realstack[realtop--];
            double c = a / b;
            realstack[++realtop] = c;
            i = i+2;
        } else if (stack1[i] == '!') {
            double b = realstack[realtop--] ;
            double c = -b ;
            realstack[++realtop] = c;
            i = i+2;
        } else {
            double b = realstack[realtop--];
            double a = realstack[realtop--];
            int m = 0;
            int n = b;
            while (n > 0) {
                n /= 10;
                m++;
            }
            double c = a + b* pow(10, -m);
            realstack[++realtop] = c;
            i = i+2;
        }
    }
    printf("%lf ",realstack[0]);
    double num = realstack[0];
    int num1 = num;
    int n = 0;
    while (num1 - num > 0.01 || num - num1 > 0.01) {
        num = num*10;
        num1 = num;
        n++;
        if (n == 8) {
            break;
        }
    }
    
    self.ptf = [NSString stringWithFormat:@"%.*f", n, realstack[0]];
}

@end

** 注:在计算的时候我对表达式中的负号进行了一次判断,如果表示的是加减法,就直接进行运算,如果负号表示的是这个数为负数,就把负号改成!,并且在计算中加上关于!的运算。这样就可以区分符号是减号还是负号了。**

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值