#swift #xcode #uiview #uipangesturerecognizer #uiview-hierarchy
#swift #xcode #uiview #uipangesturerecognizer #пользовательский интерфейс-иерархия
Вопрос:
У меня есть функция, которая создает линию перетаскивания для соединения двух кнопок друг с другом. Это работает нормально, но если некоторые кнопки перекрывают друг друга, то будут выбраны обе, если я перетащу их туда, где они перекрываются. Я хочу подключить только верхнюю кнопку.
Я думаю, что проблема заключается в выборе слоев sender.location сверху и снизу. Есть ли способ сообщить sender.location, чтобы он выбирал только вид сверху? Спасибо за любой вклад и направление
func addPanReconiser(view: UIView){
let pan = UIPanGestureRecognizer(target: self, action: #selector(DesignViewController.panGestureCalled(_:)))
view.addGestureRecognizer(pan)
}
@objc func panGestureCalled(_ sender: UIPanGestureRecognizer) {
let currentPanPoint = sender.location(in: self.view)
switch sender.state {
case .began:
panGestureStartPoint = currentPanPoint
self.view.layer.addSublayer(lineShape)
case .changed:
let linePath = UIBezierPath()
linePath.move(to: panGestureStartPoint)
linePath.addLine(to: currentPanPoint)
lineShape.path = linePath.cgPath
lineShape.path = CGPath.barbell(from: panGestureStartPoint, to: currentPanPoint, barThickness: 2.0, bellRadius: 6.0)
for button in buttonArray {
let point = sender.location(in: button)
if button.layer.contains(point) {
button.layer.borderWidth = 4
button.layer.borderColor = UIColor.blue.cgColor
} else {
button.layer.borderWidth = 0
button.layer.borderColor = UIColor.clear.cgColor
}
}
case .ended:
for button in buttonArray {
let point = sender.location(in: button)
if button.layer.contains(point){
//DO my Action here
lineShape.path = nil
lineShape.removeFromSuperlayer()
}
}
default: break
}
}
}
Примечание: некоторые строки кодов взяты из пользовательских расширений. Я сохранил их, поскольку они не требуют пояснений.
Спасибо за помощь
Ответ №1:
Есть способ обойти. Похоже, вы просто хотите, чтобы ваш жест заканчивался на одной кнопке над всеми остальными, таким образом, добавляя переменную вне цикла и каждый раз, когда выбирается кнопка, сравнивая с переменной ее уровня в z.
case .ended:
var pickedButton: UIButton?
for button in buttonArray {
let point = sender.location(in: button)
if button.layer.contains(point){
if pickedButton == nil {
pickedButton = button
} else {
if let parent = button.superView, parent.subviews.firstIndex(of: button) > parent.subviews.firstIndex(of: pickedButton!) {
pickedButton = button
}
}
}
}
//DO my Action with pickedButton here
lineShape.path = nil
lineShape.removeFromSuperlayer()
Комментарии:
1. Спасибо, Лили! Это сработало, и я немного изменил код, поскольку строка «если разрешить parent = button.SuperView, parent.subviews.firstIndex(of: button) > parent.subviews.firstIndex(of: pickedButton!)» продолжала выдавать ошибку, но в конце концов это сработало
Ответ №2:
UIView
Имеет свойство, вызываемое subViews
, в котором элементы с более высокими индексами находятся перед элементами с более низкими индексами. Например, подвид с индексом 1 находится перед подвидом с индексом 0.
При этом, чтобы получить кнопку, которая находится сверху, вы должны отсортировать свою buttonArray
так же, как организовано subViews
свойство UIView
. Предполагая, что все ваши кнопки являются одинаковыми UIView
(возможно, это не обязательно так, но вы можете настроить их так, чтобы они были правильно отсортированы):
var buttonArray = view.subviews.compactMap { $0 as? UIButton }
Таким образом, сохраняя вашу buttonArray
сортировку таким образом, нужная вам кнопка будет содержать кнопку let point = sender.location(in: button)
с более высоким индексом в массиве.
Комментарии:
1. Спасибо Ajaferson, я пробовал это, но это не решает проблему. Я думал о создании массива местоположений, когда их больше одного, и фильтрации по ним.