最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Swift 制作一个带动画效果的环形进度条例子
时间:2022-06-25 23:39:53 编辑:袖梨 来源:一聚教程网
1,带动画效果的环形进度条
下面我们演示如何制作一个环状进度条组件,当进度改变时,进度条长度变化时是有动画效果的(我们还可以设置动画时间,或者关闭动画),效果图如下:
(1)动画实现原理
使用 Core Animation 动画根据进度改变进度条(CAShapeLayer)的 strokeEnd。
(2)组件代码(OProgressView.swift)
import UIKit
@IBDesignable class OProgressView: UIView {
struct Constant {
//进度条宽度
static let lineWidth: CGFloat = 10
//进度槽颜色
static let trackColor = UIColor(red: 245/255.0, green: 245/255.0, blue: 245/255.0,
alpha: 1)
//进度条颜色
static let progressColoar = UIColor.orangeColor()
}
//进度槽
let trackLayer = CAShapeLayer()
//进度条
let progressLayer = CAShapeLayer()
//进度条路径(整个圆圈)
let path = UIBezierPath()
//当前进度
@IBInspectable var progress: Int = 0 {
didSet {
if progress > 100 {
progress = 100
}else if progress < 0 {
progress = 0
}
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func drawRect(rect: CGRect) {
//获取整个进度条圆圈路径
path.addArcWithCenter(CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)),
radius: bounds.size.width/2 - Constant.lineWidth,
startAngle: angleToRadian(-90), endAngle: angleToRadian(270), clockwise: true)
//绘制进度槽
trackLayer.frame = bounds
trackLayer.fillColor = UIColor.clearColor().CGColor
trackLayer.strokeColor = Constant.trackColor.CGColor
trackLayer.lineWidth = Constant.lineWidth
trackLayer.path = path.CGPath
layer.addSublayer(trackLayer)
//绘制进度条
progressLayer.frame = bounds
progressLayer.fillColor = UIColor.clearColor().CGColor
progressLayer.strokeColor = Constant.progressColoar.CGColor
progressLayer.lineWidth = Constant.lineWidth
progressLayer.path = path.CGPath
progressLayer.strokeStart = 0
progressLayer.strokeEnd = CGFloat(progress)/100.0
layer.addSublayer(progressLayer)
}
//设置进度(可以设置是否播放动画)
func setProgress(pro: Int,animated anim: Bool) {
setProgress(pro, animated: anim, withDuration: 0.55)
}
//设置进度(可以设置是否播放动画,以及动画时间)
func setProgress(pro: Int,animated anim: Bool, withDuration duration: Double) {
progress = pro
//进度条动画
CATransaction.begin()
CATransaction.setDisableActions(!anim)
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name:
kCAMediaTimingFunctionEaseInEaseOut))
CATransaction.setAnimationDuration(duration)
progressLayer.strokeEnd = CGFloat(progress)/100.0
CATransaction.commit()
}
//将角度转为弧度
private func angleToRadian(angle: Double)->CGFloat {
return CGFloat(angle/Double(180.0) * M_PI)
}
}
2,进度条头部增加圆点
下面给进度条头部增加一个带阴影的圆点,其随着进度条的增长也会动态地移动位置。
原文:Swift - 制作一个带动画效果的环形进度条
(1)实现原理
使用关键帧动画(CAKeyframeAnimation)让圆点顺着圆弧路径移动。
(2)组件代码(OProgressView2.swift)
import UIKit
@IBDesignable class OProgressView2: UIView {
struct Constant {
//进度条宽度
static let lineWidth: CGFloat = 10
//进度槽颜色
static let trackColor = UIColor(red: 245/255.0, green: 245/255.0, blue: 245/255.0,
alpha: 1)
//进度条颜色
static let progressColoar = UIColor.orangeColor()
}
//进度槽
let trackLayer = CAShapeLayer()
//进度条
let progressLayer = CAShapeLayer()
//进度条路径(整个圆圈)
let path = UIBezierPath()
//头部圆点
var dot:UIView!
//进度条圆环中点
var progressCenter:CGPoint {
get{
return CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))
}
}
//进度条圆环中点
var radius:CGFloat{
get{
return bounds.size.width/2 - Constant.lineWidth
}
}
//当前进度
@IBInspectable var progress: Int = 0 {
didSet {
if progress > 100 {
progress = 100
}else if progress < 0 {
progress = 0
}
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func drawRect(rect: CGRect) {
//获取整个进度条圆圈路径
path.addArcWithCenter(progressCenter, radius: radius,
startAngle: angleToRadian(-90), endAngle: angleToRadian(270), clockwise: true)
//绘制进度槽
trackLayer.frame = bounds
trackLayer.fillColor = UIColor.clearColor().CGColor
trackLayer.strokeColor = Constant.trackColor.CGColor
trackLayer.lineWidth = Constant.lineWidth
trackLayer.path = path.CGPath
layer.addSublayer(trackLayer)
//绘制进度条
progressLayer.frame = bounds
progressLayer.fillColor = UIColor.clearColor().CGColor
progressLayer.strokeColor = Constant.progressColoar.CGColor
progressLayer.lineWidth = Constant.lineWidth
progressLayer.path = path.CGPath
progressLayer.strokeStart = 0
progressLayer.strokeEnd = CGFloat(progress)/100.0
layer.addSublayer(progressLayer)
//绘制进度条头部圆点
dot = UIView(frame:CGRectMake(0, 0, Constant.lineWidth, Constant.lineWidth))
let dotPath = UIBezierPath(ovalInRect:
CGRectMake(0,0, Constant.lineWidth, Constant.lineWidth)).CGPath
let arc = CAShapeLayer()
arc.line
arc.path = dotPath
arc.strokeStart = 0
arc.strokeEnd = 1
arc.strokeColor = Constant.progressColoar.CGColor
arc.fillColor = Constant.progressColoar.CGColor
arc.shadowColor = UIColor.blackColor().CGColor
arc.shadowRadius = 5.0
arc.shadowOpacity = 0.5
arc.shadowOffset = CGSizeZero
dot.layer.addSublayer(arc)
dot.layer.position = calcCircleCoordinateWithCenter(progressCenter,
radius: radius, angle: CGFloat(-progress)/100*360+90)
addSubview(dot)
}
//设置进度(可以设置是否播放动画)
func setProgress(pro: Int,animated anim: Bool) {
setProgress(pro, animated: anim, withDuration: 0.55)
}
//设置进度(可以设置是否播放动画,以及动画时间)
func setProgress(pro: Int,animated anim: Bool, withDuration duration: Double) {
let oldProgress = progress
progress = pro
//进度条动画
CATransaction.begin()
CATransaction.setDisableActions(!anim)
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name:
kCAMediaTimingFunctionEaseInEaseOut))
CATransaction.setAnimationDuration(duration)
progressLayer.strokeEnd = CGFloat(progress)/100.0
CATransaction.commit()
//头部圆点动画
let startAngle = angleToRadian(360*Double(oldProgress)/100 - 90)
let endAngle = angleToRadian(360*Double(progress)/100 - 90)
let clockWise = progress > oldProgress ? false : true
let path2 = CGPathCreateMutable()
CGPathAddArc(path2, &transform, CGRectGetMidX(bounds), CGRectGetMidY(bounds),
bounds.size.width/2 - Constant.lineWidth,
startAngle, endAngle, clockWise)
let orbit = CAKeyframeAnimation(keyPath:"position")
orbit.duration = duration
orbit.path = path2
orbit.calculationMode = kCAAnimationPaced
orbit.timingFunction =
CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
orbit.removedOnCompletion = false
orbit.fillMode = kCAFillModeForwards
dot.layer.addAnimation(orbit,forKey:"Move")
}
//将角度转为弧度
private func angleToRadian(angle: Double)->CGFloat {
return CGFloat(angle/Double(180.0) * M_PI)
}
//计算圆弧上点的坐标
func calcCircleCoordinateWithCenter(center:CGPoint, radius:CGFloat, angle:CGFloat)
-> CGPoint {
let x2 = radius*CGFloat(cosf(Float(angle)*Float(M_PI)/Float(180)))
let y2 = radius*CGFloat(sinf(Float(angle)*Float(M_PI)/Float(180)))
return CGPointMake(center.x+x2, center.y-y2);
}
}
3,进度条头部再增加一个图片
下面给进度条头部再增加一个前进图标,其随着进度条的增长也会动态地改变朝向(一直朝向前进方向)。
原文:Swift - 制作一个带动画效果的环形进度条
(1)实现原理
箭头图标在最开始位置时,默认方向向右。同时将 CAKeyframeAnimation 的 rotationMode 设为 kCAAnimationRotateAuto,这样随着进度改变,箭头会始终朝着前进方向。
(2)组件代码(OProgressView3.swift)
import UIKit
@IBDesignable class OProgressView3: UIView {
struct Constant {
//进度条宽度
static let lineWidth: CGFloat = 10
//进度槽颜色
static let trackColor = UIColor(red: 245/255.0, green: 245/255.0, blue: 245/255.0,
alpha: 1)
//进度条颜色
static let progressColoar = UIColor.orangeColor()
}
//进度槽
let trackLayer = CAShapeLayer()
//进度条
let progressLayer = CAShapeLayer()
//进度条路径(整个圆圈)
let path = UIBezierPath()
//头部圆点
var dot = UIView()
//头部箭头图片
var arrow = UIImageView(image: UIImage(named: "arrow"))
//进度条圆环中点
var progressCenter:CGPoint {
get{
return CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))
}
}
//进度条圆环中点
var radius:CGFloat{
get{
return bounds.size.width/2 - Constant.lineWidth
}
}
//当前进度
@IBInspectable var progress: Int = 0 {
didSet {
if progress > 100 {
progress = 100
}else if progress < 0 {
progress = 0
}
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func drawRect(rect: CGRect) {
//获取整个进度条圆圈路径
path.addArcWithCenter(progressCenter, radius: radius,
startAngle: angleToRadian(-90), endAngle: angleToRadian(270), clockwise: true)
//绘制进度槽
trackLayer.frame = bounds
trackLayer.fillColor = UIColor.clearColor().CGColor
trackLayer.strokeColor = Constant.trackColor.CGColor
trackLayer.lineWidth = Constant.lineWidth
trackLayer.path = path.CGPath
layer.addSublayer(trackLayer)
//绘制进度条
progressLayer.frame = bounds
progressLayer.fillColor = UIColor.clearColor().CGColor
progressLayer.strokeColor = Constant.progressColoar.CGColor
progressLayer.lineWidth = Constant.lineWidth
progressLayer.path = path.CGPath
progressLayer.strokeStart = 0
progressLayer.strokeEnd = CGFloat(progress)/100.0
layer.addSublayer(progressLayer)
//绘制进度条头部圆点
dot.frame = CGRectMake(0, 0, Constant.lineWidth, Constant.lineWidth)
let dotPath = UIBezierPath(ovalInRect:
CGRectMake(0,0, Constant.lineWidth, Constant.lineWidth)).CGPath
let arc = CAShapeLayer()
arc.line
arc.path = dotPath
arc.strokeStart = 0
arc.strokeEnd = 1
arc.strokeColor = Constant.progressColoar.CGColor
arc.fillColor = Constant.progressColoar.CGColor
arc.shadowColor = UIColor.blackColor().CGColor
arc.shadowRadius = 5.0
arc.shadowOpacity = 0.5
arc.shadowOffset = CGSizeZero
dot.layer.addSublayer(arc)
addSubview(dot)
//圆点中添加箭头图标
arrow.frame.size = CGSize(width: Constant.lineWidth, height: Constant.lineWidth)
dot.addSubview(arrow)
//设置圆点位置
dot.layer.position = calcCircleCoordinateWithCenter(progressCenter,
radius: radius, angle: CGFloat(-progress)/100*360+90)
}
//设置进度(可以设置是否播放动画)
func setProgress(pro: Int,animated anim: Bool) {
setProgress(pro, animated: anim, withDuration: 0.55)
}
//设置进度(可以设置是否播放动画,以及动画时间)
func setProgress(pro: Int,animated anim: Bool, withDuration duration: Double) {
let oldProgress = progress
progress = pro
//进度条动画
CATransaction.begin()
CATransaction.setDisableActions(!anim)
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name:
kCAMediaTimingFunctionEaseInEaseOut))
CATransaction.setAnimationDuration(duration)
progressLayer.strokeEnd = CGFloat(progress)/100.0
CATransaction.commit()
//头部圆点动画
let startAngle = angleToRadian(360*Double(oldProgress)/100 - 90)
let endAngle = angleToRadian(360*Double(progress)/100 - 90)
let clockWise = progress > oldProgress ? false : true
let path2 = CGPathCreateMutable()
CGPathAddArc(path2, &transform, CGRectGetMidX(bounds), CGRectGetMidY(bounds),
bounds.size.width/2 - Constant.lineWidth,
startAngle, endAngle, clockWise)
let orbit = CAKeyframeAnimation(keyPath:"position")
orbit.duration = duration
orbit.path = path2
orbit.calculationMode = kCAAnimationPaced
orbit.timingFunction =
CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
orbit.rotationMode = kCAAnimationRotateAuto
orbit.removedOnCompletion = false
orbit.fillMode = kCAFillModeForwards
dot.layer.addAnimation(orbit,forKey:"Move")
}
//将角度转为弧度
private func angleToRadian(angle: Double)->CGFloat {
return CGFloat(angle/Double(180.0) * M_PI)
}
//计算圆弧上点的坐标
func calcCircleCoordinateWithCenter(center:CGPoint, radius:CGFloat, angle:CGFloat)
-> CGPoint {
let x2 = radius*CGFloat(cosf(Float(angle)*Float(M_PI)/Float(180)))
let y2 = radius*CGFloat(sinf(Float(angle)*Float(M_PI)/Float(180)))
return CGPointMake(center.x+x2, center.y-y2);
}
}
4,测试代码
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var oProgressView1: OProgressView!
@IBOutlet weak var oProgressView2: OProgressView2!
@IBOutlet weak var oProgressView3: OProgressView3!
override func viewDidLoad() {
super.viewDidLoad()
}
//增加进度
@IBAction func addProgress(sender: AnyObject) {
oProgressView1.setProgress(oProgressView1.progress + 25, animated: true)
oProgressView2.setProgress(oProgressView2.progress + 25, animated: true)
oProgressView3.setProgress(oProgressView3.progress + 25, animated: true)
}
//减少进度
@IBAction func minusProgress(sender: AnyObject) {
oProgressView1.setProgress(oProgressView1.progress - 20, animated: true)
oProgressView2.setProgress(oProgressView2.progress - 20, animated: true)
oProgressView3.setProgress(oProgressView3.progress - 20, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
原文出自:www.hangge.com
相关文章
- 王者荣耀侦探能力大测试攻略 王者荣耀侦探能力大测试怎么过 11-22
- 无期迷途主线前瞻兑换码是什么 11-22
- 原神欧洛伦怎么培养 11-22
- 炉石传说网易云音乐联动怎么玩 11-22
- 永劫无间手游确幸转盘怎么样 11-22
- 无期迷途主线前瞻兑换码是什么 无期迷途主线前瞻直播兑换码介绍 11-22