基于Swift和UIKit的简易计算器(界面部分)

229 阅读3分钟

一、任务

初步了解的UIKit框架的基本组件和Swift语法,想尝试下综合使用。 下图是MAC上的简易计算器

截屏2022-05-04 下午9.58.35.png

想实现一个类似的计算器小应用

二、项目创建和第三方库引入

  1. 项目创建

截屏2022-05-04 下午11.24.07.png 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

安装成功后会提醒你重新打开项目

截屏2022-05-04 下午10.15.47.png

这里要点击.xcworkspace结尾的文件打开项目才行,目录结构如下图

截屏2022-05-04 下午7.19.37.png

在需要的类中import SnapKit就可以使用了

cocoapods用于管理引入第三方库的,ruby写的。想要了解的可以参考 CocoapodsCocoapods Guide

三、布局划分

如图可以将计算机界面拆解为三部分

截屏2022-05-04 下午10.32.12.png

1部分为显示板screen部分

2部分为操作板board部分

3部分为操作funcbutton按钮

四、封装

  1. 按钮组件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")

    }

}
  1. 操作面板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))

    }

    

}
  1. 显示面板部分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协议的类

  1. 需要给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))

    }
  1. 在使用的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。 这是一个简单的单页面应用,尝试了横屏竖屏适配、封装独立视图控件、视图控件交互传值。

运行效果如图

截屏2022-05-04 下午11.14.10.png