2

我想创建一个具有矩形等形状的视图,该视图基于变量填充线性或角度渐变。

我的尝试如下所示:

struct TempTestView: View {
    @State var circleMode: Bool = true
    let gradient: Gradient = Gradient(colors: [.red, .green])
    var body: some View {
        Rectangle()
            .fill(circleMode ? AngularGradient(gradient: gradient, center: .center) : LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing))
            .opacity(0.5)
            .frame(width: 200, height: 200)


    }
}

struct TempTestView_Previews: PreviewProvider {
    static var previews: some View {
        TempTestView()
    }
}

斯威夫特给我一个错误: Cannot convert value of type 'AngularGradient' to expected argument type 'FillStyle'

如果我更改代码以删除内联 if 并将其替换为AngularGradient(gradient: gradient, center: .center)or LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing),则 swift 编译成功。

如果我尝试将所有内容包装在返回的函数中some ShapeStyle,swift 会抱怨 AngularGradient 和 LinearGradient 不是同一类型。使用 View 我会将两者都包裹起来AnyView,但我看不到AnyStyle要包裹的东西。

我的例子被简化了。出于动画/过渡的原因,不能有两个单独的矩形,这就是为什么我要寻找像我的示例中那样的内联解决方案。

任何帮助,将不胜感激。

4

5 回答 5

1

我有完全相同的问题。我通过创建一个计算属性来解决它,该属性返回预先格式化的矩形并将其用作正文中的视图。虽然这个解决方案并不理想,但至少它允许您将视图添加到 body 并指定一次过渡和动画:

private var Bkgr:  AnyView {
  if circleMode {
    return AnyView(Rectangle().fill(AngularGradient(gradient: gradient, center: .center)))
  }
  return AnyView(Rectangle().fill(LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing)))
}

然后你可以简单地将它作为一个单一的视图添加到你的身体中:

var body: some View {
  self.Bkgr
    .opacity(/*..*/)
    .transition(/*...*/)
    .animation(/**/)
    // go crazy just once
}
于 2020-09-27T13:56:31.227 回答
0

不透明的返回类型some view要求您提供确定的代码。结果类型必须是确定的,不依赖于任何变量或条件。这就是为什么condition ? Result1 : Result2只有当 Result1 和 Result2 是相同类型时才可以使用运算符的原因。LinearGradientAngularGradient不是。

因此,您可以将整个 Rectangle 放在 If-else 块中。它不是运行时中的流指令,而是替代视图容器,例如VStack. 它将由两个可以具有不同类型的视图组成。它就像 Schroedinger View :) 实际上它同时是两个 Views 类型,所以 swift 只需根据条件隐藏其中一个。

尝试这样的事情:

struct TempTestView: View {
    @State var circleMode: Bool = true
    let gradient: Gradient = Gradient(colors: [.red, .green])
    var body: some View 
        Group{
            if circleMode{
                Rectangle()
                    .fill(AngularGradient(gradient: gradient, center: .center))
            }else{
                Rectangle()
                    .fill(LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing))
            }
        }
            .opacity(0.5)
            .frame(width: 200, height: 200)
    }           
}
于 2020-05-24T12:46:13.233 回答
0

另一种选择是使用函数返回 AnyView。

struct TempTestView: View {
    @State var circleMode: Bool = true
    let gradient: Gradient = Gradient(colors: [.red, .green])
    var body: some View {
        VStack{
            myGradient()
                .opacity(0.5)
                .frame(width: 200, height: 200)
            Button(action: {self.circleMode.toggle()}){
                Text("toggle")
            }
        }
    }
    func myGradient() -> AnyView{
        if circleMode {
            return AnyView(Rectangle().fill(AngularGradient(gradient: gradient, center: .center)))
        } else {
            return AnyView(Rectangle().fill(LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing)))
        }
    }
}

它的一些作弊方式。您使用 AnyView 容器从 SwiftUI 中隐藏您的视图的真实签名。但如果有效。它只是一个函数中的代码。您可以使用流控制(运行时中的循环和 if-else)来创建 AnyView。

于 2020-05-25T14:07:39.313 回答
0

主体必须始终返回相同的视图:

struct TempTestView: View {

    @State var circleMode: Bool = true
    let gradient: Gradient = Gradient(colors: [.red, .green])

    var body: some View {
        Group {
            Button(action: {
                self.circleMode.toggle()
            }) {
                Text("Toggle Circle Model!")
            }
            if circleMode {
                Rectangle()
                    .fill(AngularGradient(gradient: gradient, center: .center))
            } else {
                Rectangle()
                    .fill(LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing))
            }
        }
        .opacity(0.5)
        .frame(width: 200, height: 200)
    }
}

尝试此代码以获得所需的结果。

于 2020-05-24T14:14:15.793 回答
0

您可以尝试以不同的角度来处理这种情况。尝试将 Angular 和 Linear 渐变关联为视图。并将它们放置在 VStack 中,如下所示:

struct TempTestView: View {
    @State var circleMode: Bool = true
    let gradient: Gradient = Gradient(colors: [.red, .green])
    var body: some View {
        VStack {
            if circleMode {
                AngularGradient(gradient: gradient, center: .center)
            } else {
                LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing)
            }
        }
        .opacity(0.5)
        .frame(width: 200, height: 200)
    }
}

我试过了,它符合要求。

于 2020-05-24T12:51:52.320 回答