SwiftUI基础篇Transforming(下)

1,833 阅读3分钟

Transforming View

概述

文章主要分享SwiftUI Modifier的学习过程,将使用案例的方式进行说明。内容浅显易懂,Transforming View展示部分调试结果,不过测试代码是齐全的。如果想要运行结果,可以移步Github下载code -> github案例链接

1、用精确的数值设置圆角

SwiftUI视图都可以使用cornerRadius()修饰符来设置圆角。它采用一个简单的、以点数为单位的值来控制圆角。 目前在iOS17上已不推荐使用,这个方法更像UIKit的设置圆角的方式。

struct FFViewRound: View {
    var body: some View {
        //创建一个15点圆角的文本视图。
        Text("Hello, World!")
            .padding()
            .background(.green)
            .cornerRadius(15)
        //此函数在iOS17上建议使用“Use `clipShape` or `fill` instead”
        //可以使用带Capsule的ClipShape()修饰符自动将最短的边缘更加的圆润。
        Text("Hello, world!")
            .padding()
            .background(.green)
            .clipShape(Capsule())
    }
}

调试结果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 09.27.27.png

2、设置视图的opacity

使用opacity()修饰符,任何SwiftUI视图都可以时部分透明或者全透明的,它接受一个介于0(完全不可见)-1(完全不透明)之间的值,与UIKit的alpha属性一致。

struct FFViewOpacity: View {
    @State private var opacity = 0.5
    
    var body: some View {
        //创建一个红色文本视图,附加30%透明度
        Text("Hello, World!")
            .padding()
            .background(.red)
            .opacity(0.3)
        //修改不透明度是非常快速的,基本不可见,视图出现即看见结果,通过Slider查看动态效果
        VStack {
            Text("Hello, World!")
                .padding()
                .background(.red)
                .opacity(opacity)
            Slider(value: $opacity, in: 0...1)
        }
        .padding()
    }
}

调试结果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 09.36.08.png Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 09.36.12.png

3、为一组视图设置accent

iOS使用淡色调给应用程序一个协调的主题,在SwiftUI中也有相同的功能,名为accent。就像在UIkit中,当你设置一个视图的accent会影响它里面的所有视图,如果你设置顶层空间的访问色,那么所有的东西都有颜色。

struct FFViewAccent: View {
    var body: some View {
        VStack {
            Button("Press Here") {
                print("Button pressed!")
            }
        }
        .accentColor(.orange)
    }
}

调试结果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 09.45.51.png

4、通过mask设置视图间的遮罩

SwiftUI提供了mask()修饰符,用于用一个遮罩另外一个,这意味着可以用文本遮罩一个图像,或者发挥你聪明的小脑袋瓜。

struct FFViewMask: View {
    var body: some View {
        //创建一个300*300的条纹图像,然后使用文本“SWIFT!”遮罩,这样这些字母就可以和图像合并。
        Image(.fullEnglish)
            .frame(width: 300, height: 300)
            .mask {
                Text("SWIFT!")
                    .font(.system(size: 72))
            }
    }
}

mask()修饰符与clipShape()不同,因为它也应用遮罩视图中的任何透明度。你可以根据遮罩的透明度在底层视图中设置空洞。另一方面,clipShape()值调整应用他的视图的外部形状。

调试结果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 09.50.30.png

5、设置视图的高斯模糊

blur()修饰符可以根据自己的选择对视图附加实时的高斯模糊。

struct FFViewBlur: View {
    @State private var blurAmount = 0.0
    var body: some View {
        //对图像使用模糊
        Image(.freshBakedCroissantThumb)
            .resizable()
            .frame(width: 300, height: 300)
            .blur(radius: 20)
        Divider()
        //对文本使用模糊
        Text("Meta BBlv in Swift")
            .blur(radius: 2)
        Divider()
        //通过Slider动态调整模糊效果
        VStack {
            Image(.macaronsGaloreThumb)
                .resizable()
                .frame(width: 300, height: 300)
                .blur(radius: blurAmount)
            Slider(value: $blurAmount, in:  0...20)
        }
        .padding()
    }
}

调试结果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 10.06.14.png Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 10.06.19.png

6、将视图混合在一起

当将一个视图放置在另一个视图上时,你可以使用blendMode()修饰符来控制重叠的方式。这包含了多种混合颜色的方法。

struct FFViewBlend: View {
    var body: some View {
        //创建一个ZStack,里面有两个重叠的圆,将混合模式设定为.multiply,颜色会变暗
        ZStack {
            Circle()
                .fill(.red)
                .frame(width: 200, height: 200)
                .offset(x: -50)
                .blendMode(.multiply)
            Circle()
                .fill(.blue)
                .frame(width: 200, height: 200)
                .offset(x: 50)
                .blendMode(.multiply)
        }
        .frame(width: 400)
    }
}

调试结果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 10.11.05.png

7、如何通过着色、去饱和度来调整视图

SwiftUI可以通过colorMultiplysaturationcontrast调整他们的亮度、色调、色温、饱和度来精确的调整视图。

struct FFViewTintingAndDesaturating: View {
    @State private var contrastAmount = 0.5
    var body: some View {
        //将Image调成红色
        Image(.mexicanMocha)
            .colorMultiply(.red)
        //饱和度调整,0.0时全灰色-1.0为原始颜色
        Image(.mushroomTagliatelle)
            .saturation(0.3)
        //甚至可以通过使用contrast()修饰符动态调整视图的对比度,0.0不会产生对比度,为灰色图像,
        //1.0为原始图像,高于1.0会增加对比度
        VStack {
            Image(.paellaAlicante)
                .contrast(contrastAmount)
            
            Slider(value: $contrastAmount , in: 0...3)
        }
    }
}

调试结果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 11.22.10.png Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 11.22.15.png

8、使用ButtonStyle自定义按钮

SwiftUI有很多样式协议,可以为视图定义通用的样式,比如Button、ProgressView、Toggle等。他们的工作原理都是可以集中的使用任意数量的修饰符,使视图看起来像我们想要的那样。创建一个控件其实就是一套完整的自定义修饰符的集合。

8.1、ButtonStyle效果一

//可以将常规的三个修饰符集中到一个单一的BlueButton样式中
struct BlueButton: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding()
            .background(Color(red: 0, green: 0, blue: 0.5))
            .foregroundStyle(.white)
            .clipShape(Capsule())
        
    }
}
struct FFButtonStyle: View {
    var body: some View {
        Button("Press Me") {
            print("Button pressed!")
        }
        .padding()
        .background(Color(red: 0, green: 0, blue: 0.5))
        .clipShape(Capsule())
        
        //将修饰符包装在BlueButton中了。
        Button("Press Me") {
            print("Button pressed!")
        }
        .buttonStyle(BlueButton())
    }
}

8.2、ButtonStyle效果二

//创建按钮点击时放大效果
struct GrowingButton: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding()
            .background(.green)
            .foregroundStyle(.white)
            .clipShape(Capsule())
            .scaleEffect(configuration.isPressed ? 1.2 : 1.0)
            .animation(.easeOut(duration: 0.2), value: configuration.isPressed)
    }
}

struct FFButtonStyle: View {
    var body: some View {
        Button("Press Me") {
            print("Button pressed!")
        }
        .padding()
        .background(Color(red: 0, green: 0, blue: 0.5))
        .clipShape(Capsule())
       
        Button("Press Me") {
            print("Button pressed!")
        }
        .buttonStyle(GrowingButton())
    }
}

调试结果

绿色Button点击放大效果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 11.30.04.png

9、使用ProgressViewStyle自定义ProgressView

SwiftUI提供了ProgressViewStyle协议来为ProgressView创建自定义设计,可以读取进度视图的完成情况。要创建自定义ProgressView样式,需要创建一个结构体,该结构体具有接受视图当前配置的makeBody()方法,然后,可以继续渲染想要的进度,可以时一个百分比文本,可以是一个进度圆。

//创建一个进度圆圈
struct GaugeProgressStyle: ProgressViewStyle {
    var strokeColor = Color.blue
    var strokeWidth = 25.0
    
    func makeBody(configuration: Configuration) -> some View {
        //fractionCompleted:进度视图表示的任务的完成部分,从0.0(尚未开始)到1.0(完全完成)
        let fractionCompleted = configuration.fractionCompleted ?? 0
        
        return ZStack {
            Circle()
                .trim(from: 0, to: fractionCompleted)
                .stroke(strokeColor, style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round))
                .rotationEffect(.degrees(-90))
        }
    }
}

struct FFProgressViewCustomizing: View {
    @State private var progress = 0.2
    
    var body: some View {
        ProgressView(value: progress, total: 1.0)
            .progressViewStyle(GaugeProgressStyle())
            .frame(width: 200, height: 200)
            .contentShape(Rectangle())
            .onTapGesture {
                if progress < 1.0 {
                    withAnimation {
                        progress += 0.2
                    }
                }
            }
    }
}

-90度开始绘制,圆圈会在顶部开始绘制。

调试结果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 14.32.52.png Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 14.32.56.png

10、通过ToggleStyle自定义Toggle

SwiftUI提供了ToggleStyle协议来定制开关,任何符合此协议的结构体都必须实现一个makeBody的方法。该方法可以自定义想要的方式实现Toggle。当自定义Toggle切换时,取决自己自定义开启和关闭,SwiftUI不会自动完成了。

struct CheckToggleStyle: ToggleStyle {
    func makeBody(configuration: Configuration) -> some View {
        Button {
            configuration.isOn.toggle()
        } label: {
            Label {
                configuration.label
            } icon: {
                Image(systemName: configuration.isOn ? "checkmark.circle.fill" : "circle")
                    .foregroundStyle(configuration.isOn ? Color.accentColor : .secondary)
                    .accessibilityLabel(Text(configuration.isOn ? "Checked" : "Unchecked"))
                    .imageScale(.large)
            }
        }
        .buttonStyle(.plain)
    }
}

struct FFToggleStyle: View {
    @State private var isOn = false
    var body: some View {
        Toggle("Switch Me", isOn: $isOn)
            .toggleStyle(CheckToggleStyle())
    }
}

调试结果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 14.36.28.png Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 14.36.32.png

11、隐藏默认背景色用其他替代

一些SwiftUI是有有一个默认的背景颜色,它会覆盖你自己想要的任何颜色,但是如果你使用scrollCOntentBackground()修饰符,可以隐藏默认背景并用其他颜色替代。

11.1、scrollContentBackground样式一

删除List的默认颜色,替换为.indigo

struct FFViewChangeBackground: View {
    var body: some View {
        
        List(0..<100) { i in
            Text("Exampl \(i)")
        }
        .scrollContentBackground(.hidden)
        .background(.indigo)
    }
}

11.2、scrollContentBackground样式二

隐藏TextEditor的默认背景,用渐变替代

struct FFTextEditorBackground: View {
    @State private var bio = "Describe yourself"
    var body: some View {
        
        TextEditor(text: $bio)
            .scrollContentBackground(.hidden)
            .background(LinearGradient(colors: [.white, .gray], startPoint: .top, endPoint: .bottom))
    }
}

调试结果

Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 14.42.11.png Simulator Screenshot - iPhone 14 Pro - 2023-08-22 at 14.42.38.png