Как я должен реализовать точку (внутри: с :)? - PullRequest
0 голосов
/ 29 октября 2018

Я пытаюсь создать UIView непрямоугольной формы с сенсорной областью не прямоугольной формы. Я уже знаю, как нарисовать мою фигуру с помощью более изящных контуров.

Согласно этому комментарию , мне нужно переопределить point(inside:with:), чтобы создать сенсорную область произвольной формы.

Итак, я попробовал это:

class MyView: UIView {
    override func draw(_ rect: CGRect) {
        let path = UIBezierPath()
        path.move(to: .zero)
        path.addLine(to: CGPoint(x: 0, y: bounds.maxY))
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.midY))
        path.addLine(to: CGPoint(x: bounds.midX, y: bounds.midY))
        path.addLine(to: CGPoint(x: bounds.midX, y: 0))
        path.addLine(to: CGPoint(x: 0, y: 0))
        UIColor.red.setFill()
        path.fill()
    }

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        print("point(inside:with:) called")

        func isInRegion(_ point: CGPoint) -> Bool {
            return (0...bounds.midX).contains(point.x) || (bounds.midY...bounds.maxY).contains(point.y)
        }

        guard let touches = event?.touches(for: self) else { return false }
        guard !touches.isEmpty else { return false }

        print("passed all the guards")
        let first = touches.first!
        print("first touch: \(first.location(in: self))")

        return touches.map { $0.location(in: self) }.contains(where: isInRegion)
    }
}

Метод draw рисует красную форму L. И я попробовал включить касание только внутри формы L.

Я создал MyView с именем blueView, сделал его фон синим, чтобы область касания была красной, а область без касания - синей.

Я также добавил обычный зеленый UIView под частью синего, как это:

enter image description here

Я включил взаимодействие с пользователем для обоих этих видов и добавил UITapGestureRecogniser с, чтобы при нажатии на красную область печаталось blue view tapped. Если нажать на зеленый вид, будет напечатано green view tapped.

override func viewDidLoad() {
    super.viewDidLoad()

    blueView.isUserInteractionEnabled = true
    greenView.isUserInteractionEnabled = true

    blueView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(blueViewTapped)))
    greenView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(greenViewTapped)))
}

@objc func blueViewTapped() {
    print("Blue view tapped")
}

@objc func greenViewTapped() {
    print("Green view tapped")
}

Когда я запускаю приложение и нажимаю на красный бит, только point(inside:with:) called печатается дважды и ничего больше. Я ожидал, что blue view tapped и все другие операторы печати в point(inside:with:) также будут выполнены. Если я коснусь синего бита, одно и то же сообщение будет напечатано дважды снова. Если я коснусь зеленого бита, который покрыт синим битом, Green view tapped печатается после того, как point(inside:with:) called напечатано дважды.

Почему blue view tapped не напечатано? Должно быть, я неправильно реализовал point(inside:with:), верно?

EDIT:

После некоторой отладки я обнаружил, что причина, по которой point(inside:with:) не возвращает true, заключается в том, что event.allTouches пусто. Это очень странно, потому что я на 100% уверен, что коснулся вида!

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

Поскольку вы используете UIBezierPath для рисования области, которую хотите коснуться, вы можете обнаружить точки внутри непрямоугольной области, сохранив ссылку на свой путь и используя .contains(_:):

class MyView: UIView {

    var path: UIBezierPath!

    override func draw(_ rect: CGRect) {
        path = UIBezierPath()
        path.move(to: .zero)
        path.addLine(to: CGPoint(x: 0, y: bounds.maxY))
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.midY))
        path.addLine(to: CGPoint(x: bounds.midX, y: bounds.midY))
        path.addLine(to: CGPoint(x: bounds.midX, y: 0))
        path.addLine(to: CGPoint(x: 0, y: 0))
        UIColor.red.setFill()
        path.fill()
    }

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {

        print("path containsPoint?", path.contains(point))

        return path.contains(point)

    }
}
0 голосов
/ 29 октября 2018

точка (внутри: с:) используется hitTest (_: с:) , чтобы определить, следует ли просматривать подпредставления или нет.

В вашем случае, если пользователь нажимает на синюю область, вы должны вернуть false.

Вы можете сделать это, просто установив

if (point is inside blue+red rect) {
    return !(point is inside blue)
} else {
    return false
}

Вам не нужно проверять наличие прикосновений:

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    print("point(inside:with:) called")

    func isInRegion(_ point: CGPoint) -> Bool {
        return (0...bounds.midX).contains(point.x) || (bounds.midY...bounds.maxY).contains(point.y)
    }
    let a = isInRegion(point)
    print(a)
    return a
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...