我想展示一个数学分数。为此,我有一个包含分子视图(称为ContainerView)的VStack、一个用作分数线的矩形和一个分母视图(与分子的类型相同)。由于分数是可编辑的,分子和分母的大小可以改变,因此分数线必须相应地进行调整。我的第一个尝试是将分数线放在背景中,并使用几何阅读器仅根据分子和分母的大小获得分数的框架。这样,分数线就在背景的中心,大小和我想要的一样大。代码如下:
struct FractionView: View {
@EnvironmentObject var buffer: Buffer
var numeratorBufferIndex: Int
var denominatorBufferIndex: Int
var body: some View {
VStack(alignment: .center, spacing: 0) {
ContainerView(activeBufferIndex: numeratorBufferIndex)
.environmentObject(self.buffer)
ContainerView(activeBufferIndex: denominatorBufferIndex)
.environmentObject(self.buffer)
}
.background(GeometryReader { geometry in
Rectangle()
.frame(width: geometry.frame(in: .local).width, height: 2)
.foregroundColor(Color(.systemGray))
})
}
}这三个属性用于渲染器、分子和分母。The result is this。但是,因为它在后台,所以它不知道分子和分母的高度。当它们的大小不同时,这就会产生问题,like in this case。在图像中,您可以看到分子中有另一个分数,因此其视图的高度较大。这会导致问题,因为第一个分数线通过分子的一部分。
为了避免这种情况,我认为最好的方法是将分数线直接放在主VStack中,这样它就可以划分分子和分母,而不考虑它们的高度。然而,矩形形状占用了所有可用的空间,我不知道如何将它的宽度限制为父对象的宽度。这是新的代码和what it looks like
struct FractionView: View {
@EnvironmentObject var buffer: Buffer
var numeratorBufferIndex: Int
var denominatorBufferIndex: Int
var body: some View {
VStack(alignment: .center, spacing: 0) {
ContainerView(activeBufferIndex: numeratorBufferIndex)
.environmentObject(self.buffer)
Rectangle()
.frame(height: 2)
.foregroundColor(Color(.systemGray))
ContainerView(activeBufferIndex: denominatorBufferIndex)
.environmentObject(self.buffer)
}
}
}总而言之,我必须找到一种方法,将矩形的宽度限制为VStack在没有矩形的情况下的宽度。我试着按照this article的例子使用首选项。这就是我尝试过的
struct FractionView: View {
@EnvironmentObject var buffer: Buffer
@State var fractionFrame: CGFloat = 0
var numeratorBufferIndex: Int
var denominatorBufferIndex: Int
var body: some View {
VStack(alignment: .center, spacing: 0) {
ContainerView(activeBufferIndex: numeratorBufferIndex)
.environmentObject(self.buffer)
Rectangle()
.frame(width: fractionFrame, height: 2)
.foregroundColor(Color(.systemGray))
ContainerView(activeBufferIndex: denominatorBufferIndex)
.environmentObject(self.buffer)
}
.coordinateSpace(name: "VStack")
.background(GeometryObteiner())
.onPreferenceChange(MyFractionPreferenceKey.self) { (value) in
print("Il valore della larghezza è \(value)")
self.fractionFrame = value
}
}
}
struct GeometryObteiner: View {
var body: some View {
GeometryReader { geometry in
Rectangle()
.frame(width: geometry.frame(in: .global).width, height: geometry.frame(in: .global).height)
.foregroundColor(.clear)
.preference(key: MyFractionPreferenceKey.self, value: geometry.frame(in: .named("VStack")).width)
}
}
}
struct MyFractionPreferenceKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue: CGFloat = 10
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}但是,似乎从未调用过onPreferenceChange,因为result始终是分数行具有缺省值(10)的宽度。
也许解决方案比我想的要简单得多,但我想不出来。我知道我写的东西可能有点混乱,如果你需要任何澄清,请在评论中问我。提前谢谢。
发布于 2019-12-23 15:40:52
这里应用了与您的场景注释相同的想法。当然,它只是很粗糙,但可以根据需要进行调整,并使其成为通用的(例如,用View或FullFraction本身替换当前使用的Text,以构造更复杂的分数)。
Demo (因为DispatchQueue是为了避免视图绘制过程中的修改,所以你应该运行它才能看到结果):

截图demo代码:
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")
}
}
}
struct DemoFraction_Previews: PreviewProvider {
static var previews: some View {
DemoFraction()
}
}https://stackoverflow.com/questions/59445483
复制相似问题