一个 Swift 中的自定义 UIView,提供一个简单的摇杆界面。该自定义视图由两个 UIImageView 实例组成,一个用于底座,一个用于手柄。当用户移动手柄时,它会根据其相对于摇杆底座的位置报告一个值。报告的信息类型取决于安装的监听器类型。
let monitor: JoyStickViewPolarMonitor = {
print("\(String(format: "%.2f°", $0.angle)) \(String(format: "%.3f", $0.displacement))")
}
joystick.monitor = .polar(monitor: monitor2)
自 3.0.1 起,还支持使用 Objective-C 代码块作为监听器,但类型安全性略有降低。setPolarMonitor
和 setXYMonitor
都接受一个闭包,该闭包接受两个 CGFloat
参数,并且不返回值。Objective-C 代码块和 Swift 闭包都可以用于这些方法。自 3.1.0 起,还有一个 tappedBlock
属性,可用于在用户点击摇杆手柄时接收通知。
该视图支持一个选项 (movable),当用户将手柄移动到超过 1.0 的位移时,该视图将移动。当应用程序中摇杆的初始位置对于用户的手指不理想时,这很有用。双击摇杆会将其移回原始位置。
在上面的动画中,有两个摇杆,一个是绿色的,一个是洋红色的。绿色摇杆是固定的,即使触摸动作导致大于 1.0 的位移也不会移动。然而,洋红色摇杆是可移动的,底座跟随触摸动作。对于可移动的摇杆,底座的运动可以选择限制在 movableBounds 属性中的 CGRect
中,就像上面的演示动画中那样,洋红色摇杆无法移出粉红色条带。
以下是 JoyStickView 的一些其他可配置功能:
CGRect
,用于约束手柄的移动范围。有关示例,请参见 playground。0.85
。movable
为 true,则允许用户双击视图将底座移动到原始位置。.absolute
(默认值) 时,手柄将移动到初始(受约束)的按下位置。当设置为 .relative
时,手柄只有在触摸移动后才会移动。handlePositionMode
属性来控制如何报告手柄移动。默认行为是 .absolute
。新的 .relative
模式在初始触摸时提供更精细的控制(感谢 Michael Tyson)tappedBlock
属性(感谢 Michael Tyson)scaleHandleImageView
中过度缩放的问题Xcode 工作区包含三个组件:
import BRHJoyStickView
而不是 import JoyStickView
)playground 和应用程序都依赖于 JoyStickView UIView 的框架。
⚠️ 注意: 由于 CocoaPods 的管道,在 Xcode 中编辑时,请打开工作区 JoyStickView.xcworkspace,而不是项目 JoyStickView.xcodeproj。
Xcode playground 代码设置了显示环境并安装了两个摇杆,一个是固定的(绿色),另一个是可移动的(黄色)。两个摇杆都在两个标签中报告它们的位置,一个用于角度,另一个用于位移。
JoyStickView.swift 文件定义了摇杆视图和行为。它位于 JoyStickView Swift 包中,以及 CocoaPods 中的 BRHJoyStickView 框架中。在那里你还会找到一个名为 CoreGraphics+Additions.swift 的文件,它包含一些 CoreGraphics 结构体的各种扩展,这些扩展允许 JoyStickView 代码中一些简化的数学表达式。
默认情况下,JoyStickView 类使用在 Assets 容器中找到的两个图像资源。文件夹
handleTintColor
设置进行着色两者都以三种分辨率存在,适用于当今的各种 iOS 设备。它们是使用强大的 Opacity 应用程序生成的。Opacity 文档包含在本仓库的 Resources 目录中,用于 JoyStickViewApp
演示应用程序。
要使用你自己的图像,只需使用你想使用的 UIImage
设置 baseImage
和/或 handleImage
属性。
请参阅 代码文档 获取更多信息。
有一个简单的 CocoaPods 规范文件可用,因此你可以通过将 "BRHJoyStickView" 添加到你的 Podfile
文件并使用 import BRHJoyStickView
导入来添加代码和资源。目前,一切或多或少都可以工作,除了通过 Interface Builder (IB) 指向图像资源将导致无效的 UImage 结果,因为这些文件将无法在 IB 能够找到它们的地方找到。唯一的解决方案是手动定位这些文件并在你的视图加载代码中设置它们。类似以下的内容应该会有所帮助:
extension Bundle {
/**
Locate an inner Bundle generated from CocoaPod packaging.
- parameter name: the name of the inner resource bundle. This should match the "s.resource_bundle" key or
one of the "s.resoruce_bundles" keys from the podspec file that defines the CocoPod.
- returns: the resource Bundle or `self` if resource bundle was not found
*/
func podResource(name: String) -> Bundle {
guard let bundleUrl = self.url(forResource: name, withExtension: "bundle") else { return self }
return Bundle(url: bundleUrl) ?? self
}
}
在你的设置代码中,你需要做类似这样的事情:
override func viewDidLoad() {
super.viewDidLoad()
let bundle = Bundle(for: JoyStickView.self).podResource(name: "BRHJoyStickView")
joystick.baseImage = UIImage(named: "FancyBase", in: bundle, compatibleWith: nil)
joystick.handleImage = UIImage(named: "FancyHandle", in: bundle, compatibleWith: nil)
}
podResource
方法尝试定位一个命名的内部 bundle,如果找不到,则默认为原始 bundle。viewDidLoad
代码将然后在 UIImage 构造函数中使用正确的 bundle
对象。