SwiftUI:让你的边框动起来(一)—dashPhase

有时候需要边框有线条流动的动画效果,接下来几篇文章会来探讨下不同的实现方式。本文主要是介绍第一种方式dashPhase。

dashPhase是绘制视图边框StrokeStyle上的一个属性,StrokeStyle的完整属性列表如下:

 	 
    public var lineWidth: CGFloat

    
    public var lineCap: CGLineCap

    
    public var lineJoin: CGLineJoin

    
    
    public var miterLimit: CGFloat

    
    public var dash: [CGFloat]

    
    public var dashPhase: CGFloat
字段 说明
lineWidth 边框宽度
lineCap 每段线条终点的样式 butt: 线段的端点是平的,直接在线段的终点结束。 round:线段的端点是圆形的,线段的终点会添加一个半径为线宽一半的圆。 square:线段的端点也是平的,但是会超出路径的终点,超出的距离为线宽的一半。
lineJoin 线条连接处的样式 miter:斜接连接,在拐角处创建一个尖锐的延伸。 round:圆形连接,拐角处用一个圆角来连接,效果比较平滑。 bevel:斜角连接,拐角处直接将线段切平,形成一个斜面。 以下分别是三种样式的示意图(右上角两根线条的连接处):
截屏2024-09-24 00.34.59.png截屏2024-09-24 00.35.06.png截屏2024-09-24 00.35.12.png
miterLimit 控制当两条线交汇时,交点的斜接(miter)长度。如果斜接长度超过了 miterLimit 设置的值,斜接会自动变成一个斜角(bevel),以避免生成过长的斜接尖角。
dash 用于绘制虚线,数组中元素分别表示绘制和不绘制部分的长度 例如 10, 5:10 表示每段线的长度,5 表示两端段线之间的空白距离。
dashPhase 控制描边的虚线从哪里开始绘制。它定义了虚线图案的偏移量,通过调整dashPhase可以实现像“流动边框”或者“行军蚂蚁”的效果。

看完上面的说明,实现方案其实已经很明晰了。

struct DashPhaseV1: View {
    private var clockwise = false
 	
    @State private var dashPhase: CGFloat = 0
    
    var body: some View {
        Rectangle()
            .strokeBorder(style: .init(lineWidth: 10, lineCap: .round, lineJoin: .round, dash: [20], dashPhase: dashPhase))
            .foregroundStyle(.mint)
            .background(.tertiary)
            .animation(.linear(duration: 1).repeatForever(autoreverses: false), value: dashPhase)
            .frame(width: 200, height: 200)
        
        Button("Start") {
            dashPhase = clockwise ? -40 : 40
        }
        .buttonStyle(.bordered)
        .padding()
    }
}

这段代码会产生下面的效果:
Sep-24-2024 01-14-13.gif

在上面的代码里,dashPhase的值的选择其实是有一定规律的。在解释这个值之前,请允许我先假定一个定义:虚线的基本绘制单位—用来不断重复绘制以形成整个虚线框的最小部分。以dash=20为例,一段长20的实线+一段长20的虚线就是基本绘制单位。dashPhase的值要保证是这个基本绘制单位的长度的整数倍才能保证线条的流动比较流畅。
然后对上面的代码稍作调整,假如让整个边框只有一段实线加上一段虚线组成,就可以实线一小段线段绕矩形流动的效果:

Sep-26-2024 00-18-25.gif
代码如下:

struct DashPhaseV2: View {
    private var clockwise = true
    
    @State private var dashPhase: CGFloat = 0
    private var dash: [CGFloat] = [100, 635] 
    private var cornerRadius: CGFloat = 20 
    
    var body: some View {
        RoundedRectangle(cornerRadius: cornerRadius)
            .strokeBorder(style: .init(lineWidth: 10, lineCap: .round, lineJoin: .miter, dash: dash, dashPhase: dashPhase))
            .foregroundStyle(.mint)
            .background(.tertiary)
            .animation(.linear(duration: 5).repeatForever(autoreverses: false), value: dashPhase)
            .frame(width: 200, height: 200)
        
        Button("Start") {
            let length = dash.reduce(0, +)
            dashPhase = clockwise ? -length : length
        }
        .buttonStyle(.bordered)
        .padding()
    }
}

上面的代码思路大概就是让两条线段可以铺满整个边框。但是在调研的过程中发现两段加起来刚好等于边框的周长,并不能实现像上图中流畅的流动效果,不断测试发现将虚线部分的长度减去30左右的值,一切就很美好了。这一部分如果有朋友知道原理,也欢迎分享下。

总的来说,如果需要实现类似的效果,dashPhase还是可以用的,只是在参数的微调下上可能需要花费些功夫。

SwiftUI:让你的边框动起来(二)——mask

阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=20246,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?