Middle
Kako sistem određuje u koju je vizuelnu komponentu dodir došao?
sobes.tech АИ
Одговор од АИ
Sistem koristi dva ključna mehanizma: hit-testiranje (testiranje dodira) i hijerarhiju prikaza.
-
Hit-testiranje (Hit-testing): Framework UIKit koristi metodu
hitTest(_:with:)korenskog prikaza (UIWindow) za određivanje koji prikaz se nalazi ispod tačke dodira. Ova metoda rekurzivno prolazi kroz hijerarhiju prikaza, počevši od korena. -
Hijerarhija prikaza:
- Metoda
hitTest(_:with:)prvo proverava da li je tačka dodira unutar granica trenutnog prikaza. Ako nije, vraćanil. - Ako jeste, metoda pretražuje decu prikaza u obrnutom redosledu (od poslednje dodate do prve). Za svako dete se poziva njegova sopstvena
hitTest(_:with:)metoda sa istom tačkom dodira (preko transformacije u koordinate deteta). - Prvo dete za koje
hitTest(_:with:)vrati rezultat različit odnil(tj. ono ili neki od njegovih potomaka sadrži tačku) smatra se "uhvaćenim" i taj rezultat se vraća na viši nivo. - Ako nijedno dete ne sadrži tačku, a trenutni prikaz je sadržava i
userInteractionEnabledjetrue, tada sistem smatra da je dodir dogodio u trenutnom prikazu, i metoda vraćaself. - Ako je
userInteractionEnabledtrenutnog prikazafalse, ilihiddenjetrue, ilialphamanji od 0.01, metoda vraćanil, čak i ako je tačka unutar granica.
- Metoda
Proces se nastavlja niz hijerarhiju dok se ne pronađe najniži prikaz koji sadrži tačku dodira. Taj prikaz postaje hit-test view ili hit-test rezultat, i upravo njemu (ili njegovom najbližem predku) će biti poverena dalja obrada događaja (touchesBegan, touchesMoved itd.).
Evo kako se može prepisati hitTest ili point(inside:with:) za prilagođeno ponašanje hit-testiranja:
import UIKit
class CustomView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// Proveravamo da li je tačka unutar našeg prikaza.
if !self.point(inside: point, with: event) {
return nil
}
// Prolazimo kroz decu u obrnutom redosledu.
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 {
// Osnovna implementacija proverava da li je tačka unutar granica i da li je prikaz interaktivan.
let extendedBounds = bounds.insetBy(dx: -20, dy: -20) // Povećava oblast za 20pt sa svih strana
return extendedBounds.contains(point)
}
}