Skip to content

Commit 0a50254

Browse files
authored
Merge pull request #2 from renderforest/feature/tooltip-slider
Added tooltip slider
2 parents 1de3326 + fdcee55 commit 0a50254

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-0
lines changed

.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/SliderKit/TooltipSlider.swift

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
//
2+
// TooltipSlider.swift
3+
//
4+
// MIT License
5+
//
6+
// Copyright (c) 2022 Tigran Gishyan
7+
//
8+
// Permission is hereby granted, free of charge, to any person obtaining a copy
9+
// of this software and associated documentation files (the "Software"), to deal
10+
// in the Software without restriction, including without limitation the rights
11+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
// copies of the Software, and to permit persons to whom the Software is
13+
// furnished to do so, subject to the following conditions:
14+
//
15+
// The above copyright notice and this permission notice shall be included in all
16+
// copies or substantial portions of the Software.
17+
//
18+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
// SOFTWARE.
25+
26+
import UIKit
27+
28+
public struct TooltipData {
29+
public var image: UIImage
30+
public var label: UILabel
31+
}
32+
33+
/// Custom subtype of slider with tooltip view
34+
open class TooltipSlider: UISlider {
35+
36+
var tooltipView: TooltipView?
37+
var onValueChanged: ((Double) -> Void)?
38+
39+
public init() {
40+
41+
super.init(frame: .zero)
42+
initToolTip()
43+
44+
addTarget(self, action: #selector(valueChanged), for: .valueChanged)
45+
addTarget(self, action: #selector(thumbHitted), for: .touchDown)
46+
addTarget(
47+
self,
48+
action: #selector(valueCancelled),
49+
for: [.touchCancel, .touchUpInside, .touchUpOutside]
50+
)
51+
52+
tooltipView?.callback = { [weak self] val in
53+
self?.onValueChanged?(val)
54+
}
55+
}
56+
57+
required public init?(coder: NSCoder) {
58+
fatalError("init(coder:) has not been implemented")
59+
}
60+
61+
open func set(data: TooltipData) {
62+
tooltipView?.set(data: data)
63+
}
64+
65+
open func update(tooltipValue: Float) {
66+
tooltipView?.update(value: tooltipValue)
67+
}
68+
69+
override open func thumbRect(
70+
forBounds bounds: CGRect,
71+
trackRect rect: CGRect,
72+
value: Float
73+
) -> CGRect {
74+
75+
let thumbRect = super.thumbRect(
76+
forBounds: bounds, trackRect: rect, value: value
77+
)
78+
79+
let transformedRect = CGRect(
80+
origin: thumbRect.origin,
81+
size: CGSize(
82+
width: thumbRect.width + 18,
83+
height: 38
84+
)
85+
)
86+
87+
let tooltipRect = transformedRect.offsetBy(dx: -9, dy: -(thumbRect.size.height + 6))
88+
tooltipView?.frame = tooltipRect
89+
tooltipView?.update(value: self.value)
90+
91+
return thumbRect
92+
}
93+
94+
func initToolTip() {
95+
tooltipView = TooltipView()
96+
tooltipView?.backgroundColor = UIColor.clear
97+
self.addSubview(tooltipView!)
98+
tooltipView?.alpha = 0
99+
}
100+
101+
func changeTooltipWIthAnimation(_ alpha: CGFloat) {
102+
UIView.animate(
103+
withDuration: 0.15,
104+
delay: 0,
105+
options: .curveEaseIn,
106+
animations: {
107+
self.tooltipView?.alpha = alpha
108+
},
109+
completion: nil
110+
)
111+
}
112+
113+
@objc func thumbHitted() {
114+
changeTooltipWIthAnimation(1)
115+
}
116+
117+
@objc func valueChanged() {
118+
update(tooltipValue: value)
119+
}
120+
121+
@objc func valueCancelled() {
122+
changeTooltipWIthAnimation(0)
123+
}
124+
}
125+
126+
open class TooltipView: UIView {
127+
128+
lazy var tooltipLabel = UILabel()
129+
var callback: ((Double) -> Void)?
130+
131+
let numberFormatter: NumberFormatter = {
132+
let numberForamtter = NumberFormatter()
133+
numberForamtter.maximumFractionDigits = 2
134+
return numberForamtter
135+
}()
136+
137+
public init() {
138+
super.init(frame: .zero)
139+
}
140+
141+
required public init?(coder: NSCoder) {
142+
fatalError("init(coder:) has not been implemented")
143+
}
144+
145+
func set(data: TooltipData) {
146+
let tooltipImageView = UIImageView()
147+
tooltipImageView.image = data.image
148+
149+
addSubview(tooltipImageView)
150+
151+
tooltipImageView.translatesAutoresizingMaskIntoConstraints = false
152+
NSLayoutConstraint.activate(
153+
[
154+
tooltipImageView.leadingAnchor.constraint(equalTo: leadingAnchor),
155+
tooltipImageView.trailingAnchor.constraint(equalTo: trailingAnchor),
156+
tooltipImageView.topAnchor.constraint(equalTo: topAnchor),
157+
tooltipImageView.bottomAnchor.constraint(equalTo: bottomAnchor)
158+
]
159+
)
160+
161+
tooltipLabel = data.label
162+
tooltipImageView.addSubview(tooltipLabel)
163+
164+
tooltipLabel.translatesAutoresizingMaskIntoConstraints = false
165+
NSLayoutConstraint.activate(
166+
[
167+
tooltipLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
168+
tooltipLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
169+
tooltipLabel.topAnchor.constraint(equalTo: topAnchor),
170+
tooltipLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -12)
171+
]
172+
)
173+
}
174+
175+
func update(value: Float) {
176+
let value: Double = Double(value)
177+
callback?(value)
178+
let formattedText = numberFormatter.string(
179+
from: .init(value: value)
180+
) ?? ""
181+
tooltipLabel.text = formattedText + "x"
182+
self.setNeedsDisplay()
183+
}
184+
}

0 commit comments

Comments
 (0)