找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3960|回复: 0

求救!被 coordinateSpace 给绕晕了

[复制链接]

310

主题

0

回帖

956

积分

管理员

积分
956
发表于 2023-12-6 11:21:45 | 显示全部楼层 |阅读模式
官方对 coordinateSpace 的解释是:

Assigns a name to the view’s coordinate space, so other code can operate on dimensions like points and sizes relative to the named space.

我的理解是,用户可以给某个 view 的空间坐标取个名字,然后获取到其他 view 在指定名字空间中的相对坐标。
比如横向排列 3 个圆形。

⭕️⭕️⭕️

计算第 2 个圆形相对于第 3 个圆形的相对坐标。由于第 2 个⭕️在第三个⭕️的左侧,相对坐标的 x 值,应该是负数。
在第 2 个⭕️中,print(proxy.frame(in: .named("circle3")).origin)的输出结果总是正的。
是我对 coordinateSpace 的理解有问题吗?
var body: some View {
    HStack(spacing:0) {
        Circle()
            .fill(.red)
                .frame(width: 100, height: 100)
                .coordinateSpace(name: "circle1")

            GeometryReader{ proxy in
                Circle()
                    .fill(.green)
                    .frame(width: 100, height: 100)
                    .coordinateSpace(name: "circle2")
                    .onTapGesture {
                        print(proxy.frame(in: .named("circle3")).origin);
                    }
            }

            Circle()
            .fill(.blue)
            .frame(width: 100, height: 100)
            .coordinateSpace(name: "circle3")
        }
        .coordinateSpace(name: "stack")
    }

看官方说明完全找不到头绪。
https://developer.apple.com/documentation/swiftui/view/coordinatespace(name

看样子大家注意力都在俄乌上了
https://swiftontap.com/coordinatespace曾经收藏的一个文档 可以看看 不确定是否对楼主有帮助
@justin2018 谢谢。这个我看过,不过没有解决我的疑惑。
看 #2 文档貌似仅相对于父容器?比如换成 stack 就应该正常
@goldenlove > “看 #2 文档貌似仅相对于父容器?”它虽然提到了 parent 之类的,但没有说必须是父容器。官方文档里面也没有说需要父容器。而且,上面给的只是一个 Demo ,我在实际的项目里面,相对父容器得到的值也不对。
试一下这个:``` var body: some View { HStack(spacing:0) { Circle() .fill(.red) .frame(width: 100, height: 100) .coordinateSpace(name: "circle1") GeometryReader{ proxy in Circle() .fill(.green) .frame(width: 100, height: 100) .coordinateSpace(name: "circle2") .onTapGesture { print(proxy.frame(in: .named("circle1")).origin) print(proxy.frame(in: .named("circle3")).origin) print(proxy.frame(in: .named("stack")).origin) print(proxy.frame(in: .global).origin) } }.frame(width: 100, height: 100) Circle() .fill(.blue) .frame(width: 100, height: 100) .coordinateSpace(name: "circle3") } .coordinateSpace(name: "stack") }```看起来确实是必须父容器,不然会找不到,default 到全局坐标系。
@sillydaddy 相对父容器得到的值不对,有可能是你视觉上理解的父容器 /子元素的位置和它的实际坐标系有偏差,比如说可能涉及了 offset 这种。或者你跟 global 坐标系的值比对一下,看看是不是依然是同一个问题。
@minsheng 我可能找到问题所在了:多级父容器中,如果用到了 List ,可能会导致结果不对。比如下面的代码,把外层的 HStack 的空间坐标系命名为"parent",然后取 Text("a")相对这个坐标系的坐标,发现有问题,水平拖拽这个 HStack ,会发现取得的相对坐标在不断变化,而正常来说,相对坐标应该是固定不变的。如果把 List 改成 VStack ,就没有这个问题。我猜测,是 List 作为 Text("a")的直接父容器,「扰乱」或者「阻隔」了取相对坐标的功能。```struct XOffsetPrefercence: PreferenceKey{ static var defaultValue: Float = 0.0; static func reduce(value: inout Float, nextValue: () -> Float){ print("value=", value, ",", "nextValue=", nextValue()); value = nextValue(); }}struct ContentView: View { var body: some View { ScrollView(.horizontal){ HStack{ List{ Text("a") .overlay(content: { GeometryReader{ geoitem in Color.red.frame(width: 150, height: 2) .preference(key: XOffsetPrefercence.self, value: Float(geoitem.frame(in:.named("parent") ).minX)) } })  Text("b") }.frame(width: 200)  List{ Text("c") Text("d") }.frame(width: 200) } .coordinateSpace(name: "parent") .onPreferenceChange(XOffsetPrefercence.self){ value in print("xoffset:", value); } } }}```
@minsheng @goldenlove @justin2018 结帖。看#8 楼,应该算是发现问题的表面原因了。感叹一下,SwiftUI 虽然很简洁强大,但还是有很多坑要趟。仅仅用了它一个 List 和 coordinateSpace ,就要耗费我这么多精力。😂
@sillydaddy List 底层应该是 UITableView 或者 UICollectionView ,每一个 cell 都是通过 UIHostingController 包起来的。目前来看应该是 UIHostingController 内部的 view 没有办法访问到外部的 coordinate space 。可能是一个 bug ,毕竟 EnvironmentValues 是可以跨 UIHostingController 传的;可能不是,你定义的 onPreferenceChange 其实并没有拿到 List 里的 view hierarchy 传上来的内容。
下面这个例子可以看到 UIHostingController 对 coordinate space 的影响:struct ContentView: View { var body: some View { HStack { Color.blue.frame(width: 200) HStack { Color.green.frame(width: 100) InnerHost() .background { GeometryReader { proxy in let _ = print("Outer", proxy.frame(in: .named("parent")).origin) Color.clear } } }.coordinateSpace(name: "parent") } }}struct Inner: View { var body: some View { GeometryReader { proxy in let _ = print("Inner", proxy.frame(in: .named("parent")).origin) Color.red } }}struct InnerHost: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> some UIViewController { UIHostingController(rootView: Inner()) } func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { }}
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|鲜于璜碑

GMT+8, 2024-9-8 11:42 , Processed in 0.201922 second(s), 20 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表