Hogyan határozza meg a rendszer, hogy melyik nézetben történt az érintés?
sobes.tech MI
Válasz az MI-től
A rendszer két kulcsfontosságú mechanizmust használ: a hit-tesztelést (érintés tesztelés) és a nézethierarchiát.
-
Hit-tesztelés (Hit-testing): A UIKit keretrendszer a
hitTest(_:with:)metódust használja az ablak (UIWindow) gyökérnézetén, hogy meghatározza, melyik nézet található az érintés pontja alatt. Ez a metódus rekurzívan végigjárja a nézethierarchiát, a gyökértől kezdve. -
Nézethierarchia:
- A
hitTest(_:with:)elsőként ellenőrzi, hogy az érintés pontja a jelenlegi nézet határain belül van-e. Ha nem, akkornil-t ad vissza. - Ha igen, akkor a nézet gyermekeit fordított sorrendben vizsgálja (az utoljára hozzáadottól az elsőig). Minden gyermekre meghívja a saját
hitTest(_:with:)metódusát ugyanazzal a ponttal (átalakítva a gyermek koordinátáira). - Az első gyermek, amelyik
hitTest(_:with:)eredménye nemnil, az "elkapott" nézetnek számít, és ez az eredmény felfelé kerül visszaadásra. - Ha egyik gyermek sem tartalmazza a pontot, és a jelenlegi nézet tartalmazza, valamint
userInteractionEnabledértéketrue, akkor a rendszer úgy tekinti, hogy az érintés a jelenlegi nézetben történt, és aselfértéket adja vissza. - Ha a jelenlegi nézet
userInteractionEnabledértékefalse, vagyhiddentrue, vagyalphakisebb, mint 0.01, akkornil-t ad vissza, még akkor is, ha a pont a határain belül van.
- A
A folyamat lefelé halad a hierarchiában, amíg meg nem találja a legalsó nézetet, amely tartalmazza az érintés pontját. Ez a nézet lesz a hit-test view vagy hit-test eredmény, és neki (vagy legközelebbi szülőjének) delegálódik a további eseménykezelés (touchesBegan, touchesMoved stb.).
Íme, hogyan lehet felülírni a hitTest vagy a point(inside:with:) metódust egyedi viselkedéshez:
import UIKit
class CustomView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// Ellenőrizzük, hogy a pont a view belsejében van-e.
if !self.point(inside: point, with: event) {
return nil
}
// Végigmegyünk a gyermek nézeteken fordított sorrendben.
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 {
// Alapértelmezett implementáció ellenőrzi, hogy a pont a határokon belül van-e, és az view interaktív-e.
let extendedBounds = bounds.insetBy(dx: -20, dy: -20) // Növeli a területet 20 ponttal minden irányban
return extendedBounds.contains(point)
}
}
A point(inside:with:) metódus a hitTest(_:with:) által hívódik, hogy gyorsan ellenőrizze, a pont egyáltalán a view területén belül van-e, mielőtt a gyermek nézeteket ellenőrizné.
Végül, megtaláljuk a legalsó, interaktív nézetet a hierarchiában, amely tartalmazza a pontot, és userInteractionEnabled értéke true, hidden false, és alpha nagyobb, mint 0.01, és neki delegáljuk az esemény további kezelését (touchesBegan, touchesMoved stb.).