我有一个SwiftUI屏幕,它以网格格式显示数据,动态地调整单元格的大小,以便它们总是填充可用的宽度,并确保它们始终是正方形。
我把布局做得很好,但是渐变有点令人沮丧。创建RadialGradient,时,需要在实际屏幕点中指定beginRadius和endRadius,而不是单元点(从0.0到1.0)。
如下所示:
RadialGradient(gradient: item.isBlue ? self.blue : self.red,
center: .center,
startRadius: 0.0,
endRadius: 100.0)在上面的例子中,我选择了一个任意大小的100分作为endRadius。这是很好的工作,但真正给广场一个不同的外观,当他们是不同的大小。请参阅下面的两个示例。
示例1 -- 3x2网格

示例2 -- 2x3网格:

下面是一个示例项目ContentView.swift中的所有代码,它清楚地说明了我的意思:
import SwiftUI
struct MyDataItem: Identifiable {
let id: UUID = UUID()
let text: String
let isBlue: Bool
}
struct MyDataRow: Identifiable {
let id: UUID = UUID()
let items: [MyDataItem]
}
struct ContentView: View {
@State private var datasetIndex: Int = 0
@State private var sets = [
// First data set
[
MyDataRow(items: [
MyDataItem(text: "A", isBlue: false),
MyDataItem(text: "B", isBlue: true),
MyDataItem(text: "C", isBlue: true),
]),
MyDataRow(items: [
MyDataItem(text: "D", isBlue: false),
MyDataItem(text: "E", isBlue: false),
MyDataItem(text: "F", isBlue: false),
]),
],
// Second data set
[
MyDataRow(items: [
MyDataItem(text: "A", isBlue: false),
MyDataItem(text: "B", isBlue: true),
]),
MyDataRow(items: [
MyDataItem(text: "C", isBlue: true),
MyDataItem(text: "D", isBlue: false),
]),
MyDataRow(items: [
MyDataItem(text: "E", isBlue: false),
MyDataItem(text: "F", isBlue: false),
]),
]
]
var body: some View {
VStack {
Picker(selection: $datasetIndex, label: Text("Pick a data set")) {
Text("Set 1").tag(0)
Text("Set 2").tag(1)
}.pickerStyle(SegmentedPickerStyle())
GridThing(rows: self.$sets[self.datasetIndex])
Spacer()
}
}
}
struct GridThing: View {
@Binding var rows: [MyDataRow]
private let spacing: CGFloat = 20.0
let blue = Gradient(colors: [Color.blue, Color(red: 0.85, green: 0.85, blue: 1.0)])
let red = Gradient(colors: [Color.red, Color(red: 1.0, green: 0.85, blue: 0.85)])
var body: some View {
VStack(alignment: .center, spacing: spacing) {
ForEach(self.rows) { row in
HStack(alignment: .top, spacing: self.spacing) {
ForEach(row.items) { item in
ZStack {
Rectangle()
.fill(RadialGradient(gradient: item.isBlue ? self.blue : self.red,
center: .center,
startRadius: 0.0,
endRadius: 100.0))
.aspectRatio(1.0, contentMode: .fit)
Text(item.text)
.foregroundColor(.black)
}
}
}
}
}
}
}我想让RadialGradient使用与正方形的高度和宽度相匹配的endRadius。
我希望它能自动做到这一点。例如,LinearGradient,以UnitPoint for startPoint和endPoint为例,这将是完美的,但对于RadialGradient,我们需要做所有的工作。
我对此的主要想法是在某种程度上合并一个GeometryReader.
我尝试过这样包装,用GeometryReader.计算endRadius这一次失败是因为“编译器无法在合理的时间内键入-检查该表达式;尝试将表达式拆分为不同的子表达式”。
var body: some View {
VStack(alignment: .center, spacing: spacing) {
GeometryReader { geom in
ForEach(self.rows) { row in
HStack(alignment: .top, spacing: self.spacing) {
ForEach(row.items) { item in
ZStack {
Rectangle()
.fill(RadialGradient(gradient: item.isBlue ? self.blue : self.red,
center: .center,
startRadius: 0.0,
endRadius: (geom.size.width - (self.spacing * (row.items.count + 1))) / row.items.count))
.aspectRatio(1.0, contentMode: .fit)
Text(item.text)
.foregroundColor(.black)
}
}
}
}
}
}
}谢谢!
发布于 2019-12-14 06:32:22
几何读取器是正确的,但不是包装整个网格,只是包装正方形,然后你不需要做任何额外的计算:几何宽度是正方形的宽度,这是你的梯度半径的两倍。这里有个游乐场:
import SwiftUI
import PlaygroundSupport
struct V: View {
var body: some View {
VStack(alignment: .center, spacing: 10) {
ForEach(0..<4) { row in
HStack(alignment: .top, spacing: 10) {
ForEach(0..<4) { item in
ZStack {
GeometryReader { geometry in
Rectangle()
.fill(
RadialGradient(
gradient: Gradient(colors: [Color.white, Color.red, Color.green]),
center: .center,
startRadius: 0.0,
endRadius: geometry.size.width / 2 )
)
.aspectRatio(1.0, contentMode: .fit)
}
Text("text")
.foregroundColor(.black)
}
}
}
}
}
}
}
PlaygroundPage.current.setLiveView(V())https://stackoverflow.com/questions/59332412
复制相似问题