Sobes.tech
Middle

Sistem dokunuşun hangi görünüme ait olduğunu nasıl belirler?

sobes.tech yapay zeka

AI'dan gelen yanıt

Sistem iki temel mekanizmayı kullanır: hit-test (dokunma testi) ve görünüm hiyerarşisi.

  1. Hit-test (Dokunma Testi): UIKit framework'ü, pencerenin kök görünümünün hitTest(_:with:) metodunu kullanarak, dokunma noktasının altında hangi görünümün olduğunu belirler. Bu yöntem, kök görünümden başlayarak hiyerarşiyi rekürsif olarak dolaşır.

  2. Görünüm Hiyerarşisi:

    • hitTest(_:with:) yöntemi önce dokunma noktasının mevcut görünüm sınırları içinde olup olmadığını kontrol eder. Değilse, nil döner.
    • Nokta sınırlar içindeyse, çocuk görünümleri ters sırayla (son eklenenden ilk eklenene) inceler. Her çocuk görünüm için, aynı noktayı kullanarak hitTest(_:with:) çağrısı yapılır (koordinatlar çocuk görünümüne dönüştürülerek).
    • hitTest(_:with:) yöntemi nil olmayan bir sonuç döndürürse (yani, nokta bu görünüm veya alt görünümleri tarafından içeriliyorsa), bu sonuç yukarı doğru geri döndürülür.
    • Hiçbir çocuk görünüm nokta ile ilgilenmiyorsa ve mevcut görünüm nokta içeriyorsa ve userInteractionEnabled false değilse, self döndürülür.
    • Eğer userInteractionEnabled false ise, veya hidden true ise, veya alpha 0.01'den küçükse, nil döndürülür, nokta sınırlar içinde olsa bile.

İşlem, en alttaki görünüm bulunana kadar aşağı doğru devam eder. Bu görünüm, hit-test view veya hit-test result olur ve olayların yönetimi ona (veya en yakın uygun atasına) devredilir (touchesBegan, touchesMoved vb. metodlar).

İşte hitTest veya point(inside:with:) metodunu özelleştirilmiş davranışlar için nasıl geçersiz kılacağınız:

import UIKit

class CustomView: UIView {

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        // Noktanın bu görünüm içinde olup olmadığını kontrol et.
        if !self.point(inside: point, with: event) {
            return nil
        }

        // Çocuk görünümleri ters sırayla dolaşır.
        for subview in subviews.reversed() {
            // Noktayı çocuk görünümün koordinatlarına dönüştür.
            let convertedPoint = subview.convert(point, from: self)

            // Rekürsif olarak hitTest çağrısı yap.
            if let hitTestView = subview.hitTest(convertedPoint, with: event) {
                // Çocuk görünüm veya onun alt görünümleri noktayı içeriyorsa, sonucu döndür.
                return hitTestView
            }
        }

        // Hiçbir çocuk görünüm olayla ilgilenmediyse,
        // ve bu görünüm etkileşimliyse ve nokta içeriyorsa, kendisini döndür.
        return self
    }

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        // Temel uygulama, noktanın sınırlar içinde olup olmadığını ve görünümün etkileşimli olup olmadığını kontrol eder.
        // return super.point(inside: point, with: event)

        // Özelleştirilmiş şekiller veya boşluklar için yeniden tanımlanabilir, örneğin dokunma alanını genişletmek.
        let extendedBounds = bounds.insetBy(dx: -20, dy: -20) // Tüm taraflara 20pt ekle
        return extendedBounds.contains(point)
    }
}

point(inside:with:) metodu, hitTest(_:with:) tarafından çağrılır ve noktayı görünüm alanı içinde hızlıca kontrol eder, çocuk görünümleri kontrol etmeden önce.

Sonuç olarak, hiyerarşide en alttaki ve dokunma noktasını içeren, userInteractionEnabled değeri true, hidden false ve alpha 0.01'den büyük olan görünüm, hit-test view olarak kabul edilir.