iOS -Как иметь отдельный UIView взять под контроль thumbRect UISlider - PullRequest
0 голосов
/ 04 июня 2019

У меня есть кнопка, которую я нажимаю, и появляется пользовательское предупреждение с normal UISlider внутри него.У меня есть некоторые другие виды и метки, которые показывают расстояние и т. Д., Которые находятся выше и позади слайдера.Что происходит, так это то, что thumbRect слайдера не скользит хорошо при прикосновении.Я должен быть очень точным, когда пытаюсь сдвинуть его, и он кажется глючным.То, что я хочу сделать, это добавить чистый UIView перед ним (и другие виды и надписи над ним) и сделать так, чтобы чистый UIView управлял ползунком, используя UIGestureRecognizer.

Вот настройки до сих пор.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 на передний план и использовать его для управления большим пальцем (не забывайте, что для примера только красный).

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

enter image description here

Я пытался использовать UIPanGesture и UILongPressGestureRecognizer, чтобы 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.

Как передать управление с ползунка бегунка в clearView?

Ответы [ 2 ]

0 голосов
/ 05 июня 2019

Я нашел ключ к проблеме здесь в этот ответ .@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 и включите make userInteraction для UIView

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

2-ползунок, я прокомментировал, что это addTarget для события .valueChanged

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)
}
0 голосов
/ 04 июня 2019

Возможно, вы настроитесь на это, и это нормально. Но у меня есть для вас быстрая альтернатива, которая может удовлетворить ваши потребности.

Если вы создадите подкласс для своего ползунка воспроизведения и переопределите метод 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.

Надеюсь, это поможет.

...