Sobes.tech
Middle

Kā sistēma nosaka, kurā skatā ir noticis pieskāriens?

sobes.tech AI

Atbilde no AI

Sistēma izmanto divus galvenos mehānismus: hit-testēšanu (hit-testing) un skatījumu hierarhiju:

  1. Hit-testēšana (Hit-testing): UIKit ietvars izmanto hitTest(_:with:) metodi UIWindow galvenajam skatījumam, lai noteiktu, kurš skatījums atrodas pie kontakta punkta. Šī metode rekursīvi pārbauda skatījumu hierarhiju, sākot ar galveno:

  2. Skatījumu hierarhija:

    • hitTest(_:with:) metode vispirms pārbauda, vai kontakta punkts ir iekšā pašreizējā skatījuma robežās. Ja nē, tā atgriež nil:
    • Ja ir, tā pārbauda bērnu skatījumus atpakaļejošā secībā (no pēdējā pievienotā līdz pirmajam). Katram bērnam tiek izsaukts tā hitTest(_:with:) ar to pašu kontakta punktu (pārvēršot to bērna koordinātu sistēmā):
    • Pirmais bērns, kura hitTest(_:with:) metode atgriež ne-nil rezultātu, tiek uzskatīts par "sasniegtu" un šis rezultāts tiek atgriezts augšup:
    • Ja neviens bērns neietver punktu, bet pašreizējais skatījums to ietver un userInteractionEnabled ir true, sistēma uzskata, ka kontakts noticis pašreizējā skatījumā, un metode atgriež self:
    • Ja userInteractionEnabled pašreizējā skatījumā ir false, vai hidden ir true, vai alpha ir mazāks par 0.01, metode atgriež nil, pat ja punkts ir robežās:

Process turpinās hierarhijā uz leju, līdz tiek atrasts zemākais skatījums, kas ietver kontakta punktu. Šis skatījums kļūst par hit-test view vai hit-test result, un tieši tam (vai tuvākajam tā priekšā) tiks deleģēta turpmākā notikumu pārvaldība (touchesBegan, touchesMoved utt.):

Šādi var pārdefinēt hitTest vai point(inside:with:) pielāgotai hit-testēšanas uzvedībai:

import UIKit

class CustomView: UIView {

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        // Pārbauda, vai punkts ir mūsu skatījumā.
        if !self.point(inside: point, with: event) {
            return nil
        }

        // Pāriet cauri bērniem atpakaļejošā secībā.
        for subview in subviews.reversed() {
            let convertedPoint = subview.convert(point, from: self)
            if let hitTestView = subview.hitTest(convertedPoint, with: event) {
                return hitTestView
            }
        }
        // Ja neviens neietver, atgriež self:
        return self
    }

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        // Standarta pārbaude: vai punkts ir iekšā bounds un vai skatījums ir aktīvs:
        // return super.point(inside: point, with: event)

        // Pielāgojums, piemēram, paplašināt kontaktu zonu:
        let extendedBounds = bounds.insetBy(dx: -20, dy: -20) // Paplašinām par 20 punktiem
        return extendedBounds.contains(point)
    }
}