swift 自定义 UIStepper

系统自带的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](http://upload-images.jianshu.io/upload_images/1421310-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
}

git地址:https://github.com/guijie20140501/ZGJStepView.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,856评论 25 707
  • Swift版本点击这里欢迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh阅读 25,340评论 7 249
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 童年记忆里那些美好的,不美好的,都随着时间的流逝,在我的记忆里愈渐模糊,我唯能做的,就是趁着这点微弱的回忆,将之记...
    寻覔阅读 299评论 2 1
  • 昨晚比特币下探到5537,然后在5560横盘一晚上 早上在5580内缓慢震荡 圣诞周来了,会是什么行情呢? 前三天...
    天籁村阅读 68评论 0 0