【问题标题】:UISlider in swift like youtube appUISlider 像 youtube 应用程序一样快速
【发布时间】:2015-08-11 15:34:29
【问题描述】:

我可以创建一个自定义 UISlider,它像 Youtube 应用程序中的那样具有缓冲进度吗?我知道这个问题可能是重复的;但没有人能正确解决 iOS 或 Swift 中的问题

谢谢

【问题讨论】:

  • 你可以创建任何你能想象到的自定义控件,所以是的,你可以,如果这是你的问题的话。

标签: ios swift uislider


【解决方案1】:

您需要子类UIControl 并在drawRect: 中绘制三层——一层用于背景线,第二层用于缓冲线,第三层用于进度,具体取决于当前进度和可用缓冲区值。示例:

class MySlider: UIControl
{
    var currentPosition : Float = 0.0
    {
        didSet
        {
            updateLayers()
        }
    }

    var currentBuffer : Float = 0.0
    {
        didSet
        {
            updateLayers()
        }
    }

    var backgroundLayerColor : UIColor = UIColor.lightGrayColor()
    var progressLayerColor : UIColor = UIColor.redColor()
    var bufferLayerColor : UIColor = UIColor.darkGrayColor()
    var positionRingLayerColor : UIColor = UIColor.redColor()

    private var backgroundLayer : CAShapeLayer!
    private var progressLayer : CAShapeLayer!
    private var bufferLayer : CAShapeLayer!
    private var positionRingLayer : CAShapeLayer!

    override init(frame: CGRect)
    {
        super.init(frame: frame)
        initialize()
    }

    required init(coder aDecoder: NSCoder)
    {
        super.init(coder: aDecoder)
        initialize()
    }

    override func drawRect(rect: CGRect)
    {
        updateLayers()
    }

    private func initialize()
    {
        self.backgroundColor = UIColor.clearColor()

        backgroundLayer = CAShapeLayer()
        backgroundLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
        backgroundLayer.path = UIBezierPath(rect: CGRect(x: 0, y: (self.frame.size.height / 2) - self.frame.size.height / 4, width: self.frame.size.width, height: self.frame.size.height / 2.0)).CGPath
        backgroundLayer.fillColor = backgroundLayerColor.CGColor
        backgroundLayer.backgroundColor = UIColor.clearColor().CGColor

        progressLayer = CAShapeLayer()
        progressLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)

        bufferLayer = CAShapeLayer()
        bufferLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)

        positionRingLayer = CAShapeLayer()
        positionRingLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)

        self.layer.addSublayer(backgroundLayer)
        self.layer.addSublayer(bufferLayer)
        self.layer.addSublayer(progressLayer)
        self.layer.addSublayer(positionRingLayer)

        updateLayers()
    }

    private func updateLayers()
    {
        updateProgressLine()
        updateBufferLine()
        updatePositionRing()
    }

    private func updateProgressLine()
    {
        var w = (self.frame.size.width * CGFloat(currentPosition)) + self.frame.size.height / 4

        if w > self.frame.size.width
        {
            w = self.frame.size.width
        }

        progressLayer.path = UIBezierPath(rect: CGRect(x: 0, y: (self.frame.size.height / 2) - self.frame.size.height / 4, width: w, height: self.frame.size.height / 2)).CGPath
        progressLayer.fillColor = progressLayerColor.CGColor
        progressLayer.backgroundColor = UIColor.clearColor().CGColor
    }

    private func updateBufferLine()
    {
        var w = self.frame.size.width * CGFloat(currentBuffer)

        bufferLayer.path = UIBezierPath(rect: CGRect(x: 0, y: (self.frame.size.height / 2) - self.frame.size.height / 4, width: w, height: self.frame.size.height / 2)).CGPath
        bufferLayer.fillColor = bufferLayerColor.CGColor
        bufferLayer.backgroundColor = UIColor.clearColor().CGColor
    }

    private func updatePositionRing()
    {
        var _x = self.frame.size.width * CGFloat(currentPosition)

        if _x > self.frame.size.width - self.frame.size.height
        {
            _x = self.frame.size.width - self.frame.size.height
        }

        positionRingLayer.path = UIBezierPath(ovalInRect: CGRect(x: _x, y: 0, width: self.frame.size.height, height: self.frame.size.height)).CGPath
        positionRingLayer.fillColor = positionRingLayerColor.CGColor
        positionRingLayer.backgroundColor = UIColor.clearColor().CGColor
    }

    override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool
    {
        super.continueTrackingWithTouch(touch, withEvent: event)
        let point = touch.locationInView(self)

        var _xb = (self.frame.size.width * CGFloat(currentBuffer)) - self.frame.size.height
        if (point.x < _xb) && (point.x > 0)
        {
            currentPosition = Float(point.x / self.frame.size.width)
            self.setNeedsDisplay()
        }
        return true
    }
}

在某些视图控制器中:

let slider = MySlider(frame: CGRect(x: 50, y: 100, width: 200, height: 30))
self.view.addSubview(slider)
slider.currentPosition = 0.3
slider.currentBuffer = 0.7

结果:

【讨论】:

    【解决方案2】:

    有效! 我添加了一个协议来处理组件的滚动以具有类似于 UISlider 的行为

    public protocol SliderDelegate {
        func SliderBeginDragging(slider: bufferdSlider)
        func SliderEndDragging(slider: bufferdSlider)
        func SliderScrub(slider: bufferdSlider)
    }
    
    public enum ScrollState: Int, Printable {
    case BeginDragging = 0
    case EndDragging
    case scrub
        public var description: String {
            get {
                switch self {
                case BeginDragging:
                    return "BeginDragging"
                case EndDragging:
                    return "EndDragging"
                case scrub:
                    return "Scrub"
                }
            }
        }
    }
    
    public class  bufferdSlider: UIControl
    {
        public var sliderDelegate: SliderDelegate!
        var currentPosition : Float = 0.0
        {
            didSet
            {
                updateLayers()
            }
        }
        var currentBuffer : Float = 0.0
        {
            didSet
            {
                updateLayers()
            }
        }
        var backgroundLayerColor : UIColor = UIColor.lightGrayColor()
        var progressLayerColor : UIColor = UIColor.redColor()
        var bufferLayerColor : UIColor = UIColor.darkGrayColor()
        var positionRingLayerColor : UIColor = UIColor.redColor()
        private var backgroundLayer : CAShapeLayer!
        private var progressLayer : CAShapeLayer!
        private var bufferLayer : CAShapeLayer!
        private var positionRingLayer : CAShapeLayer!
    
    
        override init(frame: CGRect)
        {
            super.init(frame: frame)
            initialize()
        }
    
        required public init(coder aDecoder: NSCoder)
        {
            super.init(coder: aDecoder)
            initialize()
        }
    
        override public func drawRect(rect: CGRect)
        {
            updateLayers()
        }
    
        private func initialize()
        {
            self.backgroundColor = UIColor.clearColor()
    
            backgroundLayer = CAShapeLayer()
            backgroundLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
            backgroundLayer.path = UIBezierPath(rect: CGRect(x: 0, y: (self.frame.size.height / 2) - self.frame.size.height / 4, width: self.frame.size.width, height: self.frame.size.height / 2.0)).CGPath
            backgroundLayer.fillColor = backgroundLayerColor.CGColor
            backgroundLayer.backgroundColor = UIColor.clearColor().CGColor
            progressLayer = CAShapeLayer()
            progressLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
            bufferLayer = CAShapeLayer()
            bufferLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
            positionRingLayer = CAShapeLayer()
            positionRingLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
            self.layer.addSublayer(backgroundLayer)
            self.layer.addSublayer(bufferLayer)
            self.layer.addSublayer(progressLayer)
            self.layer.addSublayer(positionRingLayer)
            updateLayers()
        }
    
        private func updateLayers()
        {
            updateProgressLine()
            updateBufferLine()
            updatePositionRing()
        }
    
        private func updateProgressLine()
        {
            var w = (self.frame.size.width * CGFloat(currentPosition)) + self.frame.size.height / 4
    
            if w > self.frame.size.width
            {
                w = self.frame.size.width
            }
    
            progressLayer.path = UIBezierPath(rect: CGRect(x: 0, y: (self.frame.size.height / 2) - self.frame.size.height / 4, width: w, height: self.frame.size.height / 2)).CGPath
            progressLayer.fillColor = progressLayerColor.CGColor
            progressLayer.backgroundColor = UIColor.clearColor().CGColor
        }
    
        private func updateBufferLine()
        {
            var w = self.frame.size.width * CGFloat(currentBuffer)
    
            bufferLayer.path = UIBezierPath(rect: CGRect(x: 0, y: (self.frame.size.height / 2) - self.frame.size.height / 4, width: w, height: self.frame.size.height / 2)).CGPath
            bufferLayer.fillColor = bufferLayerColor.CGColor
            bufferLayer.backgroundColor = UIColor.clearColor().CGColor
        }
    
        private func updatePositionRing()
        {
            var _x = self.frame.size.width * CGFloat(currentPosition)
    
            if _x > self.frame.size.width - self.frame.size.height
            {
                _x = self.frame.size.width - self.frame.size.height
            }
    
            positionRingLayer.path = UIBezierPath(ovalInRect: CGRect(x: _x, y: 0, width: self.frame.size.height, height: self.frame.size.height)).CGPath
            positionRingLayer.fillColor = positionRingLayerColor.CGColor
            positionRingLayer.backgroundColor = UIColor.clearColor().CGColor
        }
    
        override public func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool {
            super.beginTrackingWithTouch(touch, withEvent: event)
            println("beginTrackingWithTouch")
            sliderDelegate.SliderBeginDragging(self)
            return true
        }
    
    
        override public func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool
        {
            super.continueTrackingWithTouch(touch, withEvent: event)
    
            sliderDelegate.SliderScrub(self)
            let point = touch.locationInView(self)
    
            var _xb = (self.frame.size.width * CGFloat(currentBuffer)) - self.frame.size.height
            if  (point.x > 0) // if (point.x < _xb) && (point.x > 0) used for seek and play
            {
                currentPosition = Float(point.x / self.frame.size.width)
                self.setNeedsDisplay()
            }
            return true
        }
        override public func endTrackingWithTouch(touch: UITouch, withEvent event: UIEvent){
            super.endTrackingWithTouch(touch, withEvent: event)
            println("endTrackingWithTouch")
            sliderDelegate.SliderEndDragging(self)
        }
    
        override public func cancelTrackingWithEvent(event: UIEvent?) {
            super.cancelTrackingWithEvent(event)
            println("cancelTrackingWithEvent")
            sliderDelegate.SliderEndDragging(self)
        }
    }
    

    【讨论】:

    • sliderDelegate 变量由于某种原因没有为我初始化?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多