109 lines
4.6 KiB
Swift
109 lines
4.6 KiB
Swift
//
|
|
// SeismicNetworkScrollIndicatorView.swift
|
|
// Earthquake Network
|
|
//
|
|
// Created by Andrea Busi on 31/01/25.
|
|
// Copyright © 2025 Earthquake Network. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
import CoreGraphics
|
|
|
|
|
|
class SeismicNetworkScrollIndicatorView: UIView {
|
|
|
|
private static let HighlightColor: UIColor = .red
|
|
|
|
var seismics: [SeismicNetworkViewModel] = [] {
|
|
didSet {
|
|
setNeedsDisplay()
|
|
}
|
|
}
|
|
|
|
var highlighted: SeismicNetworkViewModel? {
|
|
didSet {
|
|
setNeedsDisplay()
|
|
}
|
|
}
|
|
|
|
private var numberOfRectangles: Int {
|
|
seismics.count
|
|
}
|
|
|
|
// MARK: - View Lifecycle
|
|
|
|
override func draw(_ rect: CGRect) {
|
|
guard numberOfRectangles > 0 else { return }
|
|
|
|
let context = UIGraphicsGetCurrentContext()
|
|
let rectStandardWidth = rect.width
|
|
let rectStandardHeight = rect.height / CGFloat(numberOfRectangles)
|
|
let rectHighlightedMinHeight: CGFloat = 4
|
|
|
|
let smallRectangles = rectStandardHeight < 10
|
|
let highlightIndex = seismics.firstIndex(where: { $0 == highlighted }) ?? 100_000
|
|
|
|
|
|
seismics.enumerated().forEach { index, seismic in
|
|
// Disegniamo un rettangolo per ogni sisma, quello evidenziato deve avere un contorno rosso.
|
|
// Ci sono situazioni in cui ci sono molti sismi da mostrare, quindi in quel caso facciamo alcune modifiche:
|
|
// - usiamo un'altezza minima per il sisma evidenziato
|
|
// - per il sisma evidenziato, anche il contenuto è rosso (e non solo il bordo)
|
|
// - negli altri sismi, non mostriamo il bordo
|
|
|
|
if highlightIndex == index {
|
|
// Stiamo disegnando il sisma evidenziato.
|
|
// Valutiamo se utilizzare l'altezza minima.
|
|
let rectHeight = smallRectangles ? rectHighlightedMinHeight : rectStandardHeight
|
|
let yPosition = CGFloat(index) * rectStandardHeight
|
|
let rectangle = CGRect(x: 0, y: yPosition, width: rectStandardWidth, height: rectHeight)
|
|
|
|
let fillColor = smallRectangles ? Self.HighlightColor : seismic.colors.textColor.withAlphaComponent(0.3)
|
|
context?.setFillColor(fillColor.cgColor)
|
|
context?.fill(rectangle)
|
|
|
|
if !smallRectangles {
|
|
// disegniamo il bordo solo se i rettangoli non sono piccoli
|
|
let borderWidth: CGFloat = 2.0
|
|
context?.setStrokeColor(Self.HighlightColor.cgColor)
|
|
context?.setLineWidth(borderWidth) // Spessore del bordo
|
|
context?.stroke(rectangle.insetBy(dx: borderWidth / 2, dy: borderWidth / 2)) // Evita che il bordo venga tagliato
|
|
}
|
|
} else {
|
|
// Stiamo disegnando i sismi non evidenziati, utilizziamo sempre l'altezza predefinita
|
|
// Dobbiamo eventualmente calcolare un offset aggiuntivo,
|
|
// perchè il sisma evidenziato ha un'altezza maggiore (se i rettangoli sono piccoli)
|
|
let rectHeight = rectStandardHeight
|
|
|
|
var offset: CGFloat = 0
|
|
if index > highlightIndex && smallRectangles {
|
|
// calcoliamo l'offset prima del rettangolo evidenziato
|
|
let preOffset = CGFloat(highlightIndex - 1) * rectStandardHeight
|
|
// offset diverso dovuto all'altezza diversa del rettangolo evidenziato
|
|
let highlightOffset = rectHighlightedMinHeight
|
|
// calcoliamo l'offset tra il rettangolo evidenziato e quello corrente
|
|
let postOffset = CGFloat(index - highlightIndex) * rectStandardHeight
|
|
offset = preOffset + highlightOffset + postOffset
|
|
} else {
|
|
// siamo prima del rettangolo evidenziato, non abbiamo calcoli da fare
|
|
offset = CGFloat(index) * rectHeight
|
|
}
|
|
|
|
let rectangle = CGRect(x: 0, y: offset, width: rectStandardWidth, height: rectHeight)
|
|
|
|
let fillColor = seismic.colors.textColor.withAlphaComponent(0.3)
|
|
context?.setFillColor(fillColor.cgColor)
|
|
context?.fill(rectangle)
|
|
|
|
if !smallRectangles {
|
|
// altrimenti un bordo grigio
|
|
let borderWidth: CGFloat = 0.5
|
|
context?.setStrokeColor(AppTheme.Colors.gray.cgColor)
|
|
context?.setLineWidth(borderWidth) // Spessore del bordo
|
|
context?.stroke(rectangle)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|