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
的实际性能测试在使用它时没有揭示任何负面影响:这是最好的解决方案。