如何在Swift中创建连接的滑块?

问题描述:

我想用3个垂直滑块创建一个控件。我希望滑块上的可拖动的点具有连接它们的线。有关如何去做这件事的任何建议?如何在Swift中创建连接的滑块?

+0

任何截图或代码,你试图做到这一点? –

您可以创建UIBezierPath,在CAShapeLayer中使用该路径,并将该图层作为子图层添加到您的视图的layer

唯一的问题是确定您的线条的开始点和结束点,可以通过查看滑块的thumbRectForBounds来完成。假设你使用的标准UISliderView并简单地旋转它,你应该确保给点转换到父的坐标系:

class ViewController: UIViewController { 

    @IBOutlet weak var slider1: UISlider! 
    @IBOutlet weak var slider2: UISlider! 
    @IBOutlet weak var slider3: UISlider! 

    lazy var lineLayer: CAShapeLayer = { 
     let layer = CAShapeLayer() 
     layer.lineWidth = 3 
     layer.fillColor = UIColor.clearColor().CGColor 
     layer.strokeColor = UIColor.redColor().CGColor 
     return layer 
    }() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     [slider1, slider2, slider3].forEach { slider in 
      slider.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI_2)) 
     } 

     view.layer.insertSublayer(lineLayer, atIndex: 0) 
    } 

    override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 

     lineLayer.frame = view.bounds 

     updatePathBetweenSliders() 
    } 

    @IBAction func didChangeValue(sender: UISlider) { 
     updatePathBetweenSliders() 
    } 

    private func updatePathBetweenSliders() { 
     let path = UIBezierPath() 
     path.moveToPoint(slider1.thumbCenter()) 
     path.addLineToPoint(slider2.thumbCenter()) 
     path.addLineToPoint(slider3.thumbCenter()) 
     lineLayer.path = path.CGPath 
    } 
} 

其中:

extension UISlider { 
    func thumbCenter() -> CGPoint { 
     let thumbRect = thumbRectForBounds(bounds, trackRect: trackRectForBounds(bounds), value: value) 
     let thumbCenter = CGPoint(x: thumbRect.midX, y: thumbRect.midY) 

     return convertPoint(thumbCenter, toView: superview) 
    } 
} 

国债收益率:

lines between sliders

如果你想在任何时候对滑块进行动画处理(就像我在动画GIF结束时那样),你可能不得不重新排序到CADisplayLink更新值:

let animationDuration = 0.5 
var originalValues: [Float]! 
var targetValues: [Float]! 
var startTime: CFAbsoluteTime! 

@IBAction func didTapResetButton(sender: UIButton) { 
    let sliders = [slider1, slider2, slider3] 

    originalValues = sliders.map { $0.value } 
    targetValues = sliders.map { _ in Float(0.5) } 

    startTime = CFAbsoluteTimeGetCurrent() 
    let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:))) 
    displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes) 
} 

func handleDisplayLink(displayLink: CADisplayLink) { 
    let percent = Float((CFAbsoluteTimeGetCurrent() - startTime)/animationDuration) 
    let sliders = [slider1, slider2, slider3] 

    if percent < 1 { 
     for (index, slider) in sliders.enumerate() { 
      slider.value = (targetValues[index] - originalValues[index]) * percent + originalValues[index] 
     } 
    } else { 
     for (index, slider) in sliders.enumerate() { 
      slider.value = targetValues[index] 
     } 
     displayLink.invalidate() 
    } 

    updatePathBetweenSliders() 
} 
+0

谢谢。这非常有用。我很好奇 - 有没有办法做到这一点,而不使用transform属性?转换不遵守autol ayout,因此难以清洁地定位这些垂直滑块。我试图把它们放在堆栈视图中,但我试图获得我想要的大小时遇到​​了各种问题。 – kubernetes

+0

我试图把它们放在堆栈视图中,发现在涉及到转换时会变得更加复杂。我使用带有自动布局的转换滑块呈现了上述内容,并且它的工作令人惊讶(尽管故事板看起来很奇怪)。不过,你确定也可以制作自己的垂直滑块控件,因为它并不复杂。我确信有第三方的垂直滑块控件,虽然我没有真正看过,当然也不能担保。 – Rob