Как запретить круговому UIView распознавать касания за пределами его круговых границ?

У меня есть два представления, сложенные друг над другом. Допустим, представление B расположено поверх большего представления A. Представление B является круглым и не должно принимать касания за пределами круга, вместо этого большее представление A должно принимать касания.

Я попытался переопределить метод touchesBegan пользовательского распознавателя PanGesture вида B, чтобы проверить, находится ли он внутри кругового пути, а затем вызвать прикосновения, отмененные в распознавателях, как это:

override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
    let touch = touches.anyObject() as UITouch
    let location = touch.locationInView(self.view)
    let isInPath = self.path.containsPoint(location)

    if(isInPath){
        super.touchesBegan(touches, withEvent: event)
        self.rotation = rotationForLocation(location)
    }else{
        // touch started outside of path so cancel touch
        super.cancelsTouchesInView = true
        super.touchesCancelled(touches, withEvent: event)
    }
}

Это не позволяет виду B принимать касания за пределами кругового пути, но вид A не принимает касания. Любая помощь будет высоко оценена, спасибо.


person eli_slade    schedule 26.01.2015    source источник
comment
Переопределите метод hitTest.   -  person rmaddy    schedule 26.01.2015


Ответы (2)


Вы можете добавить два распознавателя жестов, один из которых будет указывать делегата с методом gestureRecognizerShouldBegin, который будет запускать жест только в том случае, если он находится внутри круга. Затем вы можете добиться успеха некругового жеста, только если круговой не сработает.

// add square view

let subview = UIView(frame: frame)
subview.backgroundColor = UIColor.lightGrayColor()
subview.userInteractionEnabled = true
view.addSubview(subview)

// add circular shapelayer (so I can see the circle)

let circularShapeLayer = CAShapeLayer()
circularShapeLayer.frame = subview.bounds
circularShapeLayer.path = UIBezierPath(ovalInRect: subview.bounds).CGPath
circularShapeLayer.fillColor = UIColor.darkGrayColor().CGColor
subview.layer.addSublayer(circularShapeLayer)

// add gesture that will use delegate method `gestureRecognizerShouldBegin` to determine if you started in the circle

let circlePanGesture = UIPanGestureRecognizer(target: self, action: "handleCircularPan:")
circlePanGesture.delegate = self
subview.addGestureRecognizer(circlePanGesture)

// add a gesture recognizer that will only be recognized if the prior gesture recognizer fails

let squarePanGesture = UIPanGestureRecognizer(target: self, action: "handleSquarePan:")
squarePanGesture.requireGestureRecognizerToFail(circlePanGesture)
subview.addGestureRecognizer(squarePanGesture)

Метод делегата может выглядеть так:

func gestureRecognizerShouldBegin(gesture: UIGestureRecognizer) -> Bool {
    let center = CGPoint(x: gesture.view!.bounds.size.width / 2.0, y: gesture.view!.bounds.size.height / 2.0)
    let location = gesture.locationInView(gesture.view)
    let distance = hypot(center.x - location.x, center.y - location.y)
    return distance < (gesture.view!.bounds.size.width / 2.0)
}

Обратите внимание: я добавляю оба этих жеста в одно и то же подпредставление (потому что, если у меня есть перекрывающиеся виды, оба из которых имеют userInteractionEnabled, только верхний, если я получаю жесты).

person Rob    schedule 26.01.2015

Не отменяйте касания, вместо этого перенаправляйте их на объект A.

person Tokuriku    schedule 26.01.2015
comment
Вы имеете в виду вперед, чтобы просмотреть А? Если это так, я должен сообщить вам, что этот распознаватель жестов находится внутри пользовательского UIControl, а представление A и представление B являются двумя отдельными экземплярами этого пользовательского UIControl. Целесообразно ли передавать эту информацию между двумя отдельными UIControl? - person eli_slade; 26.01.2015
comment
Извините, я имел в виду A, и я изменил свой ответ, чтобы отразить это. Если оба обрабатываются в одном объекте, то проблем нет. Возможно, вы захотите определить два пути и проверить формат B еще один, если формат A один. Прямо сейчас, когда он не в B, ничего не происходит. - person Tokuriku; 26.01.2015