形状

咱们运用过的一切视图都是容器或规划用于在屏幕上展现预界说内容,但SwiftUI还内置了图形视图可创立自界说控件或用作闭包。这些视图与之前介绍过的类似,可运用大部分修饰符,但经过特别规划在屏幕上画自界说图形。

通用形状

SwiftUI允许咱们创立预界说或自界说开关。以下是用于创立规范开关的视图。

  • Rectangle() :这个初始化办法创立一个Rectangle视图。矩形的尺寸由视图的框架决议。
  • RoundedRectangle(cornerRadius: CGFloat, style: RoundedCornerStyle):此初始化办法创立一个RoundedRectangle视图。cornerRadius参数指定圆角的半径,style参数是RoundedCornerStyle类型的枚举,指定所用曲率的类型。值有circularcontinuous。该视图还包包经过CGSize的值界说半径的初始化办法:RoundedRectangle(cornerSize: CGSize, style: RoundedCornerStyle)
  • Circle() :些初始化办法创立一个Circle视图。圆的直径由视图的边框决议。
  • Ellipse() :此初始化办法创立一个Ellipse视图。椭圆的巨细由视图框架的宽和高决议。
  • Capsule(style: RoundedCornerStyle):此初始化办法创立一个Capsule视图。style参数是指定运用于边角曲率类型的枚举。值有circularcontinuous

和其它视图相同,图形视图在未指定巨细时采用其容器的巨细,但能够经过frame()修饰符声明详细的巨细。以下示例展现了一切的规范形状。咱们将视图放到了水平的ScrollView视图中,以例能够翻滚列表。

示例11-1:制作规范图形

struct ContentView: View {
    var body: some View {
        VStack {
            ScrollView(.horizontal, showsIndicators: true) {
                HStack {
                    Rectangle()
                        .frame(width: 100, height: 100)
                    RoundedRectangle(cornerRadius: 25, style: .continuous)
                        .frame(width: 100, height: 100)
                    Circle()
                        .frame(width: 100, height: 100)
                    Ellipse()
                        .frame(width: 100, height: 50)
                    Capsule()
                        .frame(width: 100, height: 50)
                }.padding()
            }
            Spacer()
        }
    }
}

大师学SwiftUI第11章 - 图画和动画Part 1

图11-1:规范形状

✍️跟我一同做:创立一个多渠道项目。运用示例11-1中的代码更新ContentView视图。咱们在屏幕上看不全一切形状,将视图向左翻滚。运用这个项目测验本章后续的示例。

默认,视图经过依赖于外观形式的色彩进行烘托(浅色形式为黑色,深色形式为白色),但咱们能够经过如下的修饰符对形状进行填充和边框设置。

  • fill(View):此修饰符经过参数指定的视图填充形状。参数是一个表明色彩、突变或图片的视图。
  • stroke(View, lineWidth: CGFloat):此修饰符界说形状的边框。第一个参数是表明色彩、突变或图片的视图,lineWidth参数界说边框的宽度。
  • stroke(View, style: StrokeStyle):此修饰符界说形状的边框。第一个参数是表明色彩、突变或图片的视图,style参数为StrokeStyle类型的结构体,界说边框的宽度、结尾、衔接、转角定量、虚线和虚线相位。
  • strokeBorder(View, lineWidth: CGFloat):这一修饰符界说开关的内边框。第一个参数是表明色彩、突变或图片的视图,lineWidth参数界说边框的宽度。
  • strokeBorder(View, style: StrokeStyle):此修饰符界说形状的内边框。第一个参数是表明色彩、突变或图片的视图,style参数为StrokeStyle类型的结构体,界说边框的宽度、结尾、衔接、转角定量、虚线和虚线相位。

经过这些修饰符咱们能够改变的有两类:填充和边框。填充由fill()修饰符以及表明内容的视图界说,如Color视图。

示例11-2:运用色彩填充形状

struct ContentView: View {
    var body: some View {
        RoundedRectangle(cornerRadius: 25)
            .fill(Color.red)
            .frame(width: 100, height: 100)
    }
}

注意fill()修饰符由RoundedRectangle视图完成,但frame()回来另一个视图。因而 恣意界说形状的修饰符,比方fill(),有必要在其它修饰符之前,如frame()。本例中,咱们运用这些修饰符创立一个带圆角的赤色方框。

大师学SwiftUI第11章 - 图画和动画Part 1

图11-2:矩形

增加边框的流程类似,但两种类型的修饰符结果稍有不同。stroke()修饰符向内及向外扩展边框,而strokeBorder()修饰符创立一个内边框。

示例11-3:界说边框

struct ContentView: View {
    var body: some View {
        HStack {
            RoundedRectangle(cornerRadius: 25)
                .stroke(Color.red, lineWidth: 20)
                .frame(width: 100, height: 100)
                .padding()
            RoundedRectangle(cornerRadius: 25)
                .strokeBorder(Color.red, lineWidth: 20)
                .frame(width: 100, height: 100)
                .padding()
        }
    }
}

以上视图中包括两个边框为20点的RoundedRectangle视图,但由于运用的是不同的修饰符,边框不同。第一个方框的边框有一差别在图形外制作,而另一半在视图边框内制作,但第二个方框的边框在边框内,如下图所示。

大师学SwiftUI第11章 - 图画和动画Part 1

图11-3:带不同边框的矩形

这两个修饰符也能够接纳StrokeStyle结构体对边框进行调优。该结构体供给了如下的初始化办法。

  • StrokeStyle(lineWidth: CGFloat, lineCap: CGLineCap, lineJoin: CGLineJoin, miterLimit: CGFloat, dash: [CGFloat], dashPhase: CGFloat):此初始化办法创立一个装备笔触的StrokeStyle结构体。lineWidth参数指定宽度。lineCap参数指定线结尾的款式。它是一个枚举,值有butt(平直方形)、round(圆形)和square(方形)。lineJoin参数设置两个衔接线结点的款式。它是一个枚举,值有miter(锋利结尾)、round(圆形结尾)和bevel(方形结尾)。miterLimit参数在lineJoin参数为miter时指定线扩展多长。dash参数指定虚线笔触每段的长度。dashPhase参数指定虚线的起点。

注:buttsquare都是方形结尾,但前者没有扩展段,后者有扩展段。

下例创立了一个RoundedRectangle视图,鸿沟以15点宽和圆形结尾装备虚线。

示例11-4:界说自界说边框

struct ContentView: View {
    let lineStyle = StrokeStyle(lineWidth: 15, lineCap: .round, lineJoin: .round, miterLimit: 0, dash: [20], dashPhase: 0)
    var body: some View {
        RoundedRectangle(cornerRadius: 25)
            .stroke(Color.red, style: lineStyle)
            .frame(width: 100, height: 100)
    }
}

大师学SwiftUI第11章 - 图画和动画Part 1

图11-4:带自界说笔触的矩形

形状也是视图,因而能够结合SwiftUI的视图和控件运用。比方下例中将Capsule形状赋值为按钮的布景。

示例11-5:结合形状和其它视图

struct ContentView: View {
    @State private var setActive: Bool = true
    var body: some View {
        VStack {
            Button(action: {
                setActive.toggle()
            }, label: {
                Text(setActive ? "Active" : "Inactive")
                    .font(.title)
                    .foregroundColor(Color.white)
                    .padding(.horizontal, 30)
                    .padding(.vertical, 10)
            })
            .background(
                Capsule()
                    .fill(setActive ? Color.green : Color.red)
            )
            Spacer()
        }.padding()
    }
}

事实上,background()修饰符有一个版别专门用于形状。

  • background(Color, in: Shape):这一修饰符将形状赋值给视图的布景。第一个参数指定色彩,in参数指定形状。

运用该修饰符,咱们能够经过一行代码声明上例中的按钮。

示例11-6:将形状赋值为按钮的布景

.background(setActive ? Color.green : Color.red, in: Capsule())

该按钮切换@State属性的值。若值为true,展现标签Active并将绿色胶囊赋值为按钮的布景,否则显现标签Inactive并将胶囊变为赤色。

大师学SwiftUI第11章 - 图画和动画Part 1

图11-5:图形按钮

突变

形状的填充和边框也能够运用色彩突变界说。SwiftUI有4个显现突变的结构体:LinearGradientRadialGradientAngularGradientEllipticalGradient。这些结构体遵从ShapeStyle协议,协议界说了如下办法创立自界说实例。

  • linearGradient(Gradient, startPoint: UnitPoint, endPoint: UnitPoint):此办法回来一个线性突变。gradient参数是供运用的色彩突变,startPointendPoint参数指定突变在形状中开端和完毕的点。
  • radialGradient(Gradient, center: UnitPoint, startRadius: CGFloat, endRadius: CGFloat):此办法回来一个环形突变。gradient参数是供运用的色彩突变。center参数指定圆心的方位,startRadiusendRadius参数指定突变的开端和完毕方位。
  • ellipticalGradient(Gradient, center: UnitPoint, startRadiusFraction: CGFloat, endRadiusFraction: CGFloat):此办法回来一个椭圆形状的径向突变。gradient参数是供运用的色彩突变。center参数指定椭圆的圆心,startRadiusFractionendRadiusFraction指定椭圆的半径。
  • angularGradient(Gradient, center: UnitPoint, startAngle: Angle, endAngle: Angle):此办法回来一个视点突变。gradient参数是供运用的色彩突变。center参数指定形状的中心,startAngle参数指定突变的开端视点,endAngle指定完毕视点。
  • conicGradient(Gradient, center: UnitPoint, angle: Angle):此办法回来一个锥形突变。gradient参数是供运用的色彩突变。center参数指定圆锥顶点的方位,angle参数指定突变开端的视点。

这些回来前面介绍的突变结构体中一种的实例,但色彩的突变经过Gradient结构体来界说。

  • Gradient(colors: [Color]):此初始化办法经过参数指定的色彩创立一个突变。colors参数是一个Color视图数组。
  • Gradient(stops: [Gradient.Stop]):此初始化办法经过参数指定的色彩创立一个突变。stops参数为指定色彩的Stop结构体的数组,以及完毕的时机。

另一个展现突变所需的值是UnitPoint结构体。它类似CGPoint结构体,但专门规划用于处理图形结构体。

  • UnitPoint(x: CGFloat, y: CGFloat):此初始化办法创立一个UnitPoint结构体。xy参数指定该点的x和y坐标。关于突变,这些参数值在0.0到1.0之间。

UnitPoint结构体包括界说通用点的类型属性bottombottomLeadingbottomTrailingcenterleadingtoptopLeadingtopTrailingtrailingzero。例如,咱们对线性突变运用bottomtop来从形状的底部到顶部制作突变。

示例11-7:界说线性突变

struct ContentView: View {
    let gradient = Gradient(colors: [Color.red, Color.green])
    var body: some View {
        RoundedRectangle(cornerRadius: 25)
            .fill(.linearGradient(gradient, startPoint: .bottom, endPoint: .top))
            .frame(width: 100, height: 100)
    }
}

示例11-7中的代码界说了两种色彩,赤色和绿色的突变,然后运用linearGradient()办法回来的结构体将突变运用于RoundedRectangle视图。由于运用bottom声明晰开端点,并用top声明晰完毕点,按从底到顶的顺序显现Gradient结构体中声明的色彩。

大师学SwiftUI第11章 - 图画和动画Part 1

图11-6:线性突变

创立突变时若未指定完毕色彩,色彩会在突变占有的整个区域中均匀分布。假如期望调整分布,有必要经过Stop结构体界说色彩。

  • Stop(color: Color, location: CGFloat):此初始化办法经过完毕值创立一个色彩。color参数指定色彩,location参数指定色彩在突变中开端的方位(值为0.0到1.0)。

下例重现了前面的事例,但这次绿色从0.4处开端(突变占有区域的40%)。

示例11-8:经过自界说了完毕点界说线性突变

struct ContentView: View {
    let gradient = Gradient(stops: [
        Gradient.Stop(color: Color.red, location: 0.0),
        Gradient.Stop(color: Color.green, location: 0.4)
    ])
    var body: some View {
        RoundedRectangle(cornerRadius: 25)
            .fill(.linearGradient(gradient, startPoint: .bottom, endPoint: .top))
            .frame(width: 100, height: 100)
    }
}

大师学SwiftUI第11章 - 图画和动画Part 1

图11-7:带自界说完毕点的线性突变

除了线性突变,咱们还能够创立各种形状的突变。例如,经过圆心向外制作环形图层来创立径向和椭圆突变,如下所示。

示例11-9:界说环形变量

struct ContentView: View {
    let gradient = Gradient(colors: [Color.red, Color.white])
    var body: some View {
        RoundedRectangle(cornerRadius: 25)
            .fill(.radialGradient(gradient, center: .center, startRadius: 0, endRadius: 120))
            .frame(width: 100, height: 100)
    }
}

本例描绘了怎么创立径向突变。所需求的值有Gradient结构体、圆心、突变在形状中开端和完毕的方位。这些值指定了突变开端和完毕方位,但仅在形状内的突变部分才进行制作。本例中,endRadius参数指定为120,但由于形状的尺寸是100×100,仅有部分突变可见。

大师学SwiftUI第11章 - 图画和动画Part 1

图11-8:环形突变

还能够运用另外类型的突变,角状或锥状突变。在这些突变中,延着圆制作色彩使其从上方看像是圆锥。所需求的值取决于期望界说的圆锥类型。关于简略的锥形,只需求Gradient结构体、圆心以及突变开端的视点。

示例11-10:界说锥状突变

struct ContentView: View {
    let gradient = Gradient(colors: [Color.red, Color.white])
    var body: some View {
        RoundedRectangle(cornerRadius: 25)
            .fill(.conicGradient(gradient, center: .center, angle: .degrees(180)))
            .frame(width: 100, height: 100)
    }
}

突变的视点经过Angle结构体的一个实例进行声明。这个结构体包括两类按度数或弧度值进行界说的办法:degrees(Double)radians(Double)。在示例11-10的示例中,突变的开端视点以180角进行界说,这正是默认开端点的对面。

大师学SwiftUI第11章 - 图画和动画Part 1

图11-9:锥形突变

作用

ShapeStyle协议中界说了前面末节中完成用于创立突变结构体的类型办法,也指定了对其它视图运用作用的一些属性和办法。以下是最常用的一些。

  • shadow(ShadowStyle):此办法对视图运用暗影。参数是创立内外投影的两个类型办法:drop(color: Color, radius: CGFloat, x: CGFloat, y: CGFloat)inner(color: Color, radius: CGFloat, x: CGFloat, y: CGFloat)
  • opacity(Double):此办法对视图赋值参数指定的透明度级别。参数接纳0.0(全透明)到1.0(不透明)之间的值。
  • blendMode(BlendMode):此办法决议了视图与布景及其它视图的混合办法。参数是一个枚举,值有:normaldarkenmultiplycolorBurnplusDarkerlightenscreencolorDodgeplusLighteroverlaysoftLighthardLightdifferenceexclusionhuesaturationcolorluminositysourceAtopdestinationOverdestinationOut

很我修饰符能够接纳遵从ShapeStyle协议的结构来为视图赋值款式。在操作形状时,这些款式与foregroundStyle()修饰符合作更佳。例如,若期望对矩形运用暗影,咱们能够运用这一修饰符来完成暗影,运用foregroundStyle()修饰符界说填充色彩,如下例所示。

示例11-11:对视图增加暗影

struct ContentView: View {
    var body: some View {
        RoundedRectangle(cornerRadius: 25)
            .foregroundStyle(.shadow(.drop(color: .black, radius: 3, x: 4, y: 4)))
            .foregroundColor(.red)
            .frame(width: 100, height: 100)
    }
}

大师学SwiftUI第11章 - 图画和动画Part 1

图11-10:暗影

图画

除了色彩和突变,咱们还能够运用图片来填充形状。为此SwiftUI内置了ImagePaint结构体。该结构体内置了如下类型办法用于创立自界说实例。

  • image(Image, sourceRect: CGRect, scale: CGFloat):此办法回来按参数指定的图片和装备的ImagePaint结构体。第一个参数供给咱们期望运用的图片的Image视图,sourceRect参数指定要制作的图片部分(默以为整个图片),scale参数界说图片的缩放(默以为原始巨细)。

默认,ImagePaint结构体以原始尺寸运用整个图片,因而大多数情况下指定图片就足以让系统创立图画了,如下例所示。

示例11-12:运用图片填充形状

struct ContentView: View {
    var body: some View {
        Rectangle()
            .fill(.image(Image(.pattern)))
            .frame(width: 100, height: 100)
    }
}

图片无限重复直到填充整个形状。在本例中,咱们界说了一个100乘100个点的方块,运用一个25乘25点的图片进行制作。由于图片小于形状,所以进行了屡次制作覆盖了整个区域。

大师学SwiftUI第11章 - 图画和动画Part 1

图11-11:图画

其它相关内容请见虚拟实际(VR)/增强实际(AR)&visionOS开发学习笔记