3步搞定iOS按钮转场动画:TKSubmitTransition完整自定义指南

📅 2026/8/24 2:15:02
3步搞定iOS按钮转场动画:TKSubmitTransition完整自定义指南
3步搞定iOS按钮转场动画TKSubmitTransition完整自定义指南【免费下载链接】TKSubmitTransitionAnimated UIButton of Loading Animation and Transition Animation. Inspired by https://dribbble.com/shots/1945593-Login-Home-Screen项目地址: https://gitcode.com/gh_mirrors/tk/TKSubmitTransitionTKSubmitTransition 是一个 iOS 动画库把按钮的加载动画和视图过渡效果封装进一个 UIButton点击后按钮变圆转圈再放大盖住全屏完成页面转场。读完本文你能从改一个属性做到从零实现自定义 Transitioning 协议。先跑起来15行代码运行按钮加载动画最小示例只要 15 行代码30 秒就能看到按钮变圆、转圈、放大盖满全屏的完整效果。引入 TKSubmitTransitionCocoaPods 或把 Classes 下源文件拷入工程后这段代码创建一个红色提交按钮点击先播加载动画1 秒后放大并 present 一个白底页面let btn TKTransitionSubmitButton(frame: CGRect(x: 32, y: 300, width: 250, height: 44)) btn.backgroundColor .red btn.setTitle(Sign in, for: UIControl.State()) btn.addTarget(self, action: #selector(onTap(_:)), for: .touchUpInside) view.addSubview(btn) objc func onTap(_ button: TKTransitionSubmitButton) { button.animate(1) { [weak self] in // ← 关键改动1秒后启动完成动画 let next UIViewController() next.view.backgroundColor .white next.modalPresentationStyle .fullScreen self?.present(next, animated: true) } }运行后你看到按钮先收成圆、白色加载圈开始转1 秒后圆放大到 26 倍铺满全屏放大结束的瞬间白页淡入随后按钮恢复原状。这张动图完整展示了按钮变圆、加载圈旋转、放大过渡到下一页的全过程它到底在干什么加载与转场动画的核心机制拆解整个效果由两个类分工TKTransitionSubmitButton 负责按钮自身的三段变形TKFadeInAnimator 负责页面之间的淡入淡出。TKTransitionSubmitButton 继承 UIButton同时实现 UIViewControllerTransitioningDelegate把系统转场动画交给自定义实现的协议和 CAAnimationDelegate监听 Core Animation 动画结束。它内部还持有 SpinerLayer——一个只画 40% 弧线的 CAShapeLayer就是那个旋转的加载圈。按下按钮后startLoadingAnimation() 先缓存并清空标题把 SpinerLayer 加到按钮上再把 cornerRadius 动画到高度的一半、宽度收缩到与高度相等矩形按钮变成圆加载圈随即开始旋转。startFinishAnimation(_:completion:) 在指定延迟后调用 expand()把 transform.scale 从 1 放大到 26默认缩放 26 倍圆按钮在视觉上盖住整屏。scale 动画结束时 animationDidStop 触发你的 completionpresent 下一页1 秒后按钮自动还原。整体流程点击 → startLoadingAnimation()变圆转圈→ 等待 delay → expand()缩放 26 倍盖住全屏→ completion 回调 present 下一页 → TKFadeInAnimator 淡入 → 1 秒后按钮还原。页面转场交给 TKFadeInAnimator它把旧页面透明度压到 0.8 再淡出新页面从 0.8 淡入到 1两个动画同时进行掩盖了 present 的硬切。这张图是 Demo 登录页使用的背景图按钮就放在这张图的下方从调参到换引擎分层定制按钮转场动画的3个层级定制分三档改属性、改单个动画阶段、重写整个转场按你的需求取用即可。轻度定制如何修改加载动画颜色与圆角这一档不用写子类两个 open 属性直接赋值就行。这段代码只改两个属性让加载圈变蓝、按钮带 22pt 圆角let btn TKTransitionSubmitButton(frame: someFrame) btn.spinnerColor .blue // ← 关键改动加载圈默认白色 btn.normalCornerRadius 22 // ← 关键改动默认 0即直角注意 shrinkDuration0.1 秒是 let 常量expand 的 26.0 倍也是写死的属性层面改不了节奏那是下一档的事。判断如果你只是想让加载圈变色、按钮带圆角做完这一档就够。中度定制如何替换单个动画阶段把源码拷进 App Target继承按钮类重写 expand()就能换掉完成阶段。以 Pod 引入时 internal 方法不可见把 SubmitTransition/Classes 下 4 个源文件拷进工程并加入 Target内部方法就能重写。这段代码重写 expand()把默认的 26 倍、0.3 秒换成 18 倍、0.4 秒的缓出class SoftExpandButton: TKTransitionSubmitButton { override func expand() { let anim CABasicAnimation(keyPath: transform.scale) anim.fromValue 1.0 anim.toValue 18.0 // ← 关键改动默认 26.0 anim.timingFunction CAMediaTimingFunction(name: .easeOut) anim.duration 0.4 // ← 关键改动默认 0.3 anim.delegate self anim.fillMode .forwards anim.isRemovedOnCompletion false layer.add(anim, forKey: anim.keyPath) } }同理可以重写 shrink() 和 cornerRadius() 放慢变身过程改完务必保留 anim.delegate self否则 completion 不会触发。判断要改缩放倍数、时长或变身节奏做到这一档为止只想换页面转场方式的话按钮本身不用动。重度定制自定义Transitioning协议实现步骤这一档彻底替换 TKFadeInAnimator自己实现 UIViewControllerAnimatedTransitioning控制页面过渡动画的协议。协议要求实现两个方法一个返回时长一个真正移动视图。先写协议实现class CircleWipe: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using context: UIViewControllerContextTransitioning?) - TimeInterval { return 0.4 } func animateTransition(using context: UIViewControllerContextTransitioning) { let container context.containerView let toView context.view(forKey: .to)! toView.frame container.bounds toView.alpha 0 // ← 关键改动初始透明度 container.addSubview(toView) UIView.animate(withDuration: 0.4) { toView.alpha 1 } } }animateTransition 拿到 containerView转场舞台和 to/from 两个视图摆好新视图、播完动画后必须调用 completeTransition否则系统认为转场卡死。再在过渡代理里换掉返回值转场引擎就整个换掉了extension ViewController: UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) - UIViewControllerAnimatedTransitioning? { return CircleWipe() // ← 关键改动替换 TKFadeInAnimator } }判断只有当默认淡入淡出满足不了视觉要求比如要圆形擦除时才值得写这一档。完整Demo登录按钮加载后淡入主界面需求一句话登录按钮点击后变圆转圈模拟 1 秒请求成功后按钮放大盖屏、主界面淡入。方案选型按钮侧动画用现成的 animate()页面侧用 TKFadeInAnimator所以不写任何自定义 Transitioning只负责接线。这段代码是 ViewController 里需要写的全部逻辑SecondViewController 即 Demo 自带的主界面源码见 SecondViewController.swiftobjc func onTap(_ button: TKTransitionSubmitButton) { button.animate(1) { [weak self] in // ← 关键改动模拟 1 秒网络请求 let home SecondViewController() home.transitioningDelegate self home.modalPresentationStyle .fullScreen self?.present(home, animated: true) } } extension ViewController: UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) - UIViewControllerAnimatedTransitioning? { return TKFadeInAnimator(transitionDuration: 0.5, startingAlpha: 0.8) } }最终效果按钮放大盖住全屏的瞬间主界面从 0.8 透明度淡入视觉上像按钮展开成了新页面。这张图是转场完成后的主界面踩坑提醒⚠️ 快速双击会叠两个加载圈isAnimating 只置位不拦重入。点击时禁用按钮completion 里再启用。⚠️ 白底页面上看不到加载圈spinnerColor 默认白色。按背景色改一下即可。⚠️ 在 expand 结束前就 present页面转场和按钮缩放会打架把 present 放进 animate 的 completion 里。下一步源码模块与延伸资源全部源码不到 300 行按这个顺序读一遍半天能摸清。按钮动画主类TransitionSubmitButton.swift加载圈实现SpinerLayer.swift默认淡入转场FadeTransition.swiftDemo 接线示例ViewController.swift官方文档入口README.md相关项目推荐Hero按视图层级声明对象过渡动画、Lottie用动画文件驱动复杂加载动画先只改 spinnerColor 和 normalCornerRadius 验证手感确认视觉方向后再决定是否重抄 expand() 改节奏最后才考虑自定义 Transitioning。【免费下载链接】TKSubmitTransitionAnimated UIButton of Loading Animation and Transition Animation. Inspired by https://dribbble.com/shots/1945593-Login-Home-Screen项目地址: https://gitcode.com/gh_mirrors/tk/TKSubmitTransition创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考