Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SwiftUI中的条件属性_Swift_Swiftui_Swift5.1 - Fatal编程技术网

SwiftUI中的条件属性

SwiftUI中的条件属性,swift,swiftui,swift5.1,Swift,Swiftui,Swift5.1,如何根据条件添加其他属性 在下面的代码中,我遇到了一个错误无法将类型“some View”(Self.overlay(u:alignment:)的结果)的值分配给类型“some View”(Self.ontapsignature(count:perform:)))。 导入快捷界面 结构条件属性:视图{ @状态变量覆盖:Bool var body:一些观点{ 变量视图=图像(系统名称:“照片”) .可调整大小() .ontapsignature(计数:2,执行:self.tap) 如果自我覆盖{

如何根据条件添加其他属性

在下面的代码中,我遇到了一个错误
无法将类型“some View”(Self.overlay(u:alignment:)的结果)的值分配给类型“some View”(Self.ontapsignature(count:perform:)))。

导入快捷界面
结构条件属性:视图{
@状态变量覆盖:Bool
var body:一些观点{
变量视图=图像(系统名称:“照片”)
.可调整大小()
.ontapsignature(计数:2,执行:self.tap)
如果自我覆盖{
view=view.overlay(圆圈().foregroundColor(颜色.红色))
}
返回视图
}
func tap(){
// ...
}
}

在SwiftUI术语中,您没有添加属性。您正在添加一个修改器

这里的问题是,在SwiftUI中,每个修饰符都返回一个类型,该类型取决于它所修改的内容

var view = Image(systemName: "photo")
    .resizable()
    .onTapGesture(count: 2, perform: self.tap)

// view has some deduced type like GestureModifier<SizeModifier<Image>>

if self.overlay {
    let newView = view.overlay(Circle().foregroundColor(Color.red))
    // newView has a different type than view, something like
    // OverlayModifier<GestureModifier<SizeModifier<Image>>>
}
另一种处理方法是使用类型橡皮擦
AnyView

var body: some View {
    let view = Image(systemName: "photo")
        .resizable()
        .onTapGesture(count: 2, perform: self.tap)
    if overlay {
        return AnyView(view.overlay(Circle().foregroundColor(.red)))
    } else {
        return AnyView(view)
    }
}
我从苹果工程师那里看到的建议是避免使用
AnyView
,因为它比使用全类型视图效率低。例如,和。

已经解释了为什么会出现这种行为,并提出了两种解决方案(透明覆盖或使用
AnyView
)。第三种更优雅的方法是使用

创建
\u conditional content
的一种简单方法是在组或堆栈中编写
if
else
语句。以下是使用组的示例:

import SwiftUI

struct ConditionalProperty: View {
    @State var overlay: Bool
    var body: some View {
        Group {
            if overlay {
                base.overlay(Circle().foregroundColor(Color.red))
            } else {
                base
            }
        }
    }
    
    var base: some View {
        Image("photo")
            .resizable()
            .onTapGesture(count: 2, perform: self.tap)
    }

    func tap() {
        // ...
    }
}

我认为实现
条件属性的首选方法如下。如果应用了动画,效果会很好。
我尝试了其他一些方法,但它会影响我应用的动画

您可以添加您的条件来代替我保留的false。conditionalView(
false

在下面,您可以切换到
true
查看“你好,世界!”将显示为粗体

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
        .conditionalView(false)
        // or use:
        // .modifier(ConditionalModifier(isBold: false))

    }
}

extension View {
    func conditionalView(_ value: Bool) -> some View {
        self.modifier(ConditionalModifier(isBold: value))
  }
}

struct ConditionalModifier: ViewModifier {
    var isBold: Bool
    func body(content: Content) -> some View {
    Group {
        if self.isBold {
            content.font(.custom("HelveticaNeue-Bold", size: 14))
        }else{
            content.font(.custom("HelveticaNeue", size: 14))
        }
    }
  }
}

下面是一个与Kiran Jasvanee发布的答案相似但简化的答案:

struct ContentView: View {

    var body: some View {
        Text("Hello, World!")
            .modifier(ConditionalModifier(isBold: true))
    }
}

struct ConditionalModifier: ViewModifier {

    var isBold: Bool

    func body(content: Content) -> some View {
        Group {
            if self.isBold {
                content.font(.custom("HelveticaNeue-Bold", size: 14))
            }
            else{
                content.font(.custom("HelveticaNeue", size: 14))
            }
        }
    }
}
不同之处在于无需添加此扩展:

extension View {
    func conditionalView(_ value: Bool) -> some View {
        self.modifier(ConditionalModifier(isBold: value))
  }
}
ConditionalModifier
结构中,您还可以取消组视图,而是使用
@ViewBuilder
装饰器,如下所示:

struct ConditionalModifier: ViewModifier {

    var isBold: Bool

    @ViewBuilder
    func body(content: Content) -> some View {
        // Group {
            if self.isBold {
                content.font(.custom("HelveticaNeue-Bold", size: 14))
            }
            else{
                content.font(.custom("HelveticaNeue", size: 14))
            }
        // }
    }
}
如果要有条件地显示视图,必须使用组视图(或其他父视图)或
@ViewBuilder
装饰器

下面是另一个示例,其中按钮的文本可以在粗体和非粗体之间切换:

struct ContentView: View {

    @State private var makeBold = false

    var body: some View {

        Button(action: {
            self.makeBold.toggle()
        }, label: {
            Text("Tap me to Toggle Bold")
                .modifier(ConditionalModifier(isBold: makeBold))
        })

    }
}

struct ConditionalModifier: ViewModifier {

    var isBold: Bool

    func body(content: Content) -> some View {
        Group {
            if self.isBold {
                content.font(.custom("HelveticaNeue-Bold", size: 14))
            }
            else{
                content.font(.custom("HelveticaNeue", size: 14))
            }
        }
    }
}
多亏了,我找到了一个界面非常简单的选项:

Text(“你好”)
.if(shouldBeRed){$0.foregroundColor(.red)}
通过此扩展启用:

extension View {
    func conditionalView(_ value: Bool) -> some View {
        self.modifier(ConditionalModifier(isBold: value))
  }
}
扩展视图{
@视图生成器
func`if`(条件:Bool,transform:(Self)->transform)->一些视图{
如果条件{transform(self)}
else{self}
}
}
下面是一篇很好的博客文章,附带了条件修饰符的附加提示:

就这么简单

import SwiftUI

struct SomeView: View {
  let value: Double
  let maxValue: Double
  
  private let lineWidth: CGFloat = 1
  
  var body: some View {
    Circle()
      .strokeBorder(Color.yellow, lineWidth: lineWidth)
      .overlay(optionalOverlay)
  }
  
  private var progressEnd: CGFloat {
    CGFloat(value) / CGFloat(maxValue)
  }
  
  private var showProgress: Bool {
    value != maxValue
  }
  
  @ViewBuilder private var optionalOverlay: some View {
    if showProgress {
      Circle()
        .inset(by: lineWidth / 2)
        .trim(from: 0, to: progressEnd)
        .stroke(Color.blue, lineWidth: lineWidth)
        .rotationEffect(.init(degrees: 90))
    }
  }
}

struct SomeView_Previews: PreviewProvider {
  static var previews: some View {
    Group {
      SomeView(value: 40, maxValue: 100)
      
      SomeView(value: 100, maxValue: 100)
    }
      .previewLayout(.fixed(width: 100, height: 100))
  }
}

请注意,默认情况下,SwiftUI将视图的静态类型视为动画的标识符()。在您的解决方案中,这两个子视图(带/不带覆盖)因此被视为不相关的视图。如果应用一个动画,它在您的解决方案中的应用可能与在我的解决方案中的应用不同。这不一定是错的,只是需要注意的事情。可以使用
.id
修饰符解决此问题。对于
视图
,不需要使用
条件视图
扩展。直接使用
.modifier(ConditionalModifier(isBold:viewIsBold))初始化
ConditionalModifier
结构体
@PeterSchorn我想我明白你的意思了,建议你也添加答案。
AnyView
的实际性能测试在使用它时没有揭示任何负面影响:这是最好的解决方案。