我需要根据给定的
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)
}
}
结果:
我认为,那里的问题是您试图将红色标题“气泡”与紫色突出显示和容器对齐。通常,我会使用
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
)不保存任何代码,但在我看来,更容易理解和重用。
如果您有其他问题,请告诉我这是否可以解决问题。
问候, –巴格兰