Giu*_*Dev 4 layout ios swift swiftui
我想显示一个数学分数。为此,我有一个 VStack,其中包含分子视图(称为 ContainerView)、用作分数线的矩形和分母视图(与分子相同类型)。由于分数是可编辑的,因此分子和分母的大小可以改变,并且分数线必须相应地适应。我的第一次尝试是将分数线放在背景中,并使用几何阅读器仅根据分子和分母的大小来获取分数的框架。这样分数线就在背景的中心,大小是我想要的。这是代码:
\nstruct FractionView: View {\n\n@EnvironmentObject var buffer: Buffer\nvar numeratorBufferIndex: Int\nvar denominatorBufferIndex: Int\n\nvar body: some View {\n VStack(alignment: .center, spacing: 0) {\n ContainerView(activeBufferIndex: numeratorBufferIndex)\n .environmentObject(self.buffer)\n \n ContainerView(activeBufferIndex: denominatorBufferIndex)\n .environmentObject(self.buffer)\n }\n .background(GeometryReader { geometry in\n Rectangle()\n .frame(width: geometry.frame(in: .local).width, height: 2)\n .foregroundColor(Color(.systemGray))\n })\n}\n}\nRun Code Online (Sandbox Code Playgroud)\n这三个属性用于渲染分子和分母。结果是这样的。\n但是,由于它在后台,所以它不知道分子和分母的高度。当它们具有不同的大小时,就像在本例中一样,这会产生问题。在图像中,您可以看到分子中有另一个分数,因此其视图的高度更大。这会导致问题,因为第一条分数线穿过分子的一部分。
\n为了避免这种情况,我认为最好的方法是将分数线直接放在主 VStack 中,这样它就会除分子和分母而不关心它们的高度。然而,矩形形状占用了所有可用空间,我不知道如何将其宽度限制为父级的宽度。这是新代码及其外观:
\nstruct FractionView: View {\n\n@EnvironmentObject var buffer: Buffer\nvar numeratorBufferIndex: Int\nvar denominatorBufferIndex: Int\n\nvar body: some View {\n VStack(alignment: .center, spacing: 0) {\n ContainerView(activeBufferIndex: numeratorBufferIndex)\n .environmentObject(self.buffer)\n \n Rectangle()\n .frame(height: 2)\n .foregroundColor(Color(.systemGray))\n \n ContainerView(activeBufferIndex: denominatorBufferIndex)\n .environmentObject(self.buffer)\n }\n}\n}\nRun Code Online (Sandbox Code Playgroud)\n总而言之,我必须找到一种方法将矩形的宽度限制为 VStack 没有它时的宽度。我尝试按照本文的示例使用首选项。
\n这是我尝试过的:
\nstruct FractionView: View {\n\n@EnvironmentObject var buffer: Buffer\n@State var fractionFrame: CGFloat = 0\nvar numeratorBufferIndex: Int\nvar denominatorBufferIndex: Int\n\nvar body: some View {\n VStack(alignment: .center, spacing: 0) {\n ContainerView(activeBufferIndex: numeratorBufferIndex)\n .environmentObject(self.buffer)\n \n Rectangle()\n .frame(width: fractionFrame, height: 2)\n .foregroundColor(Color(.systemGray))\n \n ContainerView(activeBufferIndex: denominatorBufferIndex)\n .environmentObject(self.buffer)\n }\n.coordinateSpace(name: "VStack")\n .background(GeometryObteiner())\n .onPreferenceChange(MyFractionPreferenceKey.self) { (value) in\n print("Il valore della larghezza \xc3\xa8 \\(value)")\n self.fractionFrame = value\n }\n \n}\n}\n\nstruct GeometryObteiner: View {\nvar body: some View {\n GeometryReader { geometry in\n Rectangle()\n .frame(width: geometry.frame(in: .global).width, height: geometry.frame(in: .global).height)\n .foregroundColor(.clear)\n .preference(key: MyFractionPreferenceKey.self, value: geometry.frame(in: .named("VStack")).width)\n }\n}\n}\n\nstruct MyFractionPreferenceKey: PreferenceKey {\ntypealias Value = CGFloat\n\nstatic var defaultValue: CGFloat = 10\n\nstatic func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {\n value = nextValue()\n}\n}\nRun Code Online (Sandbox Code Playgroud)\n然而,似乎从未调用过 onPreferenceChange,因为结果始终是分数线具有默认值 (10) 的宽度。
\n也许解决方案比我想象的要容易得多,但我无法弄清楚。我知道我写的可能有点令人困惑,如果您需要任何澄清,请在评论中询问我。
\n这里应用了与您的场景评论相同的想法。当然,它只是草图,但在我看来,它可以根据需要进行调整并使其通用(Text例如,替换当前使用的View或FullFraction本身以构造更复杂的分数)。
演示(因为 DispatchQueue 用于避免在视图绘制警告期间进行修改,您应该运行它来查看结果):

代码(截图演示):
struct FullFraction: View {
var whole: String = ""
var num: String
var denom: String
@State private var numWidth: CGFloat = 12.0 // just initial
@State private var denomWidth: CGFloat = 12.0 // just initial
var body: some View {
HStack {
Text(whole)
VStack {
numerator
divider
denominator
}
}
}
var numerator: some View {
Text(num)
.offset(x: 0, y: 8)
.alignmentGuide(HorizontalAlignment.center, computeValue: { d in
DispatchQueue.main.async {
self.numWidth = d.width
}
return d[HorizontalAlignment.center]
})
}
var denominator: some View {
Text(denom)
.offset(x: 0, y: -4)
.alignmentGuide(HorizontalAlignment.center, computeValue: { d in
DispatchQueue.main.async {
self.denomWidth = d.width
}
return d[HorizontalAlignment.center]
})
}
var divider: some View {
Rectangle().fill(Color.black).frame(width:max(self.numWidth, self.denomWidth), height: 2.0)
}
}
struct DemoFraction: View {
var body: some View {
VStack {
FullFraction(whole: "F", num: "(a + b)", denom: "c")
Divider()
FullFraction(whole: "ab12", num: "13", denom: "761")
Divider()
FullFraction(num: "1111", denom: "3")
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3023 次 |
| 最近记录: |