Sytuacja, którą próbowałem zrobić, polegała na zbudowaniu panelu sterowania przy użyciu kontrolek wewnątrz zagnieżdżonych UIStackView. Niektóre kontrolki miały UITextField, inne z UIButton. Były też etykiety identyfikujące kontrole. To, co chciałem zrobić, to umieścić duży „niewidoczny” przycisk za panelem sterowania, aby jeśli użytkownik dotknął obszaru poza przyciskiem lub polem tekstowym, mógłbym to złapać i podjąć działanie - przede wszystkim odrzucić każdą klawiaturę, jeśli tekst pole było aktywne (resignFirstResponder). Jednak dotknięcie etykiety lub innego pustego obszaru w panelu sterowania nie spowoduje przejścia. Powyższe dyskusje były pomocne w sformułowaniu mojej odpowiedzi poniżej.
Zasadniczo podklasowałem UIStackView i nadpisałem procedurę „point (inside: with)” w celu wyszukania typu elementów sterujących, które wymagały dotknięcia i „zignorowania” rzeczy, takich jak etykiety, które chciałem zignorować. Sprawdza również wewnętrzne UIStackView, aby rzeczy mogły powtarzać się w strukturze panelu sterowania.
Kod jest być może trochę bardziej rozwlekły niż powinien. Ale był pomocny w debugowaniu i, miejmy nadzieję, zapewnia większą jasność w tym, co robi rutyna. Po prostu upewnij się, że w programie Interface Builder zmienisz klasę UIStackView na PassThruStack.
class PassThruStack: UIStackView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
for view in self.subviews {
if !view.isHidden {
let isStack = view is UIStackView
let isButton = view is UIButton
let isText = view is UITextField
if isStack || isButton || isText {
let pointInside = view.point(inside: self.convert(point, to: view), with: event)
if pointInside {
return true
}
}
}
}
return false
}
}