RangeSliderView.swift 7.05 KB
//
//  RangeSliderView.swift
//  Twear
//
//  Created by yangbin on 2021/11/18.
//

import UIKit


struct SliderRange {
    var index: Int = 0
    var range: Range<CGFloat> = 0..<0.1
    var stopX: CGFloat = 0
    var value: Double = 0
}

protocol RangeSliderDelegate: NSObjectProtocol {
    func sliderDidChanged(index: Int)
//    func didClickInLabel(cell: ZCImageNewsTableCell, label: YYLabel, textRange: NSRange)
//    func didClickInteractButton(cell: ZCImageNewsTableCell, sender: BadgeNumButton)
    
}

class RangeSliderView: UIView {
    
    weak var delegate: RangeSliderDelegate?
    
    @IBOutlet weak var leftConstraint: NSLayoutConstraint!
    @IBOutlet weak var selectedView: UIButton!
    
    private var startPointX: CGFloat = 0
    private var endPointX: CGFloat = 0
    private var scaleRanges: [SliderRange] = []
    private var selectedIndex: Int = -1    
    private lazy var panGesture: UIPanGestureRecognizer = {
        let pan = UIPanGestureRecognizer(target: self, action: #selector(sliderPanGestureChange(_:)))
        return pan
    }()
    private lazy var tapGesture: UITapGestureRecognizer = {
        let tap = UITapGestureRecognizer(target: self, action: #selector(sliderTapGestureChange(_:)))
        return tap
    }()
    private var touchOffsetX: CGFloat = 0
    
    
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        initFromNib()
        setupUI()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        initFromNib()
        setupUI()
    }
    
    private func initFromNib() {
        if let view = Bundle.main.loadNibNamed("RangeSliderView", owner: self, options: nil)?.first as? UIView {
            view.frame = bounds
            self.addSubview(view)
        }
    }
    
    
    private func setupUI() {
        touchOffsetX = selectedView.frame.size.width/2
        
        selectedView.addGestureRecognizer(panGesture)
        selectedView.addGestureRecognizer(tapGesture)
    }
    
//    func setDrawSpace1(startPointX: CGFloat, endPointX: CGFloat, count: Int, startPanX: CGFloat = 0, endPanX: CGFloat = 0, imageName: String = "slider_green") {
//        selectedView.setImage(UIImage(named: imageName), for: .normal)
//        selectedView.setImage(UIImage(named: imageName), for: .highlighted)
////        layoutIfNeeded()
//        guard count > 0 else {
//            return
//        }
//        let w = selectedView.frame.size.width/2
//        self.startPointX = startPointX-w
//        self.endPointX = endPointX-w
//        var scale: CGFloat = 0.5
//        var rangeLen: CGFloat = 0
//        if count > 1 {
//            rangeLen = (endPointX - startPointX) / CGFloat(count-1)
//            scale = rangeLen/2.0
//        }
//
//        scaleRanges = []
//
//        for i in 0..<count {
//            var r = SliderRange()
//            r.index = i
//            r.range = startPointX-w+(CGFloat(i)*rangeLen)-scale..<startPointX-w+(CGFloat(i)*rangeLen)+scale
//            r.stopX = startPointX+(CGFloat(i)*rangeLen)-w
//            scaleRanges.append(r)
//        }
//        if startPanX != 0 && endPanX != 0 {
//            setPanRange(start: startPanX-w-scale, end: endPanX-w+scale)
//        }
//
//
////      0   1   2   3   4
////      10              80
//    }
//
    func setDrawSpace(startPointX: CGFloat, endPointX: CGFloat, range: ClosedRange<Int>, points: [Double], imageName: String, isLast: Bool = false) {
        selectedView.setImage(UIImage(named: imageName), for: .normal)
        selectedView.setImage(UIImage(named: imageName), for: .highlighted)
        let w = selectedView.frame.size.width/2
        scaleRanges = []
        guard points.count > 0 else {
            leftConstraint.constant = startPointX-w
            return
        }
        
        let rangeValue = range.upperBound - range.lowerBound
        let scaleLen: CGFloat = (endPointX - startPointX)/CGFloat(rangeValue)
        
        if points.count == 1 {
            let point = points[0]
            var r = SliderRange()
            r.stopX = startPointX-w+point*scaleLen
            r.value = point
            scaleRanges.append(r)
        } else {
            for (i, point) in points.enumerated() {
                var r = SliderRange()
                let stopX = startPointX-w+point*scaleLen
                r.stopX = stopX
                r.index = i
                r.value = point
                if point == points.first {
                    let firstScale = (points[1]-points[0])/2 * scaleLen
                    r.range = stopX-firstScale-20..<stopX+firstScale
                    self.startPointX = startPointX-w-firstScale-20
                } else if point == points.last {
                    let lastScale = (points[i]-points[i-1])/2 * scaleLen
                    r.range = stopX-lastScale..<stopX+lastScale+20
                    self.endPointX = endPointX-w-lastScale+20
                } else {
                    let preScale = (points[i]-points[i-1])/2 * scaleLen
                    let nextScale = (points[i+1]-points[i])/2 * scaleLen
                    r.range = stopX-preScale..<stopX+nextScale
                }
                scaleRanges.append(r)
            }
        }
        if isLast {
            didSelectedValue(points[points.count-1])
        } else {
            didSelectedValue(points[0])
        }
        
    }
    
    func setPanRange(start: CGFloat, end: CGFloat) {
        startPointX = start
        endPointX = end
    }
    
    func selectedIndex(_ index: Int) {
        for sRange in scaleRanges {
            if sRange.index == index {
                leftConstraint.constant = sRange.stopX
                delegate?.sliderDidChanged(index: index)
            }
        }
    }
    
    func didSelectedValue(_ value: Double) {
        for sRange in scaleRanges {
            if sRange.value == value {
                leftConstraint.constant = sRange.stopX
                delegate?.sliderDidChanged(index: sRange.index)
            }
        }
    }
    
    
    @objc
    private func sliderPanGestureChange(_ sender: UIPanGestureRecognizer) {
        var offsetX = sender.location(in: self).x
        if sender.state == .began {
            touchOffsetX = offsetX - selectedView.frame.origin.x
        }
        offsetX = offsetX - touchOffsetX
        if offsetX <= startPointX {
            return
        }
        if offsetX >= endPointX {
            return
        }

        for (i, sRange) in scaleRanges.enumerated() {
            if sRange.range.contains(offsetX) && selectedIndex != i {
                leftConstraint.constant = sRange.stopX
                selectedIndex = i
                delegate?.sliderDidChanged(index: i)
            }
        }
    }
    
    
    @objc
    private func sliderTapGestureChange(_ sender: UITapGestureRecognizer) {
//        print(sender.location(in: selectedView).x)

    }

    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

}