Sobes.tech
Middle

Tizim qanday qilib tegishni qaysi ko'rinishga tushganligini aniqlaydi?

sobes.tech AI

AIdan javob

Sistem ikki asosiy mexanizmni ishlatadi: hit-test (teginish test) va ko‘rinishlar hierarxiyasi.

  1. Hit-test: UIKit frameworki hitTest(_:with:) metodidan foydalanadi, bu metod oynaning asosiy ko‘rinishi (UIWindow) ostidagi qaysi ko‘rinish teginish nuqtasining ostida ekanligini aniqlash uchun. Bu metod rekursiv tarzda ko‘rinishlar hierarxiyasini yuradi, boshlang‘ich sifatida asosiy.

  2. Ko‘rinishlar hierarxiyasi:

    • hitTest(_:with:) avvalo, nuqtaning hozirgi ko‘rinish chegaralarida joylashganligini tekshiradi. Agar joylashmagan bo‘lsa, nil qaytaradi.
    • Agar nuqta chegaralar ichida bo‘lsa, metod bolalar ko‘rinishlarini teskari tartibda (so‘nggi qo‘shilganidan birinchi qo‘shilganigacha) tekshiradi. Har bir bolaga, uning hitTest(_:with:) metodini, ayni nuqtada chaqiradi (nuqtani bolaning koordinatlariga o‘tkazib).
    • hitTest(_:with:) metodidan nil bo‘lmagan natija olinsa (ya’ni, u yoki uning bolalaridan biri nuqtani o‘z ichiga olsa), bu "teginilgan" deb hisoblanadi va natija yuqoriga qaytariladi.
    • Agar hech qanday bola nuqtani o‘z ichiga olmasa va hozirgi ko‘rinish nuqtani o‘z ichiga olsa va userInteractionEnabled false emas bo‘lsa, self qaytariladi.
    • Agar userInteractionEnabled hozirgi ko‘rinishda false bo‘lsa, yoki hidden true bo‘lsa, yoki alpha 0.01 dan kichik bo‘lsa, metod nil qaytaradi, hatto nuqta chegaralar ichida bo‘lsa ham.

Jarayon, nuqtani o‘z ichiga oladigan eng pastki ko‘rinishni topguncha davom etadi. Bu ko‘rinish hit-test view yoki hit-test result bo‘lib, unga (yoki uning eng yaqin mos keladigan ajdodiga) voqea boshqaruvi (touchesBegan, touchesMoved va boshqalar) delegatsiya qilinadi.

Mana hitTest yoki point(inside:with:) metodlarini qanday qilib maxsus xulq uchun qayta yozish mumkin:

import UIKit

class CustomView: UIView {

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        // Nuqtaning bu ko‘rinishda joylashganligini tekshirish.
        if !self.point(inside: point, with: event) {
            return nil
        }

        // Bolalar ko‘rinishlarini teskari tartibda tekshirish.
        for subview in subviews.reversed() {
            // Nuqtani bolaning koordinatlariga o‘tkazish.
            let convertedPoint = subview.convert(point, from: self)

            // Rekursiv tarzda hitTest chaqirish.
            if let hitTestView = subview.hitTest(convertedPoint, with: event) {
                // Agar bola yoki uning vorislari nuqtani o‘z ichiga olsa, natijani qaytar.
                return hitTestView
            }
        }

        // Agar hech qanday bola nuqtani qabul qilmasa,
        // va hozirgi ko‘rinish interaktiv bo‘lsa va nuqtani o‘z ichiga olsa, self qaytariladi.
        return self
    }

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        // Asosiy implementatsiya nuqtaning chegaralar ichida va ko‘rinish interaktivligini tekshiradi.
        // return super.point(inside: point, with: event)

        // Maxsus shakllar yoki bo‘sh joylar uchun qayta yozilishi mumkin, masalan, tegish maydonini kengaytirish.
        let extendedBounds = bounds.insetBy(dx: -20, dy: -20) // Har tomondan 20pts kengaytirish
        return extendedBounds.contains(point)
    }
}

point(inside:with:) metodi hitTest(_:with:) ichida chaqiriladi va nuqtaning ko‘rinish ichida joylashganligini tezda tekshirish uchun ishlatiladi, bolalar ko‘rinishlarini tekshirishdan oldin.

Natijada, hierarxiyada eng pastki va nuqtani o‘z ichiga oladigan, userInteractionEnabled true, hidden false va alpha 0.01 dan katta bo‘lgan ko‘rinish topiladi va u hit-test view sifatida tan olinadi.