SwiftUI中的条件属性

时间:2019-08-12 19:43:09

标签: swift swiftui swift5.1

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

在下面的代码中,我收到错误Cannot assign value of type 'some View' (result of 'Self.overlay(_:alignment:)') to type 'some View' (result of 'Self.onTapGesture(count:perform:)')

import SwiftUI

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

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

6 个答案:

答案 0 :(得分:6)

感谢this post,我发现了一个界面非常简单的选项:

Text("Hello")
    .if(shouldBeRed) { $0.foregroundColor(.red) }

通过此扩展程序启用:

extension View {
    @ViewBuilder
    func `if`<Transform: View>(_ condition: Bool, transform: (Self) -> Transform) -> some View {
        if condition { transform(self) }
        else { self }
    }
}

这是一篇很棒的博客文章,其中包含有关条件修饰符的其他提示:https://fivestars.blog/swiftui/conditional-modifiers.html

答案 1 :(得分:4)

Rob Mayoff已经很好地解释了为什么出现此行为,并提出了两种解决方案(透明叠加层或使用AnyView)。第三种更优雅的方法是使用ConditionalContent

创建ConditionalContent的一种简单方法是在组或堆栈中编写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() {
        // ...
    }
}

答案 2 :(得分:3)

在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>>>
}

由于newViewview的类型不同,因此您不能仅分配view = newView

解决此问题的一种方法是始终使用overlay修饰符,但在不希望覆盖层可见时使其透明:

var body: some View {
    return Image(systemName: "photo")
        .resizable()
        .onTapGesture(count: 2, perform: self.tap)
        .overlay(Circle().foregroundColor(overlay ? .red : .clear))
}

另一种处理方法是使用类型橡皮擦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)
    }
}

我从Apple工程师那里看到的建议是避免使用AnyView,因为它比使用完全类型的视图效率低。例如this tweetthis tweet

答案 3 :(得分:2)

这是与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))
            }
        }
    }
}

答案 4 :(得分:0)

我认为实现#include "stdio.h" #include "stdlib.h" #include "string.h" typedef struct { int size; int id; int tip; float x1; float x2; float y1; float y2; }blocks; int main() { blocks *block1 , *block2 , *block3; char line[60]; int blcNum=1; int sizer=0; int temp; block1 = malloc( sizeof(blocks) ); block2 = malloc( sizeof(blocks) ); block3 = malloc( sizeof(blocks) ); FILE *fp; fp = fopen("test_system.txt","r"); // block's size calculator and memory allocater ; while(fgets(line,60,fp)) { if ( strstr(line,"\0") != NULL && strstr(line,"ID") == NULL && strstr(line,"END") == NULL ) { sizer++; } else if ( strstr(line,"END") != NULL ){ if ( blcNum == 1){ block1->size = sizer; blcNum++; sizer = 0; } else if ( blcNum == 2){ block2->size = sizer; blcNum++; sizer = 0; } else if ( blcNum == 3){ block3->size = sizer; blcNum++; sizer = 0; } } }; block1 = realloc(block1 , block1->size * sizeof(blocks)); block2 = realloc(block2 , block2->size * sizeof(blocks)); block3 = realloc(block3 , block3->size * sizeof(blocks)); fclose(fp); line == NULL; blcNum=1; puts("\n\n"); fp = fopen("test_system.txt","r"); char *szTempString; int index=1; while(fgets(line,60,fp)) { szTempString = line; if( strstr(line,"ID") == NULL && strstr(line,"END") == NULL ) { printf("%s",line); if(index <= block1->size) { printf("%s",line); sscanf(szTempString,"%d %f %f",&(block1 + (index*sizeof(blocks)))->id, &(block1 + (index*sizeof(blocks)))->x1, &(block1 + (index*sizeof(blocks)))->y1); index++; } } } fclose(fp); printf("\nUploader's information : \n"); for (temp =1; temp <= block1->size ; ++temp) { printf(" id : %d , X1 : %f , Y1 : %f \n",(block1+(temp*sizeof(block1)))->id,(block1+(temp*sizeof(block1)))->x1,(block1+(temp*sizeof(block1)))->y1); puts("\nIt must be \nid : 1 , X1 : 1.00 , Y1 : 1.00"); } printf("\n1 . block's size : %d ",block1->size); printf("\n2 . block's size : %d ",block2->size); printf("\n3 . block's size : %d ",block3->size); free(block1); free(block2); free(block3); return 0; } 的首选方法如下。如果应用了动画,效果会很好。
我尝试了其他几种方法,但这会影响我应用的动画。

您可以添加条件以代替我保留 .conditionalView(final InputStream file = new FileInputStream("file path");
 EnvironmentHelper environmentHelper = mock(EnvironmentHelper.class);
 Properties properties = new Properties();
 System system = mock(System.class);
 when(system.getProperties()).thenReturn(properties);
 when(environmentHelper.isRunningInProductionMode(properties)).thenReturn(true);
 when(featureDAO.findActiveEnabledFeatures(anyList())).thenReturn(new ArrayList<>());
 的错误。

下面,您可以切换到Conditional Properties来检查“世界,您好!” 会显示为 BOLD

false

答案 5 :(得分:0)

就这么简单

            float watermarkTrimmingRectangleWidth = 500;
            float watermarkTrimmingRectangleHeight = 500;
            float formWidth = 500;
            float formHeight = 500;
            float formXOffset = -40;
            float formYOffset = 0;
            float xTranslation = 50;
            float yTranslation = 25;
            double rotationInRads = Math.PI / 4.2;

 PdfDocument pdfDoc = new PdfDocument(new PdfReader(filePath), new PdfWriter(destinationfile));
 var numberOfPages = pdfDoc.GetNumberOfPages();
 PdfPage page = null;

            for (var i = 1; i <= numberOfPages; i++)
            {
                
                page = pdfDoc.GetPage(i);
                Rectangle ps = page.GetPageSize();              

                float bottomLeftX = ps.GetWidth() / 2 - watermarkTrimmingRectangleWidth / 2;                    
                float bottomLeftY = ps.GetHeight() / 2 - watermarkTrimmingRectangleHeight / 2;                  

                Rectangle watermarkTrimmingRectangle = new Rectangle(bottomLeftX, bottomLeftY, ps.GetWidth(), watermarkTrimmingRectangleHeight);
               
                PdfWatermarkAnnotation watermark = new PdfWatermarkAnnotation(watermarkTrimmingRectangle);
              
                AffineTransform transform = new AffineTransform();
                transform.Translate(xTranslation, yTranslation);
                
                transform.Rotate(rotationInRads);
                PdfFixedPrint fixedPrint = new PdfFixedPrint();
                watermark.SetFixedPrint(fixedPrint);                  
               
                Rectangle formRectangle = new Rectangle(formXOffset, formYOffset, formWidth, formHeight);

                //Observation: font XObject will be resized to fit inside the watermark rectangle
                PdfFormXObject form = new PdfFormXObject(formRectangle);
                PdfExtGState gs1 = new PdfExtGState().SetFillOpacity(0.8f).SetStrokeOpacity(1.5f);
                PdfCanvas canvas = new PdfCanvas(form, pdfDoc);
                float[] transformValues = new float[6];
                transform.GetMatrix(transformValues);

                canvas.SaveState()
                    .BeginText().SetExtGState(gs1)
                    .SetTextMatrix(transformValues[0], transformValues[1], transformValues[2], transformValues[3], transformValues[4], transformValues[5])
                    .SetFontAndSize(font, fontSize)
                    .ShowText("Restricted Internal")
                    .EndText()
                    .RestoreState();

                canvas.Release();
                watermark.SetAppearance(PdfName.N, new PdfAnnotationAppearance(form.GetPdfObject()));
                watermark.SetFlags(PdfAnnotation.READ_ONLY);
                page.AddAnnotation(watermark);
                
            }
            page?.Flush();
            pdfDoc.Close();