UPDATE
This feature has now been added to the latest version of IOS-Charts via this pull request.
ChartViewDelegate
was updated to now include the following method.
public protocol ChartViewDelegate
{
...
/// Called when a user stop highlighting values while panning
@objc optional func chartViewDidEndPanning(_ chartView: ChartViewBase)
}
All you have to do is implement that method wherever you're implementing ChartViewDelegate (the viewController with your chart).
Original Answer Sub-Class LineChartView
@JGuo's answer works, but it requires you to change code inside the pod. These means that every time you update your pod(s) you'll have to re-implement these changes. You can achieve the same results without modifying the pod as follows:
Create a protocol
import Charts
@objc protocol MyChartViewDelegate {
@objc optional func chartValueNoLongerSelected(_ chartView: MyLineChartView)
}
SubClass LineChartView
open class MyLineChartView: LineChartView {
@objc weak var myChartViewDelegate: MyChartViewDelegate?
private var touchesMoved = false
// Haptic Feedback
private let impactGenerator = UIImpactFeedbackGenerator(style: .light)
private let selectionGenerator = UISelectionFeedbackGenerator()
override open func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
// This is here to prevent the UITapGesture from blocking touches moved from firing
if gestureRecognizer.isKind(of: NSUITapGestureRecognizer.classForCoder()){
return false
}
return super.gestureRecognizerShouldBegin(gestureRecognizer)
}
override open func nsuiTouchesBegan(_ touches: Set<NSUITouch>, withEvent event: NSUIEvent?) {
impactGenerator.impactOccurred()
selectionGenerator.prepare()
// adds the highlight to the graph when tapped
super.nsuiTouchesBegan(touches, withEvent: event)
touchesMoved = false
if let touch = touches.first {
let h = getHighlightByTouchPoint(touch.location(in: self))
if h === nil || h == self.lastHighlighted {
lastHighlighted = nil
highlightValue(nil, callDelegate: true)
}
else {
lastHighlighted = h
highlightValue(h, callDelegate: true)
}
}
}
open override func nsuiTouchesEnded(_ touches: Set<NSUITouch>, withEvent event: NSUIEvent?) {
super.nsuiTouchesEnded(touches, withEvent: event)
myChartViewDelegate?.chartValueNoLongerSelected?(self) // remove the highlight
}
open override func nsuiTouchesCancelled(_ touches: Set<NSUITouch>?, withEvent event: NSUIEvent?) {
super.nsuiTouchesCancelled(touches, withEvent: event)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// if a tap turns into a panGesture touches cancelled is called this prevents the highlight from being moved
if !self.touchesMoved {
self.myChartViewDelegate?.chartValueNoLongerSelected?(self)
}
}
}
override open func nsuiTouchesMoved(_ touches: Set<NSUITouch>, withEvent event: NSUIEvent?) {
super.nsuiTouchesMoved(touches, withEvent: event)
touchesMoved = true
if let touch = touches.first {
let h = getHighlightByTouchPoint(touch.location(in: self))
if h === nil {
lastHighlighted = nil
highlightValue(nil, callDelegate: true)
}
else if h == self.lastHighlighted {
return
}
else {
lastHighlighted = h
highlightValue(h, callDelegate: true)
selectionGenerator.selectionChanged()
}
}
}
}
Create your Chart
let lineChartView = MyLineChartView()
override func viewDidLoad() {
super.viewDidLoad()
lineChartView.delegate = self // built in delegate for user interaction
lineChartView.myChartViewDelegate = self // delegate with our additions (knowing when a value is no longer selected)
lineChartView.highlightPerTapEnabled = false // disable tap gesture to highlight
lineChartView.highlightPerDragEnabled = false // disable pan gesture
}
Implement Delegates
extension MyViewController: ChartViewDelegate {
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
// Do something on selection
}
}
extension MyViewController: MyChartViewDelegate {
func chartValueNoLongerSelected(_ chartView: FlyLineChartView) {
// Do something on deselection
}
}