iOS-如何使用单独的UIView控制UISlider的thumbRect

时间:2019-06-04 19:13:07

标签: ios swift uiview uigesturerecognizer uislider

我按下了一个按钮,并且自定义警报出现,其中带有 normal UISlider。我还有一些其他视图和标签,它们显示滑块上方和下方的距离等。发生的情况是,触摸滑块的thumbRect不能很好地滑动。尝试滑动时必须非常准确,而且似乎有问题。我想做的是在其前面(及其上方的其他视图和标签)添加一个清晰的UIView,并使用UIGestureRecognizer让清晰的UIView来控制滑块。

这是到目前为止的设置。我想使用clearView来控制滑块。现在,它位于一切后面,并且我将clearView涂成红色,以便在示例中可见

enter image description here

bgView.addSubview(slider) // slider added to bgView
let trackRect = slider.trackRect(forBounds: slider.frame)
let thumbRect = slider.thumbRect(forBounds: slider.bounds, trackRect: trackRect, value: slider.value)
milesLabel.center = CGPoint(x: thumbRect.midX, y: slider.frame.origin.y - 55)
bg.addSubview(milesLabel) // milesLabel added to bgView

// ** all the other views you see are added to the bgView and aligned with the thumbRect's center **

let milesLabelRect = bgView.convert(milesLabel.frame, to: self.view)
let sliderRect = bgView.convert(slider.frame, to: self.view)

let topOfMilesLabel = milesLabelRect.origin.y
let bottomOfSlider = sliderRect.maxY
let distance = bottomOfSlider - topOfMilesLabel

clearView.frame = CGRect(x: milesLabel.frame.minX, y: milesLabel.frame.minY, width: milesLabel.frame.width, height: distance)
bgView.addSubview(clearView) // clearView added to bgView
bgView.insertSubview(clearView, at: 0)

当我滑动滑块时,包括clearView在内的所有内容都可以成功滑动,但是thumbRect当然仍然可以控制一切。

enter image description here

@objc func onSliderValChanged(sender: UISlider, event: UIEvent) {

    slider.value = round(sender.value)
    UIView.animate(withDuration: 0.25, animations: {
        self.slider.layoutIfNeeded()

        let trackRect = sender.trackRect(forBounds: sender.frame)
        let thumbRect = sender.thumbRect(forBounds: sender.bounds, trackRect: trackRect, value: sender.value)
        self.milesLabel.center = CGPoint(x: thumbRect.midX, y: sender.frame.origin.y - 55)

        // ** all the other views are aligned with the thumbRect's center as it slides **

        self.clearView.frame.origin = self.milesLabel.frame.origin
    })
}

这个想法是将clearView移到所有内容的最前面,并使用它来控制thumbRect(请记住,示例中它只是红色)。

bgView.bringSubviewToFront(clearView)
// clearView.backgroundColor = UIColor.clear

enter image description here

我尝试使用UIPanGestureUILongPressGestureRecognizer来让clearView来控制滑块,但是当我滑动滑块时,只有thumbRect会滑动,clearView保持静止。看一下clearView(红色)在哪里,然后将thumbRect滑到10英里点后看看。

enter image description here

// separately tried a UILongPressGestureRecognizer too
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(draggedView(_:)))
clearView.isUserInteractionEnabled = true
clearView.addGestureRecognizer(panGesture)

@objc func draggedView(_ sender: UIPanGestureRecognizer) {

    if slider.isHighlighted { return }

    let point = sender.location(in: slider)
    let percentage = Float(point.x / slider.frame.width)
    let delta = percentage * (slider.maximumValue - slider.minimumValue)
    let value = slider.minimumValue + delta
    slider.setValue(value, animated: true)
}

如果我玩够了,clearView有时会用thumbRect滑动,但是它们肯定没有对齐,这非常容易出错。我也失去了所有与thumbRect对齐的其他视图的控制。

如何将控件从滑块的thumbRect传递给clearView?

2 个答案:

答案 0 :(得分:0)

您可能会决定要这样做,这没关系。但是我为您提供了一种可能适合您需要的快速替代方法。

如果您将播放滑块归类并覆盖point()方法,则可以增加滑块拇指的表面积。

class CustomPlaybackSlider: UISlider {

    // Will increase target surface area for thumb.
    override public func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        var bounds: CGRect = self.bounds
        // Set the inset to a negative value by how much you want the surface area to increase by.
        bounds = bounds.insetBy(dx: -10, dy: -15)
        return bounds.contains(point)
    }

}

可能会为您简化事情。不过,这种方法的唯一缺点是,触摸的表面积对于dx值将同样向下/向上扩展,对于dy值将同样向左/右侧扩展。

希望这会有所帮助。

答案 1 :(得分:0)

我在this answer中找到了解决此问题的关键。 @PaulaHasstenteufel说

// also remember to call valueChanged if there's any
// custom behaviour going on there and pass the slider
// variable as the parameter, as indicated below
self.sliderValueChanged(slider)

我要做的是

  1. 使用UIPanGestureRecognizer
  2. 评论UISlider的目标动作
  3. 在第4步中使用目标操作的选择器方法中的代码,而不是在@objc func onSliderValChanged(sender: UISlider, event: UIEvent { }中使用它
  4. 从第3步中获取代码,并将其添加到新功能中
  5. 将步骤5中的功能添加到UIPanGetstureRecognizer方法的底部

1-使用UIPanGestureRecognizer并为UIView启用userInteraction

let panGesture = UIPanGestureRecognizer(target: self, action: #selector(draggedView(_:)))
clearView.isUserInteractionEnabled = true
clearView.addGestureRecognizer(panGesture)

2-滑块,我将其注释为.valueChanged事件的addTarget

let slider: UISlider = {
    let slider = UISlider()
    slider.translatesAutoresizingMaskIntoConstraints = false
    slider.minimumValue = 1
    slider.maximumValue = 5
    slider.value = 1
    slider.isContinuous = true
    slider.maximumTrackTintColor = UIColor(white: 0, alpha: 0.3)

    // ** COMMENT THIS OUT **
    //slider.addTarget(self, action: #selector(onSliderValChanged(sender:event:)), for: .valueChanged)

    return slider
}()

3-从上面的targetAction所使用的选择器方法中获取代码,然后在步骤4中插入该代码

@objc func onSliderValChanged(sender: UISlider, event: UIEvent) {

    /*
    use this code in step-4 instead

    slider.value = round(sender.value)

    UIView.animate(withDuration: 0.25, animations: {
        self.slider.layoutIfNeeded()

        let trackRect = sender.trackRect(forBounds: sender.frame)
        let thumbRect = sender.thumbRect(forBounds: sender.bounds, trackRect: trackRect, value: sender.value)
        self.milesLabel.center = CGPoint(x: thumbRect.midX, y: sender.frame.origin.y - 55)

        // ** all the other views are aligned with the thumbRect's center as it slides **

        self.clearView.frame.origin = self.milesLabel.frame.origin
    })
    */
}

4-创建一个新方法并插入步骤3中的代码

func sliderValueChanged(_ sender: UISlider, value: Float) {

    // round the value for smooth sliding
    sender.value = round(value)

    UIView.animate(withDuration: 0.25, animations: {
        self.slider.layoutIfNeeded()

        let trackRect = sender.trackRect(forBounds: sender.frame)
        let thumbRect = sender.thumbRect(forBounds: sender.bounds, trackRect: trackRect, value: sender.value)
        self.milesLabel.center = CGPoint(x: thumbRect.midX, y: sender.frame.origin.y - 55)

        // ** all the other views are aligned with the thumbRect's center as it slides **

        self.clearView.frame.origin = self.milesLabel.frame.origin
    })
}

5-我使用了与UIGestureRecognizer相同的代码,但是注释掉了setValue函数,而是使用了第4步中的函数

@objc fileprivate func draggedView(_ sender: UIPanGestureRecognizer) {

    if slider.isHighlighted { return }

    let point = sender.location(in: slider)
    let percentage = Float(point.x / slider.bounds.size.width)
    let delta = percentage * (slider.maximumValue - slider.minimumValue)
    let value = slider.minimumValue + delta

    // I had to comment this out because the siding was to abrupt
    //slider.setValue(value, animated: true) 

    // ** CALLING THIS FUNCTION FROM STEP-3 IS THE KEY TO GET THE UIView TO CONTROL THE SLIDER **
    sliderValueChanged(slider, value: value)
}