Sobes.tech
Middle

როგორ განსაზღვრავს სისტემა, რომელ ხედში შეხება მოხდა?

sobes.tech AI

პასუხი AI-სგან

სისტემა იყენებს ორი ძირითადი მექანიზმს: ჰიტ-ტესტირება (hit-testing) და ვიუების ჰიერქია:

  1. ჰიტ-ტესტირება (Hit-testing): UIKit ჩარჩო იყენებს hitTest(_:with:) მეთოდს UIWindow-ის ძირითადი ვიუისთვის იმის განსაზღვრად, რომელი ვიუ მდებარეობს შეხების წერტილში. ეს მეთოდი რეკურსიულად გადის ვიუების ჰიერქიას, დაწყებული ძირითადი ვიუიდან:

  2. ვიუების ჰიერქია:

    • hitTest(_:with:) მეთოდი პირველ რიგში ამოწმებს, არის თუ არა შეხების წერტილი მიმდინარე ვიუის საზღვრებში. თუ არა, აბრუნებს nil:
    • თუ არის, ის გადის შვილების ვიუებზე საპირისპირო წესით (ბოლოს დამატებული პირველი). თითოეულ შვილზე გამოიძახება მისი hitTest(_:with:) მეთოდი იგივე წერტილით (გადაყვანილი შვილ ვიუის კოორდინატებში):
    • პირველი შვილს, რომლის hitTest(_:with:) მეთოდი აბრუნებს არა-nil შედეგს, ითვლება "მიზეზად" და ეს შედეგი აბრუნებს ზემოთ:
    • თუ არც ერთი შვილი არ შეიცავს წერტილს, ხოლო მიმდინარე ვიუ შეიცავს მას და userInteractionEnabled არის true, მაშინ სისტემა მიიჩნევს, რომ შეხება მოხდა მიმდინარე ვიუზე, და მეთოდი აბრუნებს self:
    • თუ userInteractionEnabled მიმდინარე ვიუზე არის false, ან hidden არის true, ან alpha ნაკლებია 0.01-ზე, მეთოდი აბრუნებს nil, მიუხედავად იმისა, რომ წერტილი საზღვრებშია:

პროცესი გრძელდება ქვემოთ ჰიერქიაში, სანამ არ იპოვება ყველაზე ქვედა ვიუ, რომელიც შეიცავს შეხების წერტილს. ეს ვიუ ხდება hit-test view ან hit-test result, და სწორედ მას (ან მის უახლოეს შესაბამის წინამძღვარს) მიენიჭება შემდგომი მოვალეობა (მეთოდები touchesBegan, touchesMoved და ა.შ.):

როგორ შეიძლება გადახაზოთ hitTest ან point(inside:with:) მორგებული ქცევისთვის:

import UIKit

class CustomView: UIView {

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        // შემოწმება, არის თუ არა წერტილი ჩვენს ვიუში.
        if !self.point(inside: point, with: event) {
            return nil
        }

        // ვატარებთ შვილებს საპირისპირო წესით.
        for subview in subviews.reversed() {
            let convertedPoint = subview.convert(point, from: self)
            if let hitTestView = subview.hitTest(convertedPoint, with: event) {
                return hitTestView
            }
        }
        // თუ არავინ არ მოიცვა, ვუბრუნებთ self-ს:
        return self
    }

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        // სტანდარტული შემოწმება: არის თუ არა წერტილი bounds-ის შიგნით და აქტიურია თუ არა:
        // return super.point(inside: point, with: event)

        // მორგება, მაგალითად, გაფართოებული ზონა:
        let extendedBounds = bounds.insetBy(dx: -20, dy: -20) // 20 პიქსელით გაფართოება
        return extendedBounds.contains(point)
    }
}