当成员具有 @State 修饰符时,不会呈现 swiftui 中的 PieChart
PieChart in swiftui is not rendered when a member has @State modifier
我正在创建一个应用程序并一起学习 swift/swiftui。我的应用程序使用带有 ForEach 循环的 Path 对象显示饼图。
当我将 _percentages 成员从普通成员更改为 @State 成员时,我基于带有路径的 ForEach 循环的饼图没有出现。
class 成员:
@State var data: [Float]
@State var colors: [Color]
@Binding var slicePressedNo: Int
var angles: [Float] = []
var offsets: [Float] = []
var total: Float = 0
private var _sortedData: [Float]
@State private var _percentages: [Float] = [] // Removing @State fixes the issue and everything works as expected
初始化函数:
init (data: [Float], colors: [Color], slicePressedNo: Binding<Int>) {
self._data = State(initialValue: data)
self._colors = State(initialValue: colors)
self._slicePressedNo = slicePressedNo
self._sortedData = data
var sum: Float = 0.0
for value in self.data {
sum += value
}
self._percentages.removeAll()
for value in self.data {
self._percentages.append((value / sum))
print("sum = \(sum)")
print("value = \(value)")
}
angles.removeAll()
offsets.removeAll()
offsets.append(0)
for value in self._percentages {
let angle = value * 360
angles.append(angle)
offsets.append(angle + offsets.last!)
}
for i in self._percentages.indices {
self._percentages[i] = self._percentages[i] * 100.0
print("% = \(self._percentages[i])")
}
total = sum
}
负责构建饼图切片的代码:
GeometryReader { geometry in
var offset: Float = 0.0
let width: CGFloat = min(geometry.size.width, geometry.size.height)
let height = width
let center = CGPoint(x: width * 0.5, y: height * 0.5)
ForEach (angles.indices, id: \.self) { i in
withAnimation(.easeIn) {
Path { path in
path.move(to: center)
path.addArc(
center: center,
radius: width * 0.4,
startAngle: Angle(degrees: Double(offsets[i])),
endAngle: Angle(degrees: Double(offsets[i] + angles[i])),
clockwise: false)
// print("i = \(angles[i])")
offset += angles[i]
}
}
.fill(slicePressedNo != i ? colors[i] : .yellow)
}
...
_percantages 成员用在 class 但低于 PieChart 构建部分:
ForEach (angles.indices, id: \.self) { i in
if (_percentages[i] >= 2) {
PieChartSliceValueView(label: /*String(format: "%.2f",*/ $_percentages[i], x: center.x, y: center.y, angle: Double(offsets[i] + (angles[i] / 2.0)), radius: width * 0.32)
}
}
一切正常,直到我将 _percentages(或其他成员)从普通成员更改为@State 成员。如果我更改它,ForEach 循环将不起作用 - 没有任何触发来呈现它?或者更改使 angles table 为空?可能我在@State 变量理解中遗漏了一些东西。
提前致谢
茹卡斯
首先不要在变量名中使用_
。您只需要他们访问基础值,例如在 init
.
其次,我对你提到的 class
感到困惑,因为我在你的代码中没有看到任何内容。
我会将 PieView 放在一个额外的视图中,该视图只会执行以下操作:根据移交的数据显示饼图。
此数据和颜色不必在视图中声明。只有可以在视图内更改的内容必须是 @State
。您的 slicePressedNo
可能必须是 @Binding
,因为您会在点击视图中检测到它。所有其他的都可以是简单的 vars 甚至 lets。
因此 PieView 可能如下所示:
struct PieView: View {
var data: [Float]
var colors: [Color]
@Binding var slicePressedNo: Int
private var angles: [Float] = []
private var offsets: [Float] = []
var total: Float = 0
private var sortedData: [Float]
private var percentages: [Float] = []
init (data: [Float], colors: [Color], slicePressedNo: Binding<Int>) {
self.data = data
self.colors = colors
self._slicePressedNo = slicePressedNo // only _ here
self.sortedData = data
// ... your code following
然后 调用 视图可以使用@State 来更改值,它向下传递给 PieView
。一旦这些值发生变化,PieView
将被重新绘制。
这是一个在按下按钮时添加新值的简单示例:
struct ContentView: View {
@State private var pressed = 1
@State private var data: [Float] = [1, 5, 3, 8]
@State private var colors: [Color] = [.blue, .red, .green, .orange, .teal]
var body: some View {
VStack {
PieView(data: data,
colors: colors,
slicePressedNo: $pressed)
Button("Add slice") {
colors.append(colors.randomElement() ?? .red)
data.append(Float.random(in: 0..<15))
}
}
}
}
结果如下:
我正在创建一个应用程序并一起学习 swift/swiftui。我的应用程序使用带有 ForEach 循环的 Path 对象显示饼图。 当我将 _percentages 成员从普通成员更改为 @State 成员时,我基于带有路径的 ForEach 循环的饼图没有出现。
class 成员:
@State var data: [Float]
@State var colors: [Color]
@Binding var slicePressedNo: Int
var angles: [Float] = []
var offsets: [Float] = []
var total: Float = 0
private var _sortedData: [Float]
@State private var _percentages: [Float] = [] // Removing @State fixes the issue and everything works as expected
初始化函数:
init (data: [Float], colors: [Color], slicePressedNo: Binding<Int>) {
self._data = State(initialValue: data)
self._colors = State(initialValue: colors)
self._slicePressedNo = slicePressedNo
self._sortedData = data
var sum: Float = 0.0
for value in self.data {
sum += value
}
self._percentages.removeAll()
for value in self.data {
self._percentages.append((value / sum))
print("sum = \(sum)")
print("value = \(value)")
}
angles.removeAll()
offsets.removeAll()
offsets.append(0)
for value in self._percentages {
let angle = value * 360
angles.append(angle)
offsets.append(angle + offsets.last!)
}
for i in self._percentages.indices {
self._percentages[i] = self._percentages[i] * 100.0
print("% = \(self._percentages[i])")
}
total = sum
}
负责构建饼图切片的代码:
GeometryReader { geometry in
var offset: Float = 0.0
let width: CGFloat = min(geometry.size.width, geometry.size.height)
let height = width
let center = CGPoint(x: width * 0.5, y: height * 0.5)
ForEach (angles.indices, id: \.self) { i in
withAnimation(.easeIn) {
Path { path in
path.move(to: center)
path.addArc(
center: center,
radius: width * 0.4,
startAngle: Angle(degrees: Double(offsets[i])),
endAngle: Angle(degrees: Double(offsets[i] + angles[i])),
clockwise: false)
// print("i = \(angles[i])")
offset += angles[i]
}
}
.fill(slicePressedNo != i ? colors[i] : .yellow)
}
...
_percantages 成员用在 class 但低于 PieChart 构建部分:
ForEach (angles.indices, id: \.self) { i in
if (_percentages[i] >= 2) {
PieChartSliceValueView(label: /*String(format: "%.2f",*/ $_percentages[i], x: center.x, y: center.y, angle: Double(offsets[i] + (angles[i] / 2.0)), radius: width * 0.32)
}
}
一切正常,直到我将 _percentages(或其他成员)从普通成员更改为@State 成员。如果我更改它,ForEach 循环将不起作用 - 没有任何触发来呈现它?或者更改使 angles table 为空?可能我在@State 变量理解中遗漏了一些东西。
提前致谢 茹卡斯
首先不要在变量名中使用_
。您只需要他们访问基础值,例如在 init
.
其次,我对你提到的 class
感到困惑,因为我在你的代码中没有看到任何内容。
我会将 PieView 放在一个额外的视图中,该视图只会执行以下操作:根据移交的数据显示饼图。
此数据和颜色不必在视图中声明。只有可以在视图内更改的内容必须是 @State
。您的 slicePressedNo
可能必须是 @Binding
,因为您会在点击视图中检测到它。所有其他的都可以是简单的 vars 甚至 lets。
因此 PieView 可能如下所示:
struct PieView: View {
var data: [Float]
var colors: [Color]
@Binding var slicePressedNo: Int
private var angles: [Float] = []
private var offsets: [Float] = []
var total: Float = 0
private var sortedData: [Float]
private var percentages: [Float] = []
init (data: [Float], colors: [Color], slicePressedNo: Binding<Int>) {
self.data = data
self.colors = colors
self._slicePressedNo = slicePressedNo // only _ here
self.sortedData = data
// ... your code following
然后 调用 视图可以使用@State 来更改值,它向下传递给 PieView
。一旦这些值发生变化,PieView
将被重新绘制。
这是一个在按下按钮时添加新值的简单示例:
struct ContentView: View {
@State private var pressed = 1
@State private var data: [Float] = [1, 5, 3, 8]
@State private var colors: [Color] = [.blue, .red, .green, .orange, .teal]
var body: some View {
VStack {
PieView(data: data,
colors: colors,
slicePressedNo: $pressed)
Button("Add slice") {
colors.append(colors.randomElement() ?? .red)
data.append(Float.random(in: 0..<15))
}
}
}
}
结果如下: