Чӣ гуна системаи муайян мекунад, ки дар кадом намуди тамос қарор дорад?
sobes.tech AI
Ҷавоб аз AI
Системата използва два ключови механизма: hit-testing (тестване на удар) и йерархията на изгледите.
-
Hit-testing (Тестване на удар): Framework-ът UIKit използва метода
hitTest(_:with:)на кореновия изглед (UIWindow), за да определи кой изглед е под точката на докосване. Този метод рекурсивно преминава през йерархията на изгледите, започвайки от корена. -
Йерархия на изгледите:
- Методът
hitTest(_:with:)първо проверява дали точката на докосване е вътре в границите на текущия изглед. Ако не, връщаnil. - Ако е вътре, методът преглежда децата на изгледа в обратен ред (от последно добавеното към първото). За всяко дете се извиква неговият собствен
hitTest(_:with:)с същата точка на докосване (преобразувана към координатите на детето). - Първото дете, което връща резултат различен от
nil(т.е. съдържа точката), се счита за "засечено" и този резултат се връща нагоре в йерархията. - Ако никое дете не съдържа точката, а текущият изглед я съдържа и
userInteractionEnabledеtrue, тогава системата счита, че докосването е станало в текущия изглед, и методът връщаself. - Ако е
userInteractionEnabledна текущия изгледfalse, илиhiddenеtrue, илиalphaе по-малко от 0.01, методът връщаnil, дори и да е точката вътре в границите.
- Методът
Процесът продължава надолу по йерархията, докато не бъде намерен най-долният изглед, съдържащ точката на докосване. Този изглед става hit-test view или hit-test result, и именно на него (или на неговия най-близък предшественик) ще бъде делегирано управлението на събитието (touchesBegan, touchesMoved и т.н.).
Ето как може да се препише hitTest или point(inside:with:) за персонализирано поведение:
import UIKit
class CustomView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// Проверяваме дали точката е вътре в нашия изглед.
if !self.point(inside: point, with: event) {
return nil
}
// Обхождаме децата в обратен ред.
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 {
// Стандартната проверка е дали е точката вътре в bounds и дали изгледът е активен.
let extendedBounds = bounds.insetBy(dx: -20, dy: -20) // Увеличаваме областта с 20pts
return extendedBounds.contains(point)
}
}