簡體   English   中英

SwiftUI 在View上同時使用.offset和.position修飾符到底發生了什么,決定了最終的位置?

[英]SwiftUI What exactly happens when use .offset and .position Modifier simultaneously on a View, which decides the final location?

當我嘗試給 View 初始 position 時,我有這個問題,然后用戶可以使用拖動手勢將 View 的位置更改為任何位置。 雖然我已經通過僅在視圖上使用.position(x:y:)解決了這個問題,但一開始我在考慮使用.position(x:y:)來給出初始 position 和.offset(offset:)來制作同時查看手勢移動。 現在,我真的只想更詳細地了解,當我同時使用它們(下面的代碼)時到底發生了什么,所以我可以解釋下面的視圖中發生了什么。

我無法在下面的視圖中解釋的是:當我只是在 VStack 框上拖動手勢時,它會按預期工作並且 VStack 會隨着手指手勢移動,但是,一旦手勢結束並嘗試在 VStack 上開始新的拖動手勢,VStack盒子突然回到原來的position(就像加載代碼時跳轉到原來的position),然后開始隨着手勢移動。 請注意,手勢像常規手勢一樣移動,但 VStack 已經跳到不同的 position,因此它從不同的 position 開始移動。這導致指尖不再位於 VStack 框的頂部,而是離開了一段距離,盡管 VStack 的移動軌跡與拖動手勢的軌跡相同。

我的問題是:為什么.position(x:y:)修飾符似乎只在檢測到的每個新拖動手勢的最開始時生效,但在拖動手勢動作期間似乎.offset(offset:)主導了主要運動並且VStack 停在它被拖到的地方。 但是一旦啟用了新的拖動手勢,VStack 就會突然跳到原來的 position。我無法理解這種行為是如何通過時間軸發生的。 有人可以提供一些見解嗎?

請注意,我已經解決了這個問題以實現我所需要的,現在只是了解同時使用.position(x:y:).offset(offset:)時到底發生了什么,所以請避免一些建議之類的。 不要同時使用它們,謝謝。 下面的代碼假設在復制和粘貼后可以運行,如果不是,請原諒我的錯誤,因為我刪除了幾行以使其更清晰地重現問題。

import SwiftUI

struct ContentView: View {

    var body: some View {

        ButtonsViewOffset()
    }
}

struct ButtonsViewOffset: View {

    let location: CGPoint = CGPoint(x: 50, y: 50)
    @State private var offset = CGSize.zero
    @State private var color = Color.purple

    var dragGesture: some Gesture {
        DragGesture()
            .onChanged{ value in
                self.offset = value.translation
                print("offset onChange: \(offset)")
            }
            .onEnded{ _ in
                if self.color == Color.purple{
                    self.color = Color.blue
                }
                else{
                    self.color = Color.purple
                }

            }
    }
    
    var body: some View {
        VStack {
            Text("Watch 3-1")
            Text("x: \(self.location.x), y: \(self.location.y)")
        }
        .background(Color.gray)
        
        .foregroundColor(self.color)
        .offset(self.offset)
        .position(x: self.location.x, y: self.location.y)
        .gesture(dragGesture)
        
    }
}


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

您的問題與使用 position 和 offset 無關。 他們實際上同時工作。 Position 設置視圖的絕對值 position,偏移量相對於絕對值 position 移動它。因此,您會注意到您的視圖在屏幕上從 position (50, 50) 開始,然后您可以將它拖動到四周。 一旦你讓 go,它就停在原處。 到目前為止,一切都很好。 然后你想再次移動它,它會彈回到原來的 position。它這樣做的原因是你將位置設置為 let 常量的方式。 它需要是 state。

問題源於這樣一個事實,即您在沒有意識到的情況下將 offset 的值添加到 position。當您完成拖動時,offset 會保留最后的值。 但是,當您開始下一次拖動時,這些值再次從 (0,0) 開始,因此偏移量將重置為 (0,0) 並且視圖將移回原始 position。關鍵是您只需要使用position 或更新.onEnded中的偏移量。 不要同時使用兩者。 這里有一個集合 position,並且沒有保存偏移量。 您如何處理它取決於您移動視圖的目的。

首先,只需使用.position()

struct OffsetAndPositionView: View {
    
    @State private var position = CGPoint(x: 50, y: 50)
    @State private var color = Color.purple
    
    var dragGesture: some Gesture {
        DragGesture()
            .onChanged{ value in
                position = value.location
                print("position onChange: \(position)")
            }
            .onEnded{ value in
                if color == Color.purple{
                    color = Color.blue
                }
                else{
                    color = Color.purple
                }
            }
    }
    
    var body: some View {
        Rectangle()
            .fill(color)
            .frame(width: 30, height: 30)
            .position(position)
            .gesture(dragGesture)
    }
}

其次,只需使用.offset()

struct ButtonsViewOffset: View {
    @State private var savedOffset = CGSize.zero
    @State private var dragValue = CGSize.zero
    @State private var color = Color.purple
    
    var offset: CGSize {
        savedOffset + dragValue
    }

    var dragGesture: some Gesture {
        DragGesture()
            .onChanged{ value in
                dragValue = value.translation
                print("dragValue onChange: \(dragValue)")
            }
            .onEnded{ value in
                savedOffset = savedOffset + value.translation
                dragValue = CGSize.zero
                if color == Color.purple{
                    color = Color.blue
                }
                else{
                    color = Color.purple
                }
            }
    }

    var body: some View {
            Rectangle()
                .fill(color)
                .frame(width: 30, height: 30)
                .offset(offset)
                .gesture(dragGesture)
    }
}

// Convenience operator overload
func + (lhs: CGSize, rhs: CGSize) -> CGSize {
    return CGSize(width: lhs.width + rhs.width, height: lhs.height + rhs.height)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM