目录
一、开发环境
- 开发工具: Xcode 12.2(集成开发平台)、Simulator(模拟器,Xcode自带)
- 开发语言: Swift 5
- 界面搭建: Storyboard(故事板)
二、基础知识
1.往期知识点
2.简易自动布局——Stack View
Stack View(堆栈视图)类似于HTML的盒模型,你可以把它理解为一个容器。我们可以利用Stack View在水平(或垂直)方向堆叠多个子视图。
一个Stack View可以用来封装各种UI控件以及其他Stack View,通过添加对Stack View的约束(设置该View到父View的距离)可以实现UI控件的定位和布局。
1)添加Stack View
2)添加约束
3)查看约束
4)设置Stack View的属性
三、实验步骤
在MVC架构下,用故事板来开发一个简易计算器APP需要以下步骤:
应用界面的设计如下,要求计算器至少能实现整数和浮点数的加减乘除运算。
1.先在Xcode建立一个APP项目
2.界面搭建
1)打开Main.storyboard主故事板
同时,模拟器和View视图统一选择iPhone 8 Plus
通过Inspector设置Button的属性
将Button显示的文字“Button”修改为“1”,文字大小Font设置为30,文字颜色Text Color暂不修改
将Button的背景颜色Background修改为Yellow(或其他你喜欢的颜色)
修改Button的宽和高为50
3)添加容器
方法是按住鼠标左键框选要放入容器里的控件,完成后点击左下角的Stack View
可以看到Button1已经被放入Stack View里了:
一个比较快捷的方法是,框选你要复制的控件,然后按住option键往旁边拖拽
如果不清楚这个方法,一个Button一个容器地添加也可以,就是没上面的方法快。
5)为一行的Button添加容器
框选+Stack View
6) 继续往下添加Button
我们继续往下复制,总共需要4*5个Button。依然使用框选+按住option+拖拽的方法
7)把所有Button封装进一个容器
同时,也将Lable封装进一个Stack View
9)将Lable和Button都封装进一个容器中
到了这一步,所有的控件和容器都以添加完成。接下来要做的就是为各个容器添加约束,实现自动布局。
10)为最外层的Stack View设置约束
添加4条约束:将其上下左右四个方向的距离设置为0
11)设置包含所有Button的Stack View
这一步是实现自动约束的关键步骤,在左侧的Documen Outline中选择包含所有Button的Stack View,设置Stack View的属性
Alignment 设置为Fill,distribution设置为Fill Equally,Spacing设置为10
12)为每一行的Button添加约束
添加2个约束:左右距离为0
完成后结果如下:
显然,我们需要设置包含一行Button的Stack View的属性
13)设置包含一行Button的Stack View的属性
Alignment 设置为Fill,distribution设置为Fill Equally,Spacing设置为10
将所有包含一行Button的Stack View的属性Alignment 设置为Fill,distribution设置为Fill Equally,Spacing设置为10
14)设置Lable的高
15)修饰背景和UI控件
将Lable的文字设置为0,颜色Color设置为白色,文字大小Font设置为50
在Documen Outline中选择最外层的Stack View,将背景颜色Background设置为黑色
iOS支持特殊符号(例如π对应快捷键option+P,平方根对应快捷键option+V)
完成后:
到了这一步,页面的搭建就已经完成了,可以试运行一下,看看有没有bug。
3.连接控件与代码
添加一个新的窗口,同时打开主故事板和ViewController.swift页面
由于这里不需要viewDidLoad函数,直接删掉
将Lable连接到代码区:
将某个Button连接到代码区:
接着把所有Button都连接到touch代码块
通过鼠标悬停在代码区左侧的实心圆点上,可以查看连接的情况:
删除连接、重建连接请参考10 | 如何构建一个APP 的结尾部分
4.补充代码,完善功能
试运行一下,我们发现,每按一个数字键,之前的数字就被覆盖掉了,没办法显示2位及以上的数值。为了解决这个问题,我们采用下面的代码:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var display: UILabel!
@IBAction func touch(_ sender: UIButton) {
let digit = sender.currentTitle! //获取按钮值
let textIndisplay = display.text! //获取标签值
if let mathematicalSymbol = sender.currentTitle {
switch mathematicalSymbol {
case "0","1","2","3","4","5","6","7","8","9":
if textIndisplay != "0" {
display.text = textIndisplay + digit
} else {
display.text = digit
}
default:
break
}
}
}
}
通过Lable标签原来显示的数值textIndisplay与数字键代表的数值digit的拼接,实现了多位数字的显示。
2)继续完善代码
//
// ViewController.swift
// Calculator
//
// Created by Apple on 2021/12/5.
//
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var display: UILabel!
var num1: Double? //操作数1
var num2: Double? //操作数2
var ope: String? //运算符
var IsFloat = false //浮点运算标志位
var displayValue : Double {
get{
return Double(display.text!)!
}
set{
display.text = String(newValue)
}
}
@IBAction func touch(_ sender: UIButton) {
let digit = sender.currentTitle! //获取按钮值
let textIndisplay = display.text! //获取标签值
if let mathematicalSymbol = sender.currentTitle {
switch mathematicalSymbol {
case "0","9":
if textIndisplay != "0" {
display.text = textIndisplay + digit
} else {
display.text = digit
}
case "AC": display.text = "0"
case "π": display.text = String(Double.pi)
case "√": display.text = String(sqrt(displayValue))
case "sin": display.text = String(sin(displayValue))
case "+","-","*","/":
if textIndisplay.contains(".") {
IsFloat = true
}
self.ope = mathematicalSymbol //记录运算符
self.num1 = displayValue //记录操作数1
display.text = "0" //清空计算器显示
case "=":
if textIndisplay.contains(".") {
IsFloat = true
}
self.num2 = displayValue
display.text = calculation(num1: num1,num2: num2,ope: ope,IsFloat: IsFloat)
IsFloat = false
case ".":
if textIndisplay != "0" {
display.text = textIndisplay + digit
} else {
display.text = "0."
}
default:
break
}
}
}
//calculation:执行计算操作
func calculation(num1: Double?,num2: Double?,ope: String?,IsFloat: Bool) -> String {
if ope == nil {
return "EOF"
}
if num1 == nil || num2 == nil {
return "0"
}
var result: Double
switch ope {
case "+": result = num1! + num2!
case "-": result = num1! - num2!
case "*": result = num1! * num2!
case "/":
if(num1 != 0) {
result = num1! / num2!
}
else {
return "EOF"
}
default:
return "EOF"
}
if IsFloat {
return String(Float(result))
} else {
return String(Int(result))
}
}
}
不建议将整块代码直接负责到项目中,因为这有可能影响原来的(控件与代码的)连接。要么只复制代码中方法的实现部分;要么删除所有连接,重新连接控件与代码。
3)运行
如果发现模拟器旋转之后,APP的页面没有跟着旋转(没有变成横屏显示),那么可能是APP的配置文件关闭了旋转功能。下面介绍解决办法:
确保勾选了Landscape Left和Landscape Right
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。