Πώς καθορίζει το σύστημα σε ποια προβολή έγινε η αφή;
sobes.tech AI
Απάντηση από AI
Το σύστημα χρησιμοποιεί δύο βασικούς μηχανισμούς: το hit-testing (δοκιμή επαφής) και την ιεραρχία των views.
-
Hit-testing (δοκιμή επαφής): Το πλαίσιο UIKit χρησιμοποιεί τη μέθοδο
hitTest(_:with:)του ρίζας view (UIWindow) για να καθορίσει ποιο view βρίσκεται κάτω από το σημείο αφής. Αυτή η μέθοδος διατρέχει αναδρομικά την ιεραρχία των views, ξεκινώντας από το ρίζα. -
Ιεραρχία views:
- Η μέθοδος
hitTest(_:with:)ελέγχει πρώτα αν το σημείο αφής βρίσκεται εντός των ορίων του τρέχοντος view. Αν όχι, επιστρέφειnil. - Αν ναι, η μέθοδος ελέγχει τα παιδιά views με αντίστροφη σειρά (από το τελευταίο που προστέθηκε στο πρώτο). Για κάθε παιδικό view, καλείται η δική του μέθοδος
hitTest(_:with:)με το ίδιο σημείο αφής (μετασχηματισμένο στις συντεταγμένες του παιδικού view). - Το πρώτο παιδικό view που η
hitTest(_:with:)επιστρέφει αποτέλεσμα διαφορετικό απόnil(δηλαδή, αυτό ή κάποιο από τα παιδιά του περιέχει το σημείο) θεωρείται "πιασμένο" και το αποτέλεσμα αυτό επιστρέφεται προς τα πάνω στην ιεραρχία. - Αν κανένα παιδικό view δεν περιέχει το σημείο αφής, και το τρέχον view περιέχει το σημείο και δεν έχει
userInteractionEnabled = false, το σύστημα θεωρεί ότι η αφή συνέβη στο τρέχον view, και η μέθοδος επιστρέφειself. - Αν το
userInteractionEnabledτου τρέχοντος view είναιfalse, ή τοhiddenείναιtrue, ή τοalphaείναι μικρότερο από 0.01, η μέθοδος επιστρέφειnil, ακόμα και αν το σημείο βρίσκεται εντός των ορίων.
- Η μέθοδος
Η διαδικασία συνεχίζεται προς τα κάτω στην ιεραρχία μέχρι να βρεθεί το πιο κάτω view που περιέχει το σημείο αφής. Αυτό το view γίνεται hit-test view ή hit-test result, και σε αυτό (ή στον πλησιέστερο προγόνου του) θα ανατεθεί η περαιτέρω διαχείριση του γεγονότος (touchesBegan, touchesMoved κ.λπ.).
Ακολουθεί πώς μπορεί να υπερισταλεί η hitTest ή η point(inside:with:) για προσαρμοσμένη συμπεριφορά hit-testing:
import UIKit
class CustomView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// Ελέγχει αν το σημείο βρίσκεται εντός του view.
if !self.point(inside: point, with: event) {
return nil
}
// Διατρέχει τα παιδιά views με αντίστροφη σειρά.
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 {
// Βασική υλοποίηση ελέγχει αν το σημείο βρίσκεται εντός των ορίων και αν το view είναι ενεργό.
let extendedBounds = bounds.insetBy(dx: -20, dy: -20) // Επεκτείνει τα όρια κατά 20pts
return extendedBounds.contains(point)
}
}
Η μέθοδος point(inside:with:) καλείται από το hitTest(_:with:) για γρήγορο έλεγχο αν το σημείο βρίσκεται εντός της περιοχής του view, πριν ελεγχθούν τα παιδιά views.
Τελικά, βρίσκουμε το πιο κάτω interactable view στην ιεραρχία, το οποίο περιέχει το σημείο αφής και έχει userInteractionEnabled true, hidden false, και alpha μεγαλύτερο από 0.01, και του ανατίθεται η διαχείριση του γεγονότος (μέθοδοι touchesBegan, touchesMoved κ.λπ.).