使用位置修饰符时使 SwiftUI Shape 采用整个屏幕宽度减去填充

问题描述 投票:0回答:1

我需要根据给定的

CGRect
框架来定位视图,并且下面的几个像素渲染一个
RoundedRectangle
,它始终占据屏幕的整个宽度减去 20pts 水平填充(无论内部文本长度如何)。为了定位第一个视图,我使用
position
修改器,它似乎工作得很好,但是当涉及到绘制第二个
RoundedRectangle
并使其始终采用整个宽度减去 20 点水平填充时,它不起作用原因是视图一直定位在左侧并且忽略了填充(检查结果图片)。

代码很简单,如下:

struct TestView: View {
    
    let testFrame = CGRect(x: 20, y: 200, width: 240, height: 48)
    
    var body: some View {
            VStack(spacing: 20) {
                RoundedRectangle(cornerRadius: 16)
                    .stroke(.purple, lineWidth: 4)
                    .frame(width: testFrame.width, height: testFrame.height)
                //This should always take the entire width of the screen minus 20 pts horizontal padding and height be dynamic depending on inner Text / View sizes and lengths.
                VStack(alignment: .leading) {
                    Text("Some title")
                    Text("Some subtitle")
                }
                .frame(maxWidth: .infinity)
                .padding()
                .background(RoundedRectangle(cornerRadius: 16).foregroundColor(.red))
                .padding(.horizontal, 20)
            }
            .position(x: testFrame.midX, y: testFrame.midY)
    }
}

结果:

ios swiftui layout
1个回答
0
投票

我认为,那里的问题是您试图将红色标题“气泡”与紫色突出显示和容器对齐。通常,我会使用

GeometryReader
或自定义
Layout
来处理它,而不是与“内置”布局争论,只是为了头脑清晰,但这里有两种方法:

import SwiftUI

struct E25: View {
    
    let testFrame = CGRect(x: 20, y: 200, width: 240, height: 48)
    
    var body: some View {
        RoundedRectangle(cornerRadius: 16)
            .stroke(.purple, lineWidth: 4)
            .frame(width: testFrame.width, height: testFrame.height)
            .position(x: testFrame.midX, y: testFrame.midY)
            .overlay(alignment: .top) {
                VStack(alignment: .leading) {
                    Text("Some title")
                    Text("Some subtitle")
                }
                .frame(maxWidth: .infinity)
                .padding()
                .background(RoundedRectangle(cornerRadius: 16).foregroundColor(.red))
                .padding(.horizontal, 20)
                .offset(y: testFrame.maxY + 20)
            }
    }
    
    var altBody: some View {
        CustomLayout(rect: testFrame) {
            RoundedRectangle(cornerRadius: 16)
                .stroke(.purple, lineWidth: 4)
            
            ZStack {
                Color.red
                VStack(alignment: .leading) {
                    Text("Some title")
                    Text("Some subtitle")
                }
                .padding()
            }
            .clipShape(RoundedRectangle(cornerRadius: 16))
            .padding(.horizontal, 20)
        }
    }
    
    struct CustomLayout: Layout {
        let rect: CGRect
        var captionGap: CGFloat = 20
        
        func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
            
            // The highligh view
            guard let highlight = subviews.first else { return }
            highlight.place(
                at: CGPoint(
                    x: bounds.minX + rect.minX,
                    y: bounds.minY + rect.minY
                ),
                anchor: .topLeading,
                proposal: ProposedViewSize(rect.size)
            )
            
            // The optional caption view
            guard subviews.count >= 2 else { return }
            let caption = subviews[1]
            
            caption.place(
                at: CGPoint(
                    x: bounds.minX,
                    y: bounds.minY + rect.maxY + captionGap
                ),
                anchor: .topLeading,
                proposal: ProposedViewSize(width: bounds.width, height: .none)
            )
        }
        
        func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
            proposal.replacingUnspecifiedDimensions()
        }
    }
}

#Preview {
    E25()
}

第一种方法是对代码稍作修改,但带有

overlay
。有点违反直觉,它之所以有效,是因为
position
使修改后的视图变得“贪婪”(例如,视图现在占用了所有可用空间)。

第二种方法(

altBody
)不保存任何代码,但在我看来,更容易理解和重用。

如果您有其他问题,请告诉我这是否可以解决问题。

问候, –巴格兰

© www.soinside.com 2019 - 2024. All rights reserved.