我可以创建一个具有缓冲进度的自定义UISlider,就像Youtube应用程序中的那样吗?我知道这个问题可能是我可能重复的;但没有人能正确解决iOS或Swift中的问题
谢谢
答案 0 :(得分:8)
您需要子类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
结果:
答案 1 :(得分:1)
有效! 我添加了一个协议来处理组件的滚动,使其行为类似于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)
}
}