前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SwiftUI:自定义 Shape 使用 InsettableShape 协议实现向内绘制边框

SwiftUI:自定义 Shape 使用 InsettableShape 协议实现向内绘制边框

作者头像
韦弦zhy
发布2020-05-08 01:00:31
1.7K0
发布2020-05-08 01:00:31
举报
\color{red}{\Large \mathbf{Hacking \quad with \quad iOS: SwiftUI \quad Edition}}
\color{red}{\Large \mathbf{Hacking \quad with \quad iOS: SwiftUI \quad Edition}}
{\Large \mathbf{Drawing:InsettableShape}}
{\Large \mathbf{Drawing:InsettableShape}}

如果创建的形状没有特定大小,它将自动扩展以占据所有可用空间。例如,这将创建一个填充我们视图的圆,并为其提供40点蓝色边框:

代码语言:swift
复制
struct ContentView: View {
    var body: some View {
        Circle()
            .stroke(Color.blue, lineWidth: 40)
    }
}
stroke() 绘制
stroke() 绘制
仔细观察边框的左右边缘——您注意到边框是怎么被切掉的吗?

您在这里看到的是SwiftUI在形状周围绘制边框的方式的副作用。如果您递给某人一个圆的铅笔轮廓,并要求他们用粗笔在该圆上画线,他们将绘制出该圆的精确线——大约一半的笔在该线的内部,一半在该线的外部。这就是SwiftUI为我们所做的,但是当形状到达屏幕边缘时,则意味着边框的外部最终超出了屏幕边缘。

现在尝试改用这个圆:

代码语言:swift
复制
Circle()
    .strokeBorder(Color.blue, lineWidth: 40)
strokeBorder() 绘制
strokeBorder() 绘制

这将stroke()更改为strokeBorder(),现在我们得到了更好的结果:我们的所有边框都是可见的,因为Swift在圆的内部绘制而不是将圆作为绘制的中心。

之前我们建立了一个如下的弧形:

代码语言:swift
复制
struct Arc: Shape {
    var startAngle: Angle
    var endAngle: Angle
    var clockwise: Bool

    func path(in rect: CGRect) -> Path {
        let rotationAdjustment = Angle.degrees(90)
        let modifiedStart = startAngle - rotationAdjustment
        let modifiedEnd = endAngle - rotationAdjustment

        var path = Path()
        path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: modifiedStart, endAngle: modifiedEnd, clockwise: !clockwise)

        return path
    }
}

就像Circle一样,它会自动占用所有可用空间。但是,这种代码不起作用:

代码语言:swift
复制
Arc(startAngle: .degrees(-90), endAngle: .degrees(90), clockwise: true)
    .strokeBorder(Color.blue, lineWidth: 40)

如果您打开Xcode的错误消息,则会看到它显示“Value of type 'Arc' has no member 'strokeBorder'''——也就是说,arc中不存在strokeBorder()修饰符。

SwiftUI的Circle和我们的Arc之间有一个微小但重要的区别:两者均符合Shape协议,但Circle也符合名为InsettableShape的第二种协议。该形状可以嵌入(向内减小)一定距离以产生另一个形状。它产生的插图形状可以是任何其他类型的插图形状,但实际上,它应该是一个有相同形状的较小的矩形。

为了使Arc符合InsettableShape,我们需要为其添加一个额外的方法:inset(by :)。这将获得插入量(笔画的线宽的一半),并应返回一种新的可插入形状——在我们的实例中,这意味着我们应该创建一个插入弧型。问题是我们不知道圆弧的实际大小,因为尚未调用path(in :)

事实证明,解决方案非常简单:如果我们为Arc形状提供一个默认为0的新insetAmount属性,则只要调用inset(by :)就可以添加该属性。添加到inset允许我们在需要时多次调用inset(by :),例如,如果我们想手动调用一次,则使用strokeBorder()

首先,将此新属性添加到Arc

代码语言:swift
复制
var insetAmount: CGFloat = 0

现在给它这个inset(by :)方法:

代码语言:swift
复制
func inset(by amount: CGFloat) -> some InsettableShape {
    var arc = self
    arc.insetAmount += amount
    return arc
}

传入的数量参数应应用于所有边缘,这在圆弧的情况下意味着我们应使用它减小绘制半径。因此,将path(in :)内部的addArc()调用更改为:

代码语言:swift
复制
path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2 - insetAmount, startAngle: modifiedStart, endAngle: modifiedEnd, clockwise: !clockwise)

通过该更改,我们现在可以使Arc符合InsettableShape,如下所示:

代码语言:swift
复制
struct Arc: InsettableShape {
自定义 Arc 使用 strokeBorder() 绘制
自定义 Arc 使用 strokeBorder() 绘制
注意:InsettableShape实际上是基于Shape构建的,因此无需在其中添加两者。

译自 Adding strokeBorder() support with InsettableShape

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 仔细观察边框的左右边缘——您注意到边框是怎么被切掉的吗?
  • 注意:InsettableShape实际上是基于Shape构建的,因此无需在其中添加两者。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档