图像,形状和媒体

174 阅读9分钟

绘制图标,圆形,渐变等

如何使用图像视图绘制图像?

使用图像视图在 SwiftUI 布局中呈现图像。 这些可以从您的包(bundle),系统图标,UIImage 等加载图像,但是这三个是最常见的。

要从 bundle 中加载图片并将其显示在图片视图中,只需使用以下方法:

Image("dog")

需要在 Assets.xcassets 里面添加 dog 的图片。

如果要使用 Apple 的 SF Symbols 图标集,则应使用 Image(systemName:) 初始化程序,如下所示

Image(systemName: "cloud.heavyrain.fill")
    .font(.largeTitle)

请注意,如何使用 font() 修饰符来调整 SF Symbols,就好像它们是文本一样。

如何调整图像适合其空间的展示方式?

SwiftUI 的图片视图可以以不同的方式缩放,就像 UIImageView 的内容模式一样。

默认情况下,图像视图会自动调整其大小以适应其内容,这可能会使它们超出屏幕范围。 如果添加 resizable() 修饰符,则图像将自动调整大小,以使其填满所有可用空间,无论是在您指定的帧内还是在屏幕上可用的任何空间:

Image("rome")
    .resizable()
    .frame(height: 200)

但是,这也可能导致图像的原始长宽比失真,因为它将在所有尺寸上拉伸所需的任何量以使其填充空间。

如果要保持其宽高比,则应使用 .fill 或 .fit 添加一个 AspectRatio 修饰符,如下所示:

Image("rome")
    .resizable()
    .aspectRatio(contentMode: .fit)
    .frame(width: 250)

如何平铺图像?

如果要求 SwiftUI 使图片视图占用比图片设计的空间更多的空间,则默认行为是拉伸图片以使其适合您所需的空间。 但是,并不需要那样做:它还可以平铺图像,即水平和垂直重复图像,从而完全填充空间。

关键是将 resizable() 修饰符与其 resizingMode 参数一起使用。 该名称可以是 .stretch(默认设置)或 .tile,其中 .tile 是您要查找的内容。

Image("logo")
    .resizable(resizingMode: .tile)

如果您只希望平铺图像的一部分(将一个或多个边缘固定在图像视图的边缘),则可以为第一个参数提供边缘插图,如下所示:

Image("logo")
    .resizable(capInsets: EdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20), resizingMode: .tile)

如何使用SF符号渲染图像?

SwiftUI 的 Image 视图使我们可以从 SF Symbols 中加载任何 2400+ 图标,其中许多图标也可以使用多色。

要从 Apple 的 SF Symbols 集中加载图标,请使用 Image(systemName:)初始化程序,并传入要加载的图标字符串,如下所示:

Image(systemName: "cloud.heavyrain.fill")

您获得的图像是可缩放的且可着色的,这意味着您可以要求 SwiftUI 放大图像以匹配其随附的任何“动态类型”文本样式(如果有):

Image(systemName: "cloud.heavyrain.fill")
    .font(.largeTitle)

而且这还意味着您可以使用与您已经看到的相同的 frontantColor() 修饰符为图像着色:

Image(systemName: "cloud.heavyrain.fill")
    .font(.largeTitle)
    .foregroundColor(.red)

如果您使用的图像包含色彩元素,则可以使用 .renderingMode().original) 激活多色模式,如下所示:

Image(systemName: "cloud.sun.rain.fill")
    .renderingMode(.original)
    .font(.largeTitle)
    .padding()
    .background(Color.black)
    .clipShape(Circle())

image.png

您可以选择将 foregroundColor() 修改器应用于多色 SF符号,这将使部分符号重新着色。 例如,这将使图标的一部分变为蓝色,而部分变为绿色:

image.png

Image(systemName: "person.crop.circle.fill.badge.plus")
    .renderingMode(.original)
    .foregroundColor(.blue)
    .font(.largeTitle)

通过 Apple 提供的应用 SF Symbols 2 查看 SF Symbols 所有的图标名称。

如何渲染渐变?

SwiftUI 为我们提供了各种渐变选项,所有这些选项都可以以多种方式使用。 例如,您可以使用白色到黑色的线性渐变来渲染文本视图,如下所示:

Text("Hello World")
    .padding()
    .foregroundColor(.white)
    .font(.largeTitle)
    .background(
        LinearGradient(gradient: Gradient(colors: [.white, .black]), startPoint: .top, endPoint: .bottom)
    )

image.png

颜色被指定为一个数组,您可以根据需要设置任意多个颜色–默认情况下,SwiftUI 会将它们均匀地隔开。 因此,我们可以像这样从白色变成红色再变成黑色:

Text("Hello World")
    .padding()
    .foregroundColor(.white)
    .font(.largeTitle)
    .background(
        LinearGradient(gradient: Gradient(colors: [.white, .red, .black]), startPoint: .top, endPoint: .bottom)
    )

要制作水平渐变而不是垂直渐变,请使用 .lead 和 .trailing 作为起点和终点:

Text("Hello World")
    .padding()
    .foregroundColor(.white)
    .font(.largeTitle)
    .background(
        LinearGradient(gradient: Gradient(colors: [.white, .red, .black]), startPoint: .leading, endPoint: .trailing)
    )

对于其他渐变样式,请尝试 RadialGradient 或 AngularGradient。 例如,这将创建一个从圆心开始到边缘的各种颜色的径向渐变:

Circle()
    .fill(
        RadialGradient(gradient: Gradient(colors: [.red, .yellow, .green, .blue, .purple]), center: .center, startRadius: 50, endRadius: 200)        
    )
    .frame(width: 200, height: 200)

这将创建一个角度渐变(通常称为圆锥渐变),循环显示各种颜色,然后返回到起点:

Circle()
    .fill(
        AngularGradient(gradient: Gradient(colors: [.red, .yellow, .green, .blue, .purple, .red]), center: .center)
    )
    .frame(width: 200, height: 200)

由于所有三种渐变类型均符合 ShapeStyle 协议,因此可以将它们用于背景,填充和笔触。 例如,这使用我们的彩虹圆锥形渐变作为圆的粗内部笔画:

Circle()
    .strokeBorder(
        AngularGradient(gradient: Gradient(colors: [.red, .yellow, .green, .blue, .purple, .red]), center: .center, startAngle: .zero, endAngle: .degrees(360)),
        lineWidth: 50
    )
    .frame(width: 200, height: 200)

如何使用图像和其他视图作为背景?

SwiftUI 没有专用的修饰符来显示背景颜色或图像,而是使用其 background() 修饰符指定任何类型的背景视图。

例如,这将创建一个具有大字体的文本视图,然后在其后放置一个 100x100 的图像:

Text("Hacking with Swift")
    .font(.system(size: 48))
    .padding(50)
    .background(
        Image("singapore")
            .resizable()
    )

image.png

但是,它不必是图像。 例如,这将创建相同的文本视图,然后在其后放置一个 50x50 的红色圆圈:

Text("Hacking with Swift")
    .font(.largeTitle)
    .padding()
    .background(Circle()
        .fill(Color.red)
        .frame(width: 50, height: 50))

image.png

默认情况下,背景视图会自动占用需要完全可见的空间,但是如果您愿意,可以使用 clipped() 修饰符将其裁剪为其父视图的大小:

Text("Hacking with Swift")
    .font(.largeTitle)
    .padding()
    .background(
        Circle()
            .fill(Color.red)
            .frame(width: 100, height: 100)
    )
    .clipped()

如何显示实体形状?

SwiftUI 具有多种内置形状,例如矩形,圆形和胶囊形,可以根据需要创建,着色和定位每种形状。

例如,如果您想要一个 200x200 的红色矩形,则可以使用以下代码:

Rectangle()
    .fill(Color.red)
    .frame(width: 200, height: 200)

同样,如果您想要一个 100x100 的蓝色圆圈,则可以使用以下方法:

Circle()
    .fill(Color.blue)
    .frame(width: 100, height: 100)

圆角矩形有专用的形状,可让您自定义应应用的圆角程度,并完全控制圆角的类型。 例如,这将创建一个圆角矩形,每个角上有 25 个舍入点:

RoundedRectangle(cornerRadius: 25)
    .fill(Color.green)
    .frame(width: 150, height: 100)

最后,SwiftUI 提供 Capsule() 形状作为圆角矩形的一种特殊形式,其中矩形的最短边始终是完全圆角的。 这是带有按钮的流行样式,因为只需几行代码就可以得到胶囊形的按钮:

Capsule()
    .fill(Color.green)
    .frame(width: 150, height: 100)

如何同时填充和描边形状?

SwiftUI 提供了 fill()stroke() 和 strokeBorder() 修饰符,用于调整绘制图形的方式,但它并未提供内置的填充和描边方式。 但是,我们可以通过两种不同的方式获得相同的效果,在这里我将向大家展示。

第一种选择是使用 strokeBorder() 在形状周围添加边框,然后使用 background() 在背景中放置填充的形状。 例如,这将创建一个带有黑色笔划和蓝色填充的圆:

Circle()
    .strokeBorder(Color.black, lineWidth: 20)
    .background(Circle().fill(Color.blue))
    .frame(width: 150, height: 150)

image.png

使用 background() 可确保蓝色圆圈始终与红色圆圈的大小匹配。

第二个选择是使用ZStack手动将两个圆圈分层:

image.png

ZStack {
    Circle()
        .fill(Color.red)

    Circle()
        .strokeBorder(Color.black, lineWidth: 20)
}
.frame(width: 150, height: 150)

如何使用 trim() 绘制实体形状的一部分?

SwiftUI 允许我们使用其 trim() 修饰符仅绘制笔触的一部分或填充形状,该修饰符采用两个参数:起始值和终止值,都存储为 0 到 1 之间的 CGFloat

例如,如果您想要一个半圆,则可以这样写:

image.png

Circle()
    .trim(from: 0, to: 0.5)
    .frame(width: 200, height: 200)

SwiftUI 绘制其形状,以使 0 度直接位于右侧,因此,如果要更改为使其直接向上0度,则应应用 rotationEffect() 修饰符。

例如,它使用计时器来调整传递给 trim() 的值,以使矩形的笔触随着时间的推移而增长,例如进度指示器:

struct ContentView: View {
    @State private var completionAmount: CGFloat = 0.0
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    var body: some View {
        Rectangle()
            .trim(from: 0, to: completionAmount)
            .stroke(Color.red, lineWidth: 20)
            .frame(width: 200, height: 200)
            .rotationEffect(.degrees(-90))
            .onReceive(timer) { _ in
                withAnimation {
                    if completionAmount == 1 { 
                        completionAmount = 0
                    } else {
                        completionAmount += 0.2
                    }
                }
            }
    }
}

如何使用 VideoPlayer 播放电影?

SwiftUI 的 VideoPlayer 视图使我们可以从本地或远程的任何URL播放电影。 它来自 AVKit 框架,因此在尝试之前,请确保并添加导入 AVKit

例如,如果您的应用程序包中包含 video.mp4 并想播放,请使用以下命令:

VideoPlayer(player: AVPlayer(url:  Bundle.main.url(forResource: "video", withExtension: "mp4")!))
    .frame(height: 400)

提醒:您需要将导入 AVKit 添加到 Swift 文件中才能使用它。

如果要播放远程视频,请改用其远程URL:

VideoPlayer(player: AVPlayer(url:  URL(string: "https://media.w3.org/2010/05/sintel/trailer.mp4")!))
    .frame(height: 400)

如果需要,可以向 VideoPlayer 初始化程序提供第二个参数,该参数添加要在视频上绘制的内容。 此内容将绘制在系统视频控件下方,但可以响应那些控件未捕获的任何事件。

例如,这会将文本“水印(Watermark)”放置在视频区域的顶部:

image.png

VideoPlayer(player: AVPlayer(url:  URL(string: "https://media.w3.org/2010/05/sintel/trailer.mp4")!)) {
    VStack {
        Text("Watermark")
            .foregroundColor(.black)
            .background(Color.white.opacity(0.7))
        Spacer()
    }
    .frame(width: 400, height: 300)
}

如何从 URL 加载远程图像?

SwiftUI 有一个专用的 AsyncImage 用于从互联网下载和显示远程图像。 以最简单的形式,您可以只传递一个 URL,如下所示:

if #available(iOS 15.0, *) {
  AsyncImage(url: URL(string: "https://avatars.githubusercontent.com/u/1680273?v=4"))
} else {
  // Fallback on earlier versions
}

请注意 URL 是如何可选的——如果 URL 字符串无效,AsyncImage 将只显示一个默认的灰色占位符。 如果由于某种原因无法加载图像 —— 如果用户离线,或者图像不存在——那么系统将继续显示相同的占位符图像。