SwiftUI: Как я могу определить, пересекаются ли два вида друг с другом? - PullRequest
0 голосов
/ 26 февраля 2020

Один вид пересекает другой. Как мы можем обнаружить это пересечение в SwiftUI?

В Swift я достиг бы этого с помощью нескольких строк кода:

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    let a = UIView(frame: CGRect(x: 100, y: 100, width: 150, height: 150))
    a.backgroundColor = .purple
    view.addSubview(a)

    let b = UIView(frame: CGRect(x: 150, y: 150, width: 150, height: 150))
    b.backgroundColor = .orange
    view.addSubview(b)

    if a.frame.intersects(b.frame) {
        print("yes!")
    } else {
        print("no intersection!")
    }

  }

}

Очевидно, что это не относится к SwiftUI: у нас есть другой Концепция рам здесь. Что может работать вместо этого? У кого-нибудь есть идея?

enter image description here

Обновление:

Большое спасибо за user3441734 и Asperi за помощь и предложения! Вот моя попытка решить проблему, используя массив прямоугольников:

import SwiftUI

struct ContentView: View {

@State var rect = CGRect()
@State var aRects = [CGRect]()


var body: some View {

    VStack {
        ZStack {
            Rectangle()
                  .frame(width: 150, height: 300)
                  .foregroundColor(.purple)
                  .background(self.rectReader(self.$rect))
                  HStack {
                      Spacer()
                      Spacer()
                      Spacer()
                      Rectangle()
                          .frame(width: 150, height: 180)
                          .foregroundColor(.pink)
                         .background(self.rectReader(self.$rect))
                      Spacer()
                  }
            }

        Button(action: {
             //print("aRects: \(self.aRects)")
             self.checkIntersection()
         }){
            Text("Check Intersection!")
         }
    }



}


// fill array of rects here
func rectReader(_ binding: Binding<CGRect>) -> some View {
    return GeometryReader { (geometry) -> AnyView in
        let rect = geometry.frame(in: .global)
        DispatchQueue.main.async {
            binding.wrappedValue = rect
            print("rect: \(self.rect)")
            self.aRects.append(self.rect)
        }
        return AnyView(Rectangle().fill(Color.clear))
    }
}

func checkIntersection() {
    if aRects.count == 2 {
        if self.aRects[0].intersects(self.aRects[1]) {
            print("yes!")
        } else {
            print("no!")
        }
    }
}

}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
    ContentView()
}
}

enter image description here

1 Ответ

0 голосов
/ 26 февраля 2020

Ваш вопрос совсем не тупой!

Вроде бы просто

  1. прочитать кадр первого просмотра (в глобальных координатах) и сохранить его в настройках
  2. прочитать кадр второго просмотра (в глобальных координатах) и сохранить его в настройках
  3. вычислить пересечение при изменении настроек

создать нашу структуру ключей предпочтений легко , это было уже объяснено на этом веб-сайте ранее (используйте поиск для более подробной информации: -))

struct Sizes: PreferenceKey {
    typealias Value = [CGRect]
    static var defaultValue: [CGRect] = []

    static func reduce(value: inout [CGRect], nextValue: () -> [CGRect]) {
        value.append(contentsOf: nextValue())
    }
}

с использованием GeometryReader в фоновом режиме Модификатор вида уже объяснен

struct SizeReader: View {
    var body: some View {
        GeometryReader { proxy in
            Color.clear
            .preference(key: Sizes.self, value: [proxy.frame(in: .global)])
        }
    }
}

и теперь мы можете использовать его для сохранения прямоугольников в нашем ключе настройки размеров

RectView(color: .pink).background(SizeReader())

А как насчет нашего RectView? Чтобы продемонстрировать, как работает наше «простое решение», представьте, что кто-то создал его со случайным размером и случайным выравниванием

struct RectView: View {
    let color: Color
    let size = CGFloat(Int.random(in: 50 ... 200))
    var body: some View {
        color.frame(width: size, height: size)
            .alignmentGuide(HorizontalAlignment.center) {
                CGFloat.random(in: 0 ..< $0.width)
            }
            .alignmentGuide(VerticalAlignment.center) {
                CGFloat.random(in: 0 ..< $0.width)
            }
    }
}

, пока все хорошо, мы готовы проверить наше «простое решение»

Позволяет завершить sh наш проект с

struct ContentView: View {
    @State var id = UUID()
    var body: some View {
        VStack {
            ZStack {
                Color.black
                RectView(color: .pink)
                    .background(SizeReader())
                RectView(color: .yellow)
                    .background(SizeReader())
                    .blendMode(.difference)
            }
            .onPreferenceChange(Sizes.self) { (value) in
                let intersection = value[0].intersection(value[1])
                print(value[0])
                print(value[1])
                print(intersection)
                print()
            }
            .onTapGesture {
                self.id = UUID()
            }
            Text("paceholder").id(id)
        }
    }
}

Запустите его, и каждый раз, когда вы нажимаете на черную часть экрана, вы видите два прямоугольника произвольного размера и позиционирования и в окне отладки распечатывает значения наш интерес.

enter image description here

ПРЕДУПРЕЖДЕНИЕ проверьте распечатку, и вы увидите, что что-то не так!

Код является ошибочным примером, и я поместил его здесь, чтобы продемонстрировать, что ваш вопрос вовсе не глупый! Есть много мыслей, чтобы понять о макете SwiftUI и о том, как он работает за кулисами.

Надеюсь, кто-нибудь умный попытается объяснить, что не так, и подскажет нам, как сделать это функционал, все специалисты приветствуются! Пожалуйста, не меняйте RectView, думайте, что это какой-то встроенный компонент SwiftUI

...