如何在Swift中实现范围滑块

我试图实现范围滑块和我使用自定义控件称为NMRangeSlider 。

但是当我使用它时,滑块完全不会出现。 难道这也是因为它都是用Objective-C编写的吗?

这是我目前实现它的方式:

var rangeSlider = NMRangeSlider(frame: CGRectMake(16, 6, 275, 34)) rangeSlider.lowerValue = 0.54 rangeSlider.upperValue = 0.94 self.view.addSubview(rangeSlider) 

更新:

它没有显示给我,因为它全是白色的。 所以这个解决scheme,没有使用任何其他的框架,坚持使用这个 – 你需要为所有的组件设置所有的视图,然后它会显示:

在这里输入图像说明


我试图在Swift中导入它,因为我之前在Objective-C代码中使用它,但没有任何运气。 如果我正确地设置了一切,并将其添加到viewDidLoad()viewDidAppear() ,则不会显示任何内容。 值得一提的是,当我进入View Debug Hierarchy时 ,滑块实际上在canvas上:

在这里输入图像说明

但是在添加到视图中之前,我们并没有使用所有的颜色来渲染它。 logging – 这是我使用的代码:

 override func viewDidAppear(animated: Bool) { var rangeSlider = NMRangeSlider(frame: CGRectMake(50, 50, 275, 34)) rangeSlider.lowerValue = 0.54 rangeSlider.upperValue = 0.94 let range = 10.0 let oneStep = 1.0 / range let minRange: Float = 0.05 rangeSlider.minimumRange = minRange let bgImage = UIView(frame: rangeSlider.frame) bgImage.backgroundColor = .greenColor() rangeSlider.trackImage = bgImage.pb_takeSnapshot() let trackView = UIView(frame: CGRectMake(0, 0, rangeSlider.frame.size.width, 29)) trackView.backgroundColor = .whiteColor() trackView.opaque = false trackView.alpha = 0.3 rangeSlider.trackImage = UIImage(named: "") let lowerThumb = UIView(frame: CGRectMake(0, 0, 8, 29)) lowerThumb.backgroundColor = .whiteColor() let lowerThumbHigh = UIView(frame: CGRectMake(0, 0, 8, 29)) lowerThumbHigh.backgroundColor = UIColor.blueColor() rangeSlider.lowerHandleImageNormal = lowerThumb.pb_takeSnapshot() rangeSlider.lowerHandleImageHighlighted = lowerThumbHigh.pb_takeSnapshot() rangeSlider.upperHandleImageNormal = lowerThumb.pb_takeSnapshot() rangeSlider.upperHandleImageHighlighted = lowerThumbHigh.pb_takeSnapshot() self.view.addSubview(rangeSlider) self.view.backgroundColor = .lightGrayColor() } 

使用这个问题中提到的UIImage捕获UIView的方法:

 extension UIView { func pb_takeSnapshot() -> UIImage { UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.mainScreen().scale) drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } } 

其他解决scheme

你也可以尝试使用sgwilly / RangeSlider ,它是用Swift写的,所以你甚至不需要桥接头。

为了创build一个自定义的范围滑块,我在这里find了一个很好的解决scheme: 范围查找器教程iOS 8,但我需要在SWIFT 3我的项目。 我在这里更新了Swift 3 iOS 10的这个:

  1. 在你的主视图控制器添加到viewDidLayOut显示范围滑块。

     override func viewDidLayoutSubviews() { let margin: CGFloat = 20.0 let width = view.bounds.width - 2.0 * margin rangeSlider.frame = CGRect(x: margin, y: margin + topLayoutGuide.length + 170, width: width, height: 31.0) } 
  2. 创build助手函数来打印滑块输出viewDidLayoutSubviews()

     func rangeSliderValueChanged() { //rangeSlider: RangeSlider print("Range slider value changed: \(rangeSlider.lowerValue) \(rangeSlider.upperValue) ")//(\(rangeSlider.lowerValue) \(rangeSlider.upperValue)) } 
  3. 创build文件RangeSlider.swift并将其添加到它:

     import UIKit import QuartzCore class RangeSlider: UIControl { var minimumValue = 0.0 var maximumValue = 1.0 var lowerValue = 0.2 var upperValue = 0.8 let trackLayer = RangeSliderTrackLayer()//= CALayer() defined in RangeSliderTrackLayer.swift let lowerThumbLayer = RangeSliderThumbLayer()//CALayer() let upperThumbLayer = RangeSliderThumbLayer()//CALayer() var previousLocation = CGPoint() var trackTintColor = UIColor(white: 0.9, alpha: 1.0) var trackHighlightTintColor = UIColor(red: 0.0, green: 0.45, blue: 0.94, alpha: 1.0) var thumbTintColor = UIColor.white var curvaceousness : CGFloat = 1.0 var thumbWidth: CGFloat { return CGFloat(bounds.height) } override init(frame: CGRect) { super.init(frame: frame) trackLayer.rangeSlider = self trackLayer.contentsScale = UIScreen.main.scale layer.addSublayer(trackLayer) lowerThumbLayer.rangeSlider = self lowerThumbLayer.contentsScale = UIScreen.main.scale layer.addSublayer(lowerThumbLayer) upperThumbLayer.rangeSlider = self upperThumbLayer.contentsScale = UIScreen.main.scale layer.addSublayer(upperThumbLayer) } required init?(coder: NSCoder) { super.init(coder: coder) } func updateLayerFrames() { trackLayer.frame = bounds.insetBy(dx: 0.0, dy: bounds.height / 3) trackLayer.setNeedsDisplay() let lowerThumbCenter = CGFloat(positionForValue(value: lowerValue)) lowerThumbLayer.frame = CGRect(x: lowerThumbCenter - thumbWidth / 2.0, y: 0.0, width: thumbWidth, height: thumbWidth) lowerThumbLayer.setNeedsDisplay() let upperThumbCenter = CGFloat(positionForValue(value: upperValue)) upperThumbLayer.frame = CGRect(x: upperThumbCenter - thumbWidth / 2.0, y: 0.0, width: thumbWidth, height: thumbWidth) upperThumbLayer.setNeedsDisplay() } func positionForValue(value: Double) -> Double { return Double(bounds.width - thumbWidth) * (value - minimumValue) / (maximumValue - minimumValue) + Double(thumbWidth / 2.0) } override var frame: CGRect { didSet { updateLayerFrames() } } override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { previousLocation = touch.location(in: self) // Hit test the thumb layers if lowerThumbLayer.frame.contains(previousLocation) { lowerThumbLayer.highlighted = true } else if upperThumbLayer.frame.contains(previousLocation) { upperThumbLayer.highlighted = true } return lowerThumbLayer.highlighted || upperThumbLayer.highlighted } func boundValue(value: Double, toLowerValue lowerValue: Double, upperValue: Double) -> Double { return min(max(value, lowerValue), upperValue) } override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { let location = touch.location(in: self) // 1. Determine by how much the user has dragged let deltaLocation = Double(location.x - previousLocation.x) let deltaValue = (maximumValue - minimumValue) * deltaLocation / Double(bounds.width - thumbWidth) previousLocation = location // 2. Update the values if lowerThumbLayer.highlighted { lowerValue += deltaValue lowerValue = boundValue(value: lowerValue, toLowerValue: minimumValue, upperValue: upperValue) } else if upperThumbLayer.highlighted { upperValue += deltaValue upperValue = boundValue(value: upperValue, toLowerValue: lowerValue, upperValue: maximumValue) } // 3. Update the UI CATransaction.begin() CATransaction.setDisableActions(true) updateLayerFrames() CATransaction.commit() sendActions(for: .valueChanged) return true } override func endTracking(_ touch: UITouch?, with event: UIEvent?) { lowerThumbLayer.highlighted = false upperThumbLayer.highlighted = false } } 
  4. 接下来添加拇指层子类文件RangeSliderThumbLayer.swift并将其添加到它:

      import UIKit class RangeSliderThumbLayer: CALayer { var highlighted = false weak var rangeSlider: RangeSlider? override func draw(in ctx: CGContext) { if let slider = rangeSlider { let thumbFrame = bounds.insetBy(dx: 2.0, dy: 2.0) let cornerRadius = thumbFrame.height * slider.curvaceousness / 2.0 let thumbPath = UIBezierPath(roundedRect: thumbFrame, cornerRadius: cornerRadius) // Fill - with a subtle shadow let shadowColor = UIColor.gray ctx.setShadow(offset: CGSize(width: 0.0, height: 1.0), blur: 1.0, color: shadowColor.cgColor) ctx.setFillColor(slider.thumbTintColor.cgColor) ctx.addPath(thumbPath.cgPath) ctx.fillPath() // Outline ctx.setStrokeColor(shadowColor.cgColor) ctx.setLineWidth(0.5) ctx.addPath(thumbPath.cgPath) ctx.strokePath() if highlighted { ctx.setFillColor(UIColor(white: 0.0, alpha: 0.1).cgColor) ctx.addPath(thumbPath.cgPath) ctx.fillPath() } } } } 
  5. 最后添加轨道层子类文件RangeSliderTrackLayer.swift并添加以下内容:

      import Foundation import UIKit import QuartzCore class RangeSliderTrackLayer: CALayer { weak var rangeSlider: RangeSlider? override func draw(in ctx: CGContext) { if let slider = rangeSlider { // Clip let cornerRadius = bounds.height * slider.curvaceousness / 2.0 let path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius) ctx.addPath(path.cgPath) // Fill the track ctx.setFillColor(slider.trackTintColor.cgColor) ctx.addPath(path.cgPath) ctx.fillPath() // Fill the highlighted range ctx.setFillColor(slider.trackHighlightTintColor.cgColor) let lowerValuePosition = CGFloat(slider.positionForValue(value: slider.lowerValue)) let upperValuePosition = CGFloat(slider.positionForValue(value: slider.upperValue)) let rect = CGRect(x: lowerValuePosition, y: 0.0, width: upperValuePosition - lowerValuePosition, height: bounds.height) ctx.fill(rect) } } } 

build立运行并获取: 在这里输入图像说明

试试这个代码:

 override func viewDidLayoutSubviews() { let margin: CGFloat = 20.0 let width = view.bounds.width - 2.0 * margin rangeSlider.frame = CGRect(x: margin, y: margin + topLayoutGuide.length, width: width, height: 31.0) } 

我使用https://github.com/Zengzhihui/RangeSlider实现了范围滑块

在GZRangeSlider类中,有一个方法叫做:private func setLabelText()

在这个方法中,只要把:

leftTextLayer.frame = CGRectMake(leftHandleLayer.frame.minX – 0.5 *(kTextWidth – leftHandleLayer.frame.width),leftHandleLayer.frame.minY – kTextHeight,kTextWidth,kTextHeight)

rightTextLayer.frame = CGRectMake(rightHandleLayer.frame.minX – 0.5 *(kTextWidth – leftHandleLayer.frame.width),leftTextLayer.frame.minY,kTextWidth,kTextHeight)

为下部和上部标签制作animation

这个对我来说工作得很好,而且很快就能完成。