SwiftUI学习(6)-Image
基本使用
自动大小
Image通过imageName初始化,如果不设置图片大小,会自动读取图片大小
Image("cover")
根据2x,3x算出来pt
resizable,重新设置大小
Image必须通过resizable方法才能调整大小,否则设置frame没有作用
resizable有两个参数可以调整capInsets和resizingMode
capInsets表示内间距
resizingMode表示渲染模式
ResizingMode是一个枚举类型有两个取值
public enum ResizingMode {
case tile //瓦片方式
case stretch //拉抻方式
}
具体代码如
Image("cover")
.resizable(capInsets: EdgeInsets(), resizingMode: .tile)
.frame(height:40)
两种方式效果


interpolation,插值
在渲染大小大于图片大小的时候,可以通过interpolation方法进行插值方式的设置
Interpolation是个枚举,具体取值如下:
public enum Interpolation {
case none //无插值
case low //低插值
case medium
case high
}
具体代码如
Image("cover")
.resizable()
.interpolation(.none)
.frame(width: 150, height: 150, alignment: .center)
具体表现如下图


antialiased 抗锯齿
antialiased方法需要传一个bool值确定是否打开抗锯齿。
锯齿何来?
当位图进行旋转和缩放就会产生锯齿。以旋转举例,图像都是数字化非连续的,由像素组成,每个点都是最小单位。当旋转到非水平和垂直的方向时候,它仍然需要落在某一行的某一个格子,而这个格子并不是它应该的位置,所以要么靠前,要么靠后,就出现了锯齿。除非以更小的点作为基本单位,直到突破肉眼分辨率的极限,但是这些图像放大后仍然有锯齿,这是由于位图的显示原理导致的。
而抗锯齿技术的原理就是对于边界通过渐变色的方式,弱化靠前,靠后的影响,视觉上弱化锯齿效果。
打开抗锯齿需要消耗一定的性能,在旋转的时候,我们可以明显的看到抗锯齿的效果
具体代码如
Image("cover2")
.resizable()
.antialiased(true)
.transformEffect(.init(rotationAngle: CGFloat(Double.pi/8)))
.frame(width: 80, height: 80, alignment: .center)
打开和关闭的效果分别如图


通过系统提供的图片初始化
iOS系统提供了很多图片给开发者用,这些图片都是系统内置的,用这些图片不需要倒入到项目里面,如:
Image(systemName: "gear")
.resizable()
.frame(width: 80, height: 80, alignment: .center)
如图

我们如何知道系统有哪些图可用呢?
苹果官方提供了一个mac版的app,里面有所有的图片(其实主要是icon)和对应的名字,
下载地址如下:
https://developer.apple.com/sf-symbols/
具体的软件截图如下:

clipShape,裁剪
这个方法并不是Image独有的,只要是View就有这个方法,图片做clipShape比较普遍,就在这里讲一下。
该方法有两个参数:
shape 实现Shape协议的对象
style FillStyle对象
先说下Shape是一个协议,Shape也遵循View协议,所以也是一个View,在(2)那篇文章介绍过,有Capsule,Circle,ContainerRelativeShape,Ellipse,OffsetShape,Path,Rectangle,RotatedShape,RoundedRectangle(圆角矩形),ScaledShape,TransformedShape。也就是说图片会按照Shape的形状进行裁剪。
再说下FillStyle,FillStype是一个struct,具体定义如下:
public struct FillStyle : Equatable {
public var isEOFilled: Bool //默认false
public var isAntialiased: Bool //默认false
}
它有两个属性,isAntialiased不难理解就是上面介绍的是否支持抗锯齿。
isEOFilled就比较难以理解了。
只要是路径填充,都有两种规则,nonzero和even-odd。
true表示even-odd。false表示nonzero。
那问题来了,nonzero和even-odd又是啥?
首先我们要知道图形(Shape)由stroke(笔触)和fill(填充)组成的。而Shape只是提供了store(笔触)或者说path(路径),但是并没有提供填充的信息。
而nonzero和even-odd正是填充信息的描述。
nonzero表示非0填充。其实这个是比较好理解的。
具体来讲就是一个坐标点是否在图形的内部,如果在图形内部我就填充,否则我就不填充。这就完全跟我们理解上是一致的。只有在闭合路径的内部就填充,外面就不填充。
even-odd比较难以理解。even-odd表示奇偶填充。
图形由一条条路径拼接而成。even-odd的含义表示任意一点往任意方向延伸出一条射线,跟图形中每一条路径相交计数为1,如果相交个数为奇数就填充,相交个数为偶数就不填充,如下图。



所以如上图A不填充,B不填充,C填充。
同理我们可知,对于这个图片如果以nonzero方式进行填充,结果则为A填充,B不填充,C填充。
填充方式 | A | B | C |
---|---|---|---|
nonzero | 填充 | 不填充 | 填充 |
even-odd | 不填充 | 不填充 | 填充 |
具体的代码如下:
Image("cover2")
.resizable()
.frame(width: 80, height: 80, alignment: .center)
.clipShape(Circle())
效果如图:

mask遮罩
与clipShape极其类似,mask是遮罩,它需要传一个遵循View协议的对象。
方法 | 参数 |
---|---|
clipShape | 必须是Shape,支持FillStyle填充 |
mask | 任意View,不支持FillStyle填充 |
代码如下:
Image("cover2")
.resizable()
.frame(width: 80, height: 80, alignment: .center)
.mask(Circle())
展示效果与clipShape是相同的
cornerRadius
这个方法也不是Image独有的它也是View的方法,比UIKit它直接可以设置圆角不同通过layer层,方便很多
代码如下:
Image("cover2")
.resizable()
.frame(width: 80, height: 80, alignment: .center)
.cornerRadius(15)
效果如图:

shadow
shadow也是View的方法,它表示阴影。可以传Color,radius(size)和x,y(position)
代码如下:
Image("cover")
.shadow(color:.gray,radius: 3)
效果如图:

overlay
这个也是View的方法。overlay表示覆盖。
它有两个参数:
overlay:任意遵循View类型的对象
alignment:对齐方式
Alignment是一个struct有两个属性
一个horizontal一个vertical, 分别是两个struct HorizontalAlignment,VerticalAlignment
Alignment有很多全局成员,例如:
public static let center: Alignment
public static let leading: Alignment
public static let trailing: Alignment
public static let top: Alignment
public static let bottom: Alignment
public static let topLeading: Alignment
public static let topTrailing: Alignment
public static let bottomLeading: Alignment
public static let bottomTrailing: Alignment
这些对象的名字已经很明确的表示了它的含义。
overlay的使用方式如下:
Image("cover")
.overlay(Color.blue.clipShape(Circle()))
效果如下:

代码Demo
Demo
struct ImageViewTestView: View {
@State private var animationAmount: CGFloat = 1
@State private var large = false
var body: some View {
VStack(alignment: .center, spacing: 10, content: {
Image("cover")
Image("cover")
.resizable(capInsets: EdgeInsets(), resizingMode: .tile)
.frame(height:40)
Image("cover")
.resizable(capInsets: EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 0), resizingMode: .stretch)
.frame(height:40)
Image("cover")
.resizable()
.interpolation(.none)
.frame(width: 150, height: 150, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
Image("cover")
.resizable()
.interpolation(.high)
.frame(width: 150, height: 150, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
})
VStack {
Image("cover2")
.resizable()
.antialiased(true)
.transformEffect(.init(rotationAngle: CGFloat(Double.pi/8)))
.frame(width: 80, height: 80, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
Spacer()
Image("cover2")
.resizable()
.antialiased(false)
.transformEffect(.init(rotationAngle: CGFloat(Double.pi/8)))
.frame(width: 80, height: 80, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
Spacer()
Image(systemName: "gear")
.resizable()
.frame(width: 80, height: 80, alignment: .center)
Image("cover2")
.resizable()
.frame(width: 80, height: 80, alignment: .center)
.cornerRadius(15)
Image("cover2")
.resizable()
.frame(width: 80, height: 80, alignment: .center)
.clipShape(Circle())
}
VStack {
Image("cover2")
.resizable()
.frame(width: 80, height: 80, alignment: .center)
.mask(Capsule()
.frame(width: 80, height: 60, alignment: .center))
Image("cover")
.shadow(color:.gray,radius: 3)
Image("cover")
.overlay(Color.blue.clipShape(/*@START_MENU_TOKEN@*/Circle()/*@END_MENU_TOKEN@*/))
}
}
}
struct ImageViewTestView_Previews: PreviewProvider {
static var previews: some View {
ImageViewTestView()
}
}
效果图



苹果官方的一个例子
代码
struct ContentView: View {
var body: some View {
Image("cover")
.resizable()
.frame(width: 80, height: 80, alignment: .center)
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 4),alignment: .bottom)
.shadow(radius: 10)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
效果
