本项目是 Apple 提供的传统 UISwitch
的健壮、纯 Swift、高质量的“直接替换”方案。 它派生自 UISwitch
,并提供几乎与 UISwitch
相同的 API。
它被实现为 单个源文件,没有依赖项。
集成到您的应用程序非常简单,只需在 Interface Builder 中添加一个 UIView
,并将其指定为 RVS_Checkbox
,或创建 RVS_Checkbox
的一个实例即可。
经典的 UISwitch
是一个很棒的 UI 元素,用于代替 Mac 的经典 “复选框”
在 iOS UI 的“胖手指”世界中,它实际上效果不太好。
问题在于 UISwitch
是一个大型的、形状相当笨拙的元素。 它是“菱形”的,并且始终是水平的,因此在将其安装到 UI 中时可能需要一些创造力。 此外,它具有特定的设计美学,并且很难自定义(公平地说,Apple 不鼓励我们自定义任何 UI,所以这并不奇怪)。
...或者右侧
但是将其放在开关下方看起来“笨拙”
如果您使用“标签按钮”(就像我一样)更是如此(运行测试工具即可看到它们的实际效果)。 另外,滑块外观似乎要求滑动姿势,而不是点击姿势(这才是我们真正想要的),这也有些“奇怪”。 这意味着该姿势还需要一些“心理准备”。 RVS_Checkbox
允许正方形外观和无方向(点击)动作,就像常规复选框一样。
UISwitch
还具有严格的“二进制”动作。 如果您有三个选择,则应该使用 UISegmentedControl
,这实际上非常合理。 Apple 显然对他们的 UX 进行了大量研究,并且有充分的理由。 移动界面充其量只是一种折衷。
很高兴您问了这个问题。 RVS_Checkbox
带有两种“内置”外观:一个默认的圆形复选框,以及一个相当“经典”的外观,它使用内置的 SF Symbols 来模仿 Mac 复选框的显示方式。
您还可以添加自己的图像。
图像很简单。 它们始终以 “模板”模式渲染,因此它们是“轮廓”,并由控件的色调着色。
此外,RVS_Checkbox
将 Mac 中的“三态”复选框引入 iOS。 这意味着可以具有“OFF”、“ON”和“不确定”模式(我称之为“CLEAR”)。 默认外观是圆形复选框,默认模式是“二进制”,就像 UISwitch
一样。
以下是图像的外观(颜色由控件的 tintColor
属性控制)
默认 | SF 符号 | 用户提供 | |
开 | ![]() |
![]() |
![]() |
关 | ![]() |
![]() |
![]() |
清除 | ![]() |
![]() |
![]() |
“DEFAULT”和“SF SYMBOLS”图像已“烘焙到”类中,而“USER-PROVIDED”图像是在情节提要中添加的三个任意图像(您可以在测试工具中看到这些图像)。
图像将随控件一起调整大小,但会保留其纵横比(纵横比填充模式)。
注意:目前,图像必须是单色模板图像。 这不是最佳的,我们将考虑支持全彩色图像。
RVS_Checkbox
是一个 iOS/iPadOS 专用的 UIKit
/Cocoa Touch 框架 UIControl,专为 Swift 语言应用程序设计。
它专为本机 Swift iOS 应用程序开发而设计。
该模块没有依赖项。 如果您要运行 测试工具,则还需要加载 RVS_Generic_Swift_Toolbox 项目。 同样,使用此软件包不是必需的。 仅用于测试工具!
该控件以 Swift Package Manager 软件包的形式提供,并且可以使用 Carthage 进行安装。 您也可以简单地将 该项目 直接从本地存储库拖到您自己的项目中,甚至只需包含 单个源文件(我喜欢将这些类型项目的源文件数量保持在最低限度)。
您应该与 SPM 一起包含的存储库是 git@github.com:RiftValleySoftware/RVS_Checkbox.git
。
可以通过直接编辑 Package.swift
文件,或使用项目 GUI 添加软件包
步骤 1:在主项目的“Swift Packages”选项卡中,选择“+”按钮以添加软件包。
步骤 2:在弹出的模式屏幕中,输入 GitHub URI:git@github.com:RiftValleySoftware/RVS_Checkbox.git
。
步骤 3:输入当前版本(如果您使用了 URI,则已经设置了)。
步骤 4:将软件包添加到您的目标。 此时,您只能将软件包添加到单个目标。
如果已经导入了该软件包,您现在可以像任何其他框架一样使用它,并且可以使用“通用”选项卡手动将其添加到任何目标
步骤 5:在“通用”选项卡中将软件包添加到目标。
步骤 6:选择导入的框架。
此时,您需要在将访问它的 Swift 源文件中导入该模块
import RVS_Checkbox
如果您正在使用 Carthage,则应将以下行添加到您的 Cartfile
github "RiftValleySoftware/RVS_Checkbox"
然后,打开“终端”并导航到项目目录的顶部,然后在“终端”中输入以下内容
carthage update
它将在与 Cartfile 相同的级别创建一个名为“Carthage
”的目录。 在此目录中,将有另一个名为“Checkouts
”的目录。 在该目录中,将有另一个名为“RVS_Checkbox
”的目录。 您要进入“Sources/RVS_Checkout
”并访问 RVS_Checkbox.swift
文件。 将其拖到您的项目中,并将其与您的应用程序构建目标相关联。
GitHub 仓库是 https://github.com/RiftValleySoftware/RVS_Checkbox
。
Git 克隆 URI 为 git@github.com:RiftValleySoftware/RVS_Checkbox.git
(SSH) 或 https://github.com/RiftValleySoftware/RVS_Checkbox.git
(HTTPS)。
您可以直接访问并克隆此代码仓库,或者将其作为Git子模块添加到您的项目中。
如果您这样做,请注意您只需要将**一个**文件添加到您的项目中:RVS_Checkbox.swift
文件。
建议您直接将此文件集成到您的项目中,而不是构建一个库。因为它只有一个源文件,直接集成是最简单的方法。
如果直接集成,则无需导入模块。RVS_Checkbox
类将直接在模块命名空间中可用。
此自述文件提供了主要的文档,但也有一个代码文档站点,可能对实现RVS_Checkbox
有所帮助。
要使用RVS_Checkbox
,我们需要在Interface Builder中添加它,或者以编程方式创建实例。
如果我们使用Interface Builder来实现RVS_Checkbox
的实例,我们首先在IB中打开我们的视图控制器,然后点击右上角的“+”按钮。
这将打开一个模态屏幕,允许我们选择要添加的元素类型。
我们应该选择一个通用的UIView
(View)对象。
将其拖到视图控制器中(1),并按照您喜欢的方式排列它。然后选择它,并选择“Identity Inspector”选项卡。选择后,输入RVS_Checkbox
作为对象类(2)。
如果我们使用Swift Package Manager添加该类,我们应该将“Module
”字段设置为“RVS_Checkbox
”(3)。否则,我们应该选中“Inherit Module From Target
”复选框,并让应用程序模块被选择。
最后,我们应该选择“Properties Inspector”,并将各种可检查的属性设置为我们想要的值。
注意: 在撰写本指南时,
IBDesignable
支持似乎在渲染控件时存在问题(请参阅“Designables Build Failed
”消息)。我会看看我能做些什么来解决这个问题。这不会阻止控件工作,它只会阻止它预览。
动态实例化并不困难。只需以与UIView
相同的方式创建RVS_Checkbox
的实例即可。
/* ################################################################## */
/**
This sets up the three checkboxes along the bottom of the screen.
We set up a center box, using SF Symbols, then add one to its left, using the default, and one to its right, using some custom images.
We use programmatic Auto-Layout for this.
*/
func setUpDynamicCheckBoxes() {
if let dynamicContainer = dynamicContainer { // Make sure we have the container.
let gap: CGFloat = 8
let dynamicControlSize: CGFloat = 64
let testImageFormat = "TestImage-%d"
let centerDynamicCheckbox = RVS_Checkbox() // Create the instance
dynamicContainer.addSubview(centerDynamicCheckbox) // Add it to the container.
centerDynamicCheckbox.backgroundColor = .clear // Nothing behind us (Just to be sure).
centerDynamicCheckbox.tintColor = checkboxObject?.tintColor // We steal the tint color from the IB-instantiated checkbox.
centerDynamicCheckbox.isUsingSFSymbols = true
centerDynamicCheckbox.isThreeState = true
centerDynamicCheckbox.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
centerDynamicCheckbox.centerXAnchor.constraint(equalTo: dynamicContainer.centerXAnchor, constant: 0),
centerDynamicCheckbox.widthAnchor.constraint(equalToConstant: dynamicControlSize),
centerDynamicCheckbox.heightAnchor.constraint(equalToConstant: dynamicControlSize)
])
let leftDynamicCheckbox = RVS_Checkbox()
dynamicContainer.addSubview(leftDynamicCheckbox)
leftDynamicCheckbox.backgroundColor = .clear
leftDynamicCheckbox.tintColor = checkboxObject?.tintColor
leftDynamicCheckbox.isThreeState = true
leftDynamicCheckbox.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
leftDynamicCheckbox.trailingAnchor.constraint(equalTo: centerDynamicCheckbox.leadingAnchor, constant: -gap),
leftDynamicCheckbox.widthAnchor.constraint(equalToConstant: dynamicControlSize),
leftDynamicCheckbox.heightAnchor.constraint(equalToConstant: dynamicControlSize)
])
let rightDynamicCheckbox = RVS_Checkbox()
dynamicContainer.addSubview(rightDynamicCheckbox)
rightDynamicCheckbox.backgroundColor = .clear
rightDynamicCheckbox.tintColor = checkboxObject?.tintColor
rightDynamicCheckbox.offImage = UIImage(named: String(format: testImageFormat, 0))
rightDynamicCheckbox.clearImage = UIImage(named: String(format: testImageFormat, 1))
rightDynamicCheckbox.onImage = UIImage(named: String(format: testImageFormat, 2))
rightDynamicCheckbox.isThreeState = true
rightDynamicCheckbox.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
rightDynamicCheckbox.leadingAnchor.constraint(equalTo: centerDynamicCheckbox.trailingAnchor, constant: gap),
rightDynamicCheckbox.widthAnchor.constraint(equalToConstant: dynamicControlSize),
rightDynamicCheckbox.heightAnchor.constraint(equalToConstant: dynamicControlSize)
])
}
}
上面的代码片段直接取自Test Harness项目。它展示了我们如何在屏幕底部创建三个动态实例化的复选框。
结果是这样的显示效果:
有许多选项可用于自定义控件的工作方式。
这些选项在Interface Builder和编程中都可用。
控件可以在两种模式下运行
这是复选框的默认操作。它有两种状态:OFF或ON(值为0或1)。
如果我们将useThreeState
复选框选项设置为ON,则控件有三种状态:OFF (-1),CLEAR (0) 和 ON (1)。CLEAR可以用作“不确定”状态,并且在连续驱动控件时(OFF-CLEAR-ON或ON-CLEAR-OFF),在其他两种状态之间选择。
如果此选项为ON(默认为OFF),则控件将显示近似于Mac复选框的图像。
如果选择了此项,则忽略“Use OFF Image for CLEAR”选项(因为Mac复选框有一种特定的工作方式,并且它们已经这样做了)。
如果选择此项(默认为OFF),那么,在默认外观或自定义图像外观中,用于三态“OFF”状态的图像将用于两态“CLEAR”(也为OFF)。
这对于三态或使用SF Symbol外观将被忽略。
默认情况下,控件使用与UISwitch
相同的微妙触感反馈。如果关闭此选项,则不使用触感反馈。
即使开启此选项,以编程方式设置值时也不会使用触感反馈。
可以覆盖内置图像并添加您自己的图像。
复选框始终处于某种状态:OFF、CLEAR或ON。如果在两态模式下,则OFF和CLEAR是同义词。
可以通过checkboxState
属性(使用RVS_Checkbox.States
枚举),或者通过value
属性(使用整数-1、0或1)来访问状态。您可以修改其中任何一个,控件都会改变其状态*(**注意:**以编程方式更改控件状态不会发送操作消息或触发触感反馈)*
value
属性允许您以数字方式影响控件状态。负数将为OFF(或CLEAR,如果在两态模式下)。0为CLEAR,正数为ON。
它具有与UISwitch
具有的相同的isOn
属性。
此外,它还具有isOff
和isClear
(它与两态模式下的isOff
相同)。
与UISwitch
一样,它具有一个setOn(_:Bool,animated:Bool)
方法。 它也具有setClear
。
RVS_Checkbox
与UISwitch
有两个主要区别:它不支持onTintColor
或thumbTintColor
。
它也不支持Mac Catalyst的Mac风格复选框功能。这将在Mac Catalyst中工作,但与在iOS中完全相同的方式。
虽然不是实现RVS_Checkbox
所必需的,但Test Harness App对于演示其功能并为使用该控件提供指导非常有用。
强烈建议,如果您对RVS_Checkbox
的实现有任何疑问或疑虑,请首先运行测试工具并检查其代码库。
该应用程序本身非常简单。它是一个单屏幕iOS应用程序,可在iPod、iPhone和iPad上运行。
它是一个基于UIKit
的应用程序,使用情节提要(Interface Builder)。
这是GitHub代码仓库中Test Harness App的位置
除了框架目标(RVS_Checkbox)之外,还有四个应用程序目标。所有目标都共享源代码,但Direct和Carthage目标除外。它们使用相同的源代码,但使用单独的情节提要。这是因为它们对RVS_Checkbox
的实现直接编译到应用程序中,因此没有单独的模块。
此目标直接将RVS_Checkbox.swift
文件导入到项目中,没有包管理器或库/框架。该文件在应用程序命名空间中编译。
此目标使用内置的 RVS_Checkbox 动态框架目标来构建框架,并将该动态库导入到项目中。
此目标使用 Swift Package Manager 从 GitHub 上的位置导入包。 这是在您的项目中采用 RVS_Checkbox
的首选方法。
此目标使用 GitHub Carthage 从 GitHub 上的位置获取包。 然后它直接将 RVS_Checkbox.swift
文件从 Carthage
目录包含到项目中,而无需库/框架。 该文件在应用程序命名空间中编译。
每个目标都有四个运行方案。
根据不同的目标,RVS_Checkbox
框架/源文件可能是一个依赖项。
所有目标都依赖于 RVS_Generic_Swift_Toolbox
包,使用 Swift Package Manager。