簡體   English   中英

SwiftUI 如何動態地使視圖的前導等於其與超級視圖的頂部距離

[英]SwiftUI How to dynamically make a view's leading equal to its top distance to superview

下圖顯示了一個包含三行文本的VStack

VStack位於ZStack中,該 ZStack 還包含一個藍色方塊。

我已經能夠 position 藍色正方形,使其垂直中心等於“第 1 行” Text的垂直中心。 無論文本大小如何,都必須保持這種關系。 換句話說,我無法硬編碼藍色方塊的垂直偏移的特定值,因為它取決於右側Text的大小。

注意文本上方和下方的綠線。 這表示容器視圖的頂部和底部邊緣。

我想做的(但不知道怎么做)是 position 藍色方塊的前緣與藍色方塊的頂部邊緣到頂部綠線的距離相同。

例如,假設藍色框垂直放置后,它的頂部恰好從頂部的綠線向下 12 點。 在這種情況下,盒子應該移動 12 點到容器左邊緣的右側。

在此處輸入圖像描述

這是我正在處理的代碼:

import SwiftUI

extension Alignment {
    static let blueBoxAlignment = Alignment(horizontal: .blueBoxLeadingAlignment, vertical: .blueBoxCenterAlignment)
}

extension HorizontalAlignment {
    private enum BlueBoxHorizontalAlignment: AlignmentID {
        static func defaultValue(in d: ViewDimensions) -> CGFloat {
            return d[HorizontalAlignment.leading]
        }
    }
    static let blueBoxLeadingAlignment = HorizontalAlignment(BlueBoxHorizontalAlignment.self)
}

extension VerticalAlignment {
    private enum BlueBoxCenterAlignment: AlignmentID {
        static func defaultValue(in d: ViewDimensions) -> CGFloat {
            return d[VerticalAlignment.center]
        }
    }

    static let blueBoxCenterAlignment = VerticalAlignment(BlueBoxCenterAlignment.self)
}

struct TestView: View {
    var body: some View {
        ZStack(alignment: .blueBoxAlignment) {
            VStack(spacing: 50) {
                Text("Line 1")
                    .alignmentGuide(.blueBoxCenterAlignment) { d in d[VerticalAlignment.center] }
                Text("Line 2")
                Text("Line 3")
            }
            .padding([.top, .bottom], 50)
            .frame(maxWidth: .infinity)
            .border(.green)

            Rectangle()
                .fill(.blue)
                .opacity(0.5)
                .frame(width: 50, height: 50)
        }
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        TestView()
            .edgesIgnoringSafeArea(.bottom)
    }
}

可能的方法是使用錨首選項,因為它們允許讀取目標視圖的不同 position 屬性並在視圖布局周期內使用。

這是一個演示。 使用 Xcode 13.2 / iOS 15.2 測試

演示

注意:使用padding代替offset ,因為 offset 不影響布局,以防萬一。

struct PositionPreferenceKey: PreferenceKey {   // << helper key !!
    static var defaultValue: [Anchor<CGPoint>] = [] // << use something persistent

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

struct TestView: View {
    @State private var offset = CGFloat.zero

    var body: some View {
        ZStack(alignment: .blueBoxAlignment) {
            VStack(spacing: 50) {
                Text("Line 1")
                    .alignmentGuide(.blueBoxCenterAlignment) { d in d[VerticalAlignment.center] }
                Text("Line 2")
                Text("Line 3")
            }
            .padding([.top, .bottom], 50)
            .frame(maxWidth: .infinity)
            .border(.green)

            Rectangle()
                .fill(.blue)
                .opacity(0.5)
                .frame(width: 50, height: 50)
                .anchorPreference(
                    key: PositionPreferenceKey.self,
                    value: .top               // read position from top !!
                ) { [$0] }
                .padding(.leading, offset)    // << apply as X !!
        }
        .backgroundPreferenceValue(PositionPreferenceKey.self) { prefs in
            GeometryReader { gr in
                Color.clear.onAppear {
                    self.offset = gr[prefs[0]].y  // << store Y !!
                }
            }
        }
    }
}

備份

暫無
暫無

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

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