swift 自定义 UIStepper
2016-10-28 本文已影响103人
flyrr
系统自带的UIStepper没有显示当前value值得控件,需要自行添加label来显示。而此控件自带一个label来显示当前值。而且,与系统UIStepper的属性一样都可以设置的。
控件类型分为普通类型,以及外层带有圆圈的。在这里,左边的减号,右边的加号,以及当类型为circle时的圆圈是通过CAShapeLayer和UIBezierPath画出来的,非UIButton控件。
/**
控件类型
- custome: 默认
- circle: 外层带圆圈
*/
enum StepType {
case custom
case circle
}
![Simulator Screen Shot 2016年10月28日 下午4.53.15.png](https://img.haomeiwen.com/i1421310/f8095d5df825347d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
控件的初始化方法,可选择闭包处理点击事件,或者选择代理
/**
初始化方法
- parameter frame: 控件frame--若想circle类型时,成圆形,最好宽高比为10:3
- parameter type: 控件类型
- action: 点击闭包,可选代理或者闭包,二选1
- returns: 此控件
*/
init(frame: CGRect, type: StepType, action: TypeClouse?) {
self.stepType = type
self.action = action
super.init(frame: frame)
defaultAppearance()
}
控件有个属性,是设置控件外观的。里面有个属性观察器didSet方法---当设置外观的时候调用draw()方法~~~
此方法,先reset UI--即清除UI上所有的控件以及layer,然后在重新布置界面---如果不设置的话,会使用默认设置
var appearance: Appearance! {
didSet {
self.draw()
}
}
private func reset() {
//清除控件
for sub in subviews {
sub.removeFromSuperview()
}
//清除layer
if let layers = layer.sublayers {
for lay in layers {
lay.removeFromSuperlayer()
}
}
}
private func draw() {
reset()
let centerY = frame.size.height * 0.5
let width = frame.size.width
let linePath = UIBezierPath()
defer {
linePath.closePath()
}
//(- : label : +) = (3:4:3)
// 画减号
//(空白:-:空白) = (3:4:3)
//线条宽度/高度
let lineHeight = frame.size.height / 3
// 减号起始点
let startX1 = width * 0.3 * 0.3
linePath.moveToPoint(CGPoint(x: startX1, y: centerY))
linePath.addLineToPoint(CGPoint(x: startX1 + lineHeight, y: centerY))
// 画加号
//(空白:+:空白) = (3:4:3)
//横线
// 加号起始点
let startX2 = width - width * 0.3 * 0.3 - lineHeight
linePath.moveToPoint(CGPoint(x: startX2, y: centerY))
linePath.addLineToPoint(CGPoint(x: startX2 + lineHeight, y: centerY))
//竖线
linePath.moveToPoint(CGPoint(x: startX2 + lineHeight * 0.5, y: centerY - lineHeight * 0.5))
linePath.addLineToPoint(CGPoint(x: startX2 + lineHeight * 0.5, y: centerY + lineHeight * 0.5))
let lineLayer = CAShapeLayer()
lineLayer.path = linePath.CGPath
lineLayer.strokeColor = appearance.actionColor.CGColor
lineLayer.lineWidth = 1
self.layer.addSublayer(lineLayer)
let (leftFrame, remainFrame) = bounds.divide(bounds.size.width * 0.3, fromEdge: .MinXEdge)
let (middleFrame, rightFrame) = remainFrame.divide(remainFrame.size.width * 4 / 7, fromEdge: .MinXEdge)
label.frame = middleFrame
addSubview(label)
label.textAlignment = .Center
label.textColor = appearance.textColor
label.font = appearance.textFont
label.adjustsFontSizeToFitWidth = true
//添加action
let reduceC = UIControl(frame: leftFrame)
reduceC.addTarget(self, action: #selector(reduce), forControlEvents: .TouchUpInside)
addSubview(reduceC)
let addC = UIControl(frame: rightFrame)
addC.addTarget(self, action: #selector(add), forControlEvents: .TouchUpInside)
addSubview(addC)
switch stepType {
case .circle:
let scale: CGFloat = 0.7
let reduceFrame = CGRect(x: leftFrame.size.width * 0.5 * (1 - scale), y: centerY - leftFrame.size.height * scale * 0.5, width: leftFrame.size.width * scale, height: leftFrame.size.height * scale)
let reducePath = UIBezierPath(ovalInRect: reduceFrame)
let reduceLayer = CAShapeLayer()
reduceLayer.path = reducePath.CGPath
reduceLayer.fillColor = appearance.fillColor.CGColor
reduceLayer.strokeColor = appearance.strokeColor.CGColor
reduceLayer.lineWidth = 1
layer.addSublayer(reduceLayer)
let addFrame = CGRect(x: startX2 + lineHeight * 0.5 - rightFrame.size.width * scale * 0.5, y: centerY - rightFrame.size.height * scale * 0.5, width: rightFrame.size.width * scale, height: rightFrame.size.height * scale)
let addPath = UIBezierPath(ovalInRect: addFrame)
let addLayer = CAShapeLayer()
addLayer.path = addPath.CGPath
addLayer.fillColor = appearance.fillColor.CGColor
addLayer.strokeColor = appearance.strokeColor.CGColor
addLayer.lineWidth = 1
layer.addSublayer(addLayer)
case .custom:
return
}
}
外界调用代码:
stepV = ZGJStepView(frame: CGRect(x: 50, y: 400, width: 300, height: 90), type: .custom, action: nil)
stepV.backgroundColor = UIColor.lightGrayColor()
stepV.minimumValue = 2
stepV.maximumValue = 10
stepV.stepValue = 1
stepV.delegate = self
stepV.appearance = Appearance(
actionColor: UIColor.redColor(),
strokeColor: UIColor.redColor(),
fillColor: UIColor.clearColor(),
textColor: UIColor.blackColor(),
textFont: UIFont.systemFontOfSize(15))
view.addSubview(stepV)
下面是控件一些可设置的属性,与系统UIStepper的属性非常相识,可以无痛转接
/// 最小值 默认0
var minimumValue: Double = 0 {
didSet {
self.value = minimumValue
if minimumValue % 1.0 == 0.0 {
label.text = "\(Int(minimumValue))"
} else {
label.text = "\(minimumValue)"
}
}
}
/// 最大值默认 100
var maximumValue: Double = 100
/// 每一次点击增减值 默认1
var stepValue: Double = 1
/// 当前值---默认0
var value: Double = 0 {
didSet {
if stepValue % 1.0 == 0.0 && minimumValue % 1.0 == 0.0 {
label.text = "\(Int(value))"
} else {
label.text = "\(value)"
}
}
}
然后是可以设置控件的外观
/**
* 控件的基本设置
*/
struct Appearance {
/// ➕/➖的颜色
var actionColor: UIColor
/// circle类型时,外围圆圈颜色
var strokeColor: UIColor
var fillColor: UIColor
/// 字体颜色
var textColor: UIColor
/// 字体
var textFont: UIFont
}