159 lines
5.9 KiB
Swift
159 lines
5.9 KiB
Swift
//
|
|
// MLSliderRuler.swift
|
|
// MLSilderRulerView
|
|
//
|
|
// Created by Macro on 2018/1/25.
|
|
// Copyright © 2018年 CodeMarco. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
let DISTANCELEFTANDRIGHT: CGFloat = 8.0 // 标尺左右距离
|
|
let DISTANCEVALUE: CGFloat = 8.0 // 每隔刻度实际长度8个点
|
|
let DISTANCETOPANDBOTTOM: CGFloat = 5.0 // 标尺上下距离
|
|
|
|
class MLSliderRulerScrollView: UIScrollView {
|
|
|
|
var maxValue: CGFloat = 2000
|
|
var minValue: CGFloat = 0
|
|
var rulerAverage: CGFloat = 1
|
|
|
|
var rulerCount: Int {
|
|
return Int(maxValue - minValue)
|
|
}
|
|
|
|
var isShowShortSymbol = true
|
|
var isSmallModel: Bool = true
|
|
|
|
var binary: Int = 10
|
|
var ruleFont = UIFont.systemFont(ofSize: 12)
|
|
|
|
var longSymbolColor = UIColor.hexSting(color: "#B6BCC7", alpha: 1) {
|
|
didSet {
|
|
longSymbol.strokeColor = longSymbolColor.cgColor
|
|
}
|
|
}
|
|
var middleSymbolColor = UIColor.hexSting(color: "#B6BCC7", alpha: 1) {
|
|
didSet {
|
|
middleSymbol.strokeColor = middleSymbolColor.cgColor
|
|
}
|
|
}
|
|
var shortSymbolColor = UIColor.hexSting(color: "#B6BCC7", alpha: 1) {
|
|
didSet {
|
|
shortSymbol.strokeColor = shortSymbolColor.cgColor
|
|
}
|
|
}
|
|
|
|
fileprivate lazy var longSymbol: CAShapeLayer = {
|
|
let shapeLayer = CAShapeLayer()
|
|
shapeLayer.strokeColor = longSymbolColor.cgColor
|
|
shapeLayer.fillColor = UIColor.clear.cgColor
|
|
shapeLayer.lineWidth = 3
|
|
shapeLayer.lineCap = .round
|
|
return shapeLayer
|
|
}()
|
|
|
|
fileprivate lazy var middleSymbol: CAShapeLayer = {
|
|
let shapeLayer = CAShapeLayer()
|
|
shapeLayer.strokeColor = middleSymbolColor.cgColor
|
|
shapeLayer.fillColor = UIColor.clear.cgColor
|
|
shapeLayer.lineWidth = 3
|
|
shapeLayer.lineCap = .round
|
|
return shapeLayer
|
|
}()
|
|
|
|
fileprivate lazy var shortSymbol: CAShapeLayer = {
|
|
let shapeLayer = CAShapeLayer()
|
|
shapeLayer.strokeColor = shortSymbolColor.cgColor
|
|
shapeLayer.fillColor = UIColor.clear.cgColor
|
|
shapeLayer.lineWidth = 3
|
|
shapeLayer.lineCap = .round
|
|
return shapeLayer
|
|
}()
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
setupSubviews()
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
func setupSubviews() {
|
|
layer.addSublayer(shortSymbol)
|
|
layer.addSublayer(middleSymbol)
|
|
layer.addSublayer(longSymbol)
|
|
backgroundColor = UIColor.white
|
|
}
|
|
|
|
func drawRuler() {
|
|
layer.sublayers?.forEach { (sublayer) in
|
|
if sublayer.isKind(of: CATextLayer.self) {
|
|
sublayer.removeFromSuperlayer()
|
|
}
|
|
}
|
|
|
|
let longPathRef = CGMutablePath()
|
|
let middlePathRef = CGMutablePath()
|
|
let shortPathRef = CGMutablePath()
|
|
|
|
for idx in 0 ... rulerCount {
|
|
let i = CGFloat(idx)
|
|
|
|
let rule = CATextLayer()
|
|
rule.foregroundColor = UIColor.lightGray.cgColor
|
|
rule.font = ruleFont
|
|
rule.fontSize = ruleFont.pointSize
|
|
rule.contentsScale = UIScreen.main.scale
|
|
rule.string = String(format: "%.0f", (i + minValue) * rulerAverage)
|
|
|
|
let textSize = (rule.string as! NSString).size(withAttributes: [NSAttributedString.Key.font: ruleFont])
|
|
rule.bounds = CGRect(origin: CGPoint.zero, size: textSize)
|
|
|
|
let xPos = DISTANCELEFTANDRIGHT + DISTANCEVALUE * i
|
|
|
|
if idx % Int(binary) == 0 {
|
|
longPathRef.move(to: CGPoint(x: xPos, y: DISTANCETOPANDBOTTOM + textSize.height + 5))
|
|
longPathRef.addLine(to: CGPoint(x: xPos, y: bounds.height - DISTANCETOPANDBOTTOM))
|
|
rule.position = CGPoint(x: xPos, y: 5 + textSize.height / 2)
|
|
layer.addSublayer(rule)
|
|
|
|
} else if idx % Int(binary / 2) == 0 {
|
|
middlePathRef.move(to: CGPoint(x: xPos, y: DISTANCETOPANDBOTTOM + textSize.height + 10))
|
|
middlePathRef.addLine(to: CGPoint(x: xPos, y: bounds.height - DISTANCETOPANDBOTTOM))
|
|
|
|
} else if isShowShortSymbol {
|
|
shortPathRef.move(to: CGPoint(x: xPos, y: DISTANCETOPANDBOTTOM + textSize.height + 15))
|
|
shortPathRef.addLine(to: CGPoint(x: xPos, y: bounds.height - DISTANCETOPANDBOTTOM))
|
|
}
|
|
}
|
|
|
|
longSymbol.path = longPathRef
|
|
|
|
let longSymbolFrame = longSymbol.path?.boundingBoxOfPath ?? .zero
|
|
let longSymbolCenterY = longSymbolFrame.midY
|
|
|
|
middleSymbol.path = middlePathRef
|
|
shortSymbol.path = shortPathRef
|
|
|
|
middleSymbol.position.y += (longSymbolCenterY - (middlePathRef.boundingBoxOfPath.midY))
|
|
shortSymbol.position.y += (longSymbolCenterY - (shortPathRef.boundingBoxOfPath.midY))
|
|
|
|
if isSmallModel {
|
|
contentInset = UIEdgeInsets(top: 0, left: bounds.width / 2 - DISTANCELEFTANDRIGHT, bottom: 0, right: bounds.width / 2 - DISTANCELEFTANDRIGHT)
|
|
contentOffset = CGPoint(x: DISTANCEVALUE * ((currentRulerValue - minValue) / rulerAverage) - bounds.width + (bounds.width / 2 + DISTANCELEFTANDRIGHT), y: 0)
|
|
} else {
|
|
contentOffset = CGPoint(x: DISTANCEVALUE * ((currentRulerValue - minValue) / rulerAverage) - bounds.width / 2.0 + DISTANCELEFTANDRIGHT, y: 0)
|
|
}
|
|
|
|
contentSize = CGSize(width: CGFloat(rulerCount) * DISTANCEVALUE + DISTANCELEFTANDRIGHT * 2, height: bounds.height)
|
|
}
|
|
|
|
// Computed property to get the current ruler value based on scroll position
|
|
var currentRulerValue: CGFloat {
|
|
let offsetX = contentOffset.x + bounds.size.width / 2 - DISTANCELEFTANDRIGHT
|
|
return (offsetX / DISTANCEVALUE) * rulerAverage + minValue
|
|
}
|
|
}
|