ios - 调整 RangeSlider 最小值、最大值、下限值和上限值?
问题描述
我按照 Raywenderlich 网站 ( https://www.raywenderlich.com/7595-how-to-make-a-custom-control-tutorial-a-reusable-slider ) 上的教程来创建自定义范围滑块。我执行的步骤如下:
(1) 创建一个 swift 文件并在其中添加以下代码:
import UIKit
class RangeSlider: UIControl {
override var frame: CGRect {
didSet {
updateLayerFrames()
}
}
private var previousLocation = CGPoint()
var minimumValue: CGFloat = 0 {
didSet {
updateLayerFrames()
}
}
var maximumValue: CGFloat = 1 {
didSet {
updateLayerFrames()
}
}
var lowerValue: CGFloat = 0.2 {
didSet {
updateLayerFrames()
}
}
var upperValue: CGFloat = 0.8 {
didSet {
updateLayerFrames()
}
}
var trackTintColor = UIColor(white: 0.9, alpha: 1) {
didSet {
trackLayer.setNeedsDisplay()
}
}
var trackHighlightTintColor = UIColor(red: 0, green: 0.45, blue: 0.94, alpha: 1) {
didSet {
trackLayer.setNeedsDisplay()
}
}
var thumbImage = #imageLiteral(resourceName: "Oval") {
didSet {
upperThumbImageView.image = thumbImage
lowerThumbImageView.image = thumbImage
updateLayerFrames()
}
}
var highlightedThumbImage = #imageLiteral(resourceName: "HighlightedOval") {
didSet {
upperThumbImageView.highlightedImage = highlightedThumbImage
lowerThumbImageView.highlightedImage = highlightedThumbImage
updateLayerFrames()
}
}
private let trackLayer = RangeSliderTrackLayer()
private let lowerThumbImageView = UIImageView()
private let upperThumbImageView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
trackLayer.rangeSlider = self
trackLayer.contentsScale = UIScreen.main.scale
layer.addSublayer(trackLayer)
lowerThumbImageView.image = thumbImage
addSubview(lowerThumbImageView)
upperThumbImageView.image = thumbImage
addSubview(upperThumbImageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func updateLayerFrames() {
CATransaction.begin()
CATransaction.setDisableActions(true)
trackLayer.frame = bounds.insetBy(dx: 0.0, dy: bounds.height / 3)
trackLayer.setNeedsDisplay()
lowerThumbImageView.frame = CGRect(origin: thumbOriginForValue(lowerValue),size: thumbImage.size)
upperThumbImageView.frame = CGRect(origin: thumbOriginForValue(upperValue),size: thumbImage.size)
CATransaction.commit()
}
func positionForValue(_ value: CGFloat) -> CGFloat {
return bounds.width * value
}
private func thumbOriginForValue(_ value: CGFloat) -> CGPoint {
let x = positionForValue(value) - thumbImage.size.width / 2.0
return CGPoint(x: x, y: (bounds.height - thumbImage.size.height) / 2.0)
}
}
extension RangeSlider {
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
previousLocation = touch.location(in: self)
if lowerThumbImageView.frame.contains(previousLocation) {
lowerThumbImageView.isHighlighted = true
} else if upperThumbImageView.frame.contains(previousLocation) {
upperThumbImageView.isHighlighted = true
}
return lowerThumbImageView.isHighlighted || upperThumbImageView.isHighlighted
}
override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
let location = touch.location(in: self)
let deltaLocation = location.x - previousLocation.x
let deltaValue = (maximumValue - minimumValue) * deltaLocation / bounds.width
previousLocation = location
if lowerThumbImageView.isHighlighted {
lowerValue += deltaValue
lowerValue = boundValue(lowerValue, toLowerValue: minimumValue, upperValue: upperValue)
} else if upperThumbImageView.isHighlighted {
upperValue += deltaValue
upperValue = boundValue(upperValue, toLowerValue: lowerValue, upperValue: maximumValue)
}
sendActions(for: .valueChanged)
return true
}
private func boundValue(_ value: CGFloat, toLowerValue lowerValue: CGFloat, upperValue: CGFloat) -> CGFloat {
return min(max(value, lowerValue), upperValue)
}
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
lowerThumbImageView.isHighlighted = false
upperThumbImageView.isHighlighted = false
}
}
(2) 然后我在我的项目中创建了另一个 Swift 文件,并按照上述教程在其中添加了以下代码:
import UIKit
class RangeSliderTrackLayer: CALayer {
weak var rangeSlider: RangeSlider?
override func draw(in ctx: CGContext) {
guard let slider = rangeSlider else {
return
}
let path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
ctx.addPath(path.cgPath)
ctx.setFillColor(slider.trackTintColor.cgColor)
ctx.fillPath()
ctx.setFillColor(slider.trackHighlightTintColor.cgColor)
let lowerValuePosition = slider.positionForValue(slider.lowerValue)
let upperValuePosition = slider.positionForValue(slider.upperValue)
let rect = CGRect(x: lowerValuePosition, y: 0, width: upperValuePosition - lowerValuePosition, height: bounds.height)
ctx.fill(rect)
}
}
(3) 最后一步,是我在 ViewController 中创建了一个自定义 Range Slider 类的实例,我有兴趣在里面实现 RangeSlider:
import UIKit
class FilterDataVC: UIViewController {
let rangeSlider = RangeSlider(frame: .zero)
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(rangeSlider)
rangeSlider.addTarget(self, action: #selector(rangeSliderValueChanged(_:)), for: .valueChanged)
}
override func viewDidLayoutSubviews() {
let margin: CGFloat = 20
let width = view.bounds.width - 2 * margin
let height: CGFloat = 30
rangeSlider.frame = CGRect(x: 0, y: 0, width: width, height: height)
rangeSlider.center = view.center
}
@objc func rangeSliderValueChanged(_ rangeSlider: RangeSlider) {
let values = "(\(rangeSlider.lowerValue) \(rangeSlider.upperValue))"
}
到目前为止,一切都完美无缺,我获得了与教程相同的结果。但是,显然我需要为自己的 App 自定义 RangeSlider。因此,我尝试通过将上面步骤 01 中所述的代码部分更改为下图所示的部分来更改滑块的 minimumValue、maximumValue、lowerValue 和 upperValue:
var minimumValue: CGFloat = 100 {
didSet {
updateLayerFrames()
}
}
var maximumValue: CGFloat = 1200 {
didSet {
updateLayerFrames()
}
}
var lowerValue: CGFloat = 200 {
didSet {
updateLayerFrames()
}
}
var upperValue: CGFloat = 800 {
didSet {
updateLayerFrames()
}
}
但是,在进行了上述修改后,并使用模拟器运行了我的应用程序。RangeSlider 只显示轨道,我看不到拇指。知道出了什么问题吗?
解决方案
我设法通过调整上面步骤 01 中所述的部分代码来解决我的问题,如下所述:
func positionForValue(_ value: CGFloat) -> CGFloat {
return (bounds.width * value) / (maximumValue - minimumValue)
}
推荐阅读
- random - 如何测量和显示Processing中按键的响应时间?
- php - php - 将单个数组值合并到一个数组中
- log4j2 - Log4j2 自定义过滤器不起作用获取过滤器包含无效的元素或属性
- asp.net-mvc - Azure B2C 和多租户 - 实施的最佳实践
- android - QT 应用程序在 Android 10 设备上的 std::thread 析构函数处崩溃
- docker - Docker 容器中的 Docker
- jquery - 在 div 元素上切换类处于活动状态,并将切换元素的值设置为下拉菜单中的选定选项
- java - Java FilenameExtensionFilter 无法正常工作
- r - 参考 POSIXct 格式时间区分高峰和非高峰流量时段
- mysql - 如何解决“ERROR 1215 (HY000): 无法添加外键约束”