Icon

RVS_Checkbox

简介

本项目是 Apple 提供的传统 UISwitch 的健壮、纯 Swift、高质量的“直接替换”方案。 它派生自 UISwitch,并提供几乎与 UISwitch 相同的 API。

它被实现为 单个源文件,没有依赖项。

集成到您的应用程序非常简单,只需在 Interface Builder 中添加一个 UIView,并将其指定为 RVS_Checkbox,或创建 RVS_Checkbox 的一个实例即可。

解决了什么问题?

经典的 UISwitch

The Standard UISwitch Control

是一个很棒的 UI 元素,用于代替 Mac 的经典 “复选框”

The Standard Mac Checkbox Control

在 iOS UI 的“胖手指”世界中,它实际上效果不太好。

那么,问题是什么?

问题在于 UISwitch 是一个大型的、形状相当笨拙的元素。 它是“菱形”的,并且始终是水平的,因此在将其安装到 UI 中时可能需要一些创造力。 此外,它具有特定的设计美学,并且很难自定义(公平地说,Apple 不鼓励我们自定义任何 UI,所以这并不奇怪)。

由于控件的水平特性,将标签放在左侧是相当“自然的”:一个开关,标签在左侧

...或者右侧

A Switch, With the Label on the Right

但是将其放在开关下方看起来“笨拙”

A Switch, With the Label on the Bottom

如果您使用“标签按钮”(就像我一样)更是如此(运行测试工具即可看到它们的实际效果)。 另外,滑块外观似乎要求滑动姿势,而不是点击姿势(这才是我们真正想要的),这也有些“奇怪”。 这意味着该姿势还需要一些“心理准备”。 RVS_Checkbox 允许正方形外观和无方向(点击)动作,就像常规复选框一样。

UISwitch 还具有严格的“二进制”动作。 如果您有三个选择,则应该使用 UISegmentedControl,这实际上非常合理。 Apple 显然对他们的 UX 进行了大量研究,并且有充分的理由。 移动界面充其量只是一种折衷。

为什么 RVS_Checkbox 可以解决这个问题?

很高兴您问了这个问题。 RVS_Checkbox 带有两种“内置”外观:一个默认的圆形复选框,以及一个相当“经典”的外观,它使用内置的 SF Symbols 来模仿 Mac 复选框的显示方式。

您还可以添加自己的图像。

图像很简单。 它们始终以 “模板”模式渲染,因此它们是“轮廓”,并由控件的色调着色。

此外,RVS_Checkbox 将 Mac 中的“三态”复选框引入 iOS。 这意味着可以具有“OFF”、“ON”和“不确定”模式(我称之为“CLEAR”)。 默认外观是圆形复选框,默认模式是“二进制”,就像 UISwitch 一样。

以下是图像的外观(颜色由控件的 tintColor 属性控制)

  默认 SF 符号 用户提供
The Default Image for the ON State. The SF Symbols Image for the ON State. An Example Customer-Supplied Image for the ON State.
The Default Image for the OFF State. The SF Symbols Image for the OFF State. An Example Customer-Supplied Image for the OFF State.
清除 The Default Image for the CLEAR State. The SF Symbols Image for the CLEAR State. An Example Customer-Supplied Image for the CLEAR State.

“DEFAULT”和“SF SYMBOLS”图像已“烘焙到”类中,而“USER-PROVIDED”图像是在情节提要中添加的三个任意图像(您可以在测试工具中看到这些图像)。

图像将随控件一起调整大小,但会保留其纵横比(纵横比填充模式)。

注意:目前,图像必须是单色模板图像。 这不是最佳的,我们将考虑支持全彩色图像。

要求

RVS_Checkbox 是一个 iOS/iPadOS 专用的 UIKit/Cocoa Touch 框架 UIControl,专为 Swift 语言应用程序设计。

它专为本机 Swift iOS 应用程序开发而设计。

这需要 iOS/iPadOS 13.0 或以上版本。

依赖项

该模块没有依赖项。 如果您要运行 测试工具,则还需要加载 RVS_Generic_Swift_Toolbox 项目。 同样,使用此软件包不是必需的。 仅用于测试工具!

安装

该控件以 Swift Package Manager 软件包的形式提供,并且可以使用 Carthage 进行安装。 您也可以简单地将 该项目 直接从本地存储库拖到您自己的项目中,甚至只需包含 单个源文件(我喜欢将这些类型项目的源文件数量保持在最低限度)。

Swift Package Manager

您应该与 SPM 一起包含的存储库是 git@github.com:RiftValleySoftware/RVS_Checkbox.git

可以通过直接编辑 Package.swift 文件,或使用项目 GUI 添加软件包

直接将软件包添加到单个目标

Step 1: Add A Package

步骤 1:在主项目的“Swift Packages”选项卡中,选择“+”按钮以添加软件包。

Step 2: Enter the URI

步骤 2:在弹出的模式屏幕中,输入 GitHub URI:git@github.com:RiftValleySoftware/RVS_Checkbox.git

Step 3: Enter the Version

步骤 3:输入当前版本(如果您使用了 URI,则已经设置了)。

Step 4: Add the Package to Your Target

步骤 4:将软件包添加到您的目标。 此时,您只能将软件包添加到单个目标。

将软件包添加到另一个目标

如果已经导入了该软件包,您现在可以像任何其他框架一样使用它,并且可以使用“通用”选项卡手动将其添加到任何目标

Step 5: Adding to A Target

步骤 5:在“通用”选项卡中将软件包添加到目标。

Step 6: Selecting the Framework

步骤 6:选择导入的框架。

包含软件包或库之后

此时,您需要在将访问它的 Swift 源文件中导入该模块

import RVS_Checkbox

Carthage

如果您正在使用 Carthage,则应将以下行添加到您的 Cartfile

github "RiftValleySoftware/RVS_Checkbox"

然后,打开“终端”并导航到项目目录的顶部,然后在“终端”中输入以下内容

carthage update

它将在与 Cartfile 相同的级别创建一个名为“Carthage”的目录。 在此目录中,将有另一个名为“Checkouts”的目录。 在该目录中,将有另一个名为“RVS_Checkbox”的目录。 您要进入“Sources/RVS_Checkout”并访问 RVS_Checkbox.swift 文件。 将其拖到您的项目中,并将其与您的应用程序构建目标相关联。

The Carthage Checkouts Directory

直接访问 GitHub 仓库

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

如果我们使用Interface Builder来实现RVS_Checkbox的实例,我们首先在IB中打开我们的视图控制器,然后点击右上角的“+”按钮。

The Add New Element Button

这将打开一个模态屏幕,允许我们选择要添加的元素类型。

我们应该选择一个通用的UIView (View)对象。

Add View

将其拖到视图控制器中(1),并按照您喜欢的方式排列它。然后选择它,并选择“Identity Inspector”选项卡。选择后,输入RVS_Checkbox作为对象类(2)。

如果我们使用Swift Package Manager添加该类,我们应该将“Module”字段设置为“RVS_Checkbox”(3)。否则,我们应该选中“Inherit Module From Target”复选框,并让应用程序模块被选择。

Set Class and Module

最后,我们应该选择“Properties Inspector”,并将各种可检查的属性设置为我们想要的值。

Set Class Properties

注意: 在撰写本指南时,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项目。它展示了我们如何在屏幕底部创建三个动态实例化的复选框。

结果是这样的显示效果:

The Dynamic Display

选项

有许多选项可用于自定义控件的工作方式。

这些选项在Interface Builder和编程中都可用。

三态(默认关闭)

此选项的文档

控件可以在两种模式下运行

两态(默认)

这是复选框的默认操作。它有两种状态:OFF或ON(值为0或1)。

三态

如果我们将useThreeState复选框选项设置为ON,则控件有三种状态:OFF (-1),CLEAR (0) 和 ON (1)。CLEAR可以用作“不确定”状态,并且在连续驱动控件时(OFF-CLEAR-ON或ON-CLEAR-OFF),在其他两种状态之间选择。

使用SF Symbols(默认关闭)

此选项的文档

如果此选项为ON(默认为OFF),则控件将显示近似于Mac复选框的图像。

如果选择了此项,则忽略“Use OFF Image for CLEAR”选项(因为Mac复选框有一种特定的工作方式,并且它们已经这样做了)。

将OFF图像用于CLEAR(默认关闭)

此选项的文档

如果选择此项(默认为OFF),那么,在默认外观或自定义图像外观中,用于三态“OFF”状态的图像将用于两态“CLEAR”(也为OFF)。

这对于三态或使用SF Symbol外观将被忽略。

使用触感反馈 (默认开启)

此选项的文档

默认情况下,控件使用与UISwitch相同的微妙触感反馈。如果关闭此选项,则不使用触感反馈。

即使开启此选项,以编程方式设置值时也不会使用触感反馈。

图像

可以覆盖内置图像并添加您自己的图像。

OFF图像

此选项的文档

CLEAR图像

此选项的文档

ON图像

此选项的文档

复选框状态

复选框始终处于某种状态:OFF、CLEAR或ON。如果在两态模式下,则OFF和CLEAR是同义词。

可以通过checkboxState属性(使用RVS_Checkbox.States枚举),或者通过value属性(使用整数-1、0或1)来访问状态。您可以修改其中任何一个,控件都会改变其状态*(**注意:**以编程方式更改控件状态不会发送操作消息或触发触感反馈)*

value属性允许您以数字方式影响控件状态。负数将为OFF(或CLEAR,如果在两态模式下)。0为CLEAR,正数为ON。

它具有与UISwitch具有的相同的isOn属性。

此外,它还具有isOffisClear(它与两态模式下的isOff相同)。

UISwitch一样,它具有一个setOn(_:Bool,animated:Bool)方法。 它也具有setClear

不支持

RVS_CheckboxUISwitch有两个主要区别:它不支持onTintColorthumbTintColor

它也不支持Mac Catalyst的Mac风格复选框功能。这将在Mac Catalyst中工作,但与在iOS中完全相同的方式。

测试应用

The Test Harness App Screen

虽然不是实现RVS_Checkbox所必需的,但Test Harness App对于演示其功能并为使用该控件提供指导非常有用。

强烈建议,如果您对RVS_Checkbox的实现有任何疑问或疑虑,请首先运行测试工具并检查其代码库。

该应用程序本身非常简单。它是一个单屏幕iOS应用程序,可在iPod、iPhone和iPad上运行。

它是一个基于UIKit的应用程序,使用情节提要Interface Builder)。

这是GitHub代码仓库中Test Harness App的位置

应用程序构建目标

App Targets

除了框架目标(RVS_Checkbox)之外,还有四个应用程序目标。所有目标都共享源代码,但Direct和Carthage目标除外。它们使用相同的源代码,但使用单独的情节提要。这是因为它们对RVS_Checkbox的实现直接编译到应用程序中,因此没有单独的模块。

RVS_Checkbox_Test_Harness (Direct)

此目标直接将RVS_Checkbox.swift文件导入到项目中,没有包管理器或库/框架。该文件在应用程序命名空间中编译。

RVS_Checkbox_Test_Harness (Framework)

此目标使用内置的 RVS_Checkbox 动态框架目标来构建框架,并将该动态库导入到项目中。

RVS_Checkbox_Test_Harness (SPM)

此目标使用 Swift Package ManagerGitHub 上的位置导入包。 这是在您的项目中采用 RVS_Checkbox 的首选方法。

RVS_Checkbox_Test_Harness (Carthage)

此目标使用 GitHub CarthageGitHub 上的位置获取包。 然后它直接将 RVS_Checkbox.swift 文件Carthage 目录包含到项目中,而无需库/框架。 该文件在应用程序命名空间中编译。

应用程序运行方案

App Schemes

每个目标都有四个运行方案。

依赖关系和要求

根据不同的目标,RVS_Checkbox 框架/源文件可能是一个依赖项。

所有目标都依赖于 RVS_Generic_Swift_Toolbox,使用 Swift Package Manager