Middle
Ako systém určuje, na ktorú zobrazenie sa dotyk vzťahuje?
sobes.tech AI
Odpoveď od AI
Systém využíva dva kľúčové mechanizmy: hit-testovanie (testovanie zásahu) a hierarchiu pohľadov.
-
Hit-testovanie (Hit-testing): Framework UIKit používa metódu
hitTest(_:with:)koreňového pohľadu (UIWindow) na určenie, ktorý pohľad je pod bodom dotyku. Táto metóda rekurzívne prechádza hierarchiu pohľadov, začínajúc od koreňa. -
Hierarchia pohľadov:
- Metóda
hitTest(_:with:)najskôr skontroluje, či je bod dotyku vo vnútri hraníc aktuálneho pohľadu. Ak nie, vrátinil. - Ak áno, metóda prehľadáva deti pohľadu v opačnom poradí (od posledného pridaného k prvému). Pre každé dieťa sa volá jeho vlastná
hitTest(_:with:)metóda so rovnakým bodom dotyku (prevedeným do súradníc dieťaťa). - Prvé dieťa, ktoré
hitTest(_:with:)vráti výsledok odlišný odnil(t.j. obsahuje bod), sa považuje za "zasiahnuté" a tento výsledok sa vracia nahor v hierarchii. - Ak žiadne dieťa neobsahuje bod, a aktuálny pohľad ho obsahuje a nemá
userInteractionEnabled = false, systém považuje, že dotyk sa stal v aktuálnom pohľade, a metóda vraciaself. - Ak je
userInteractionEnabledaktuálneho pohľadufalse, alebohiddenjetrue, aleboalphaje menšie ako 0.01, metóda vracianil, aj keď je bod vo vnútri hraníc.
- Metóda
Proces pokračuje nadol hierarchiou, kým sa nenájde najnižší pohľad obsahujúci bod dotyku. Tento pohľad sa stáva hit-test view alebo hit-test result, a jemu (alebo jeho najbližšiemu predkovi) bude delegované ďalšie riadenie udalosti (touchesBegan, touchesMoved atď.).
Tu je, ako možno prepísať hitTest alebo point(inside:with:) pre vlastné správanie hit-testovania:
import UIKit
class CustomView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// Kontrolujeme, či je bod vo vnútri nášho pohľadu.
if !self.point(inside: point, with: event) {
return nil
}
// Prechádzame deti v opačnom poradí.
for subview in subviews.reversed() {
let convertedPoint = subview.convert(point, from: self)
if let hitTestView = subview.hitTest(convertedPoint, with: event) {
return hitTestView
}
}
return self
}
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
// Základná implementácia kontroluje, či je bod vo vnútri bounds a či je pohľad interaktívny.
let extendedBounds = bounds.insetBy(dx: -20, dy: -20) // Rozširuje hranice o 20pt
return extendedBounds.contains(point)
}
}