원 그리기 애니메이션
원의 그림을 애니메이션으로 만드는 방법을 찾고 있습니다. 나는 원을 만들 수 있었지만 그것은 모두 함께 그립니다.
내 CircleView수업 은 다음과 가변 .
import UIKit
class CircleView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.clearColor()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func drawRect(rect: CGRect) {
// Get the Graphics Context
var context = UIGraphicsGetCurrentContext();
// Set the circle outerline-width
CGContextSetLineWidth(context, 5.0);
// Set the circle outerline-colour
UIColor.redColor().set()
// Create Circle
CGContextAddArc(context, (frame.size.width)/2, frame.size.height/2, (frame.size.width - 10)/2, 0.0, CGFloat(M_PI * 2.0), 1)
// Draw
CGContextStrokePath(context);
}
}
그리고 다음은 뷰 컨트롤러의 뷰 계층 구조에 추가하는 방법입니다.
func addCircleView() {
let diceRoll = CGFloat(Int(arc4random_uniform(7))*50)
var circleWidth = CGFloat(200)
var circleHeight = circleWidth
// Create a new CircleView
var circleView = CircleView(frame: CGRectMake(diceRoll, 0, circleWidth, circleHeight))
view.addSubview(circleView)
}
원의 그림을 1 초 이상 애니메이션하는 방법이 있습니까?
예를 들어, 애니메이션의 일부는이 이미지에서 파란색 선처럼 보일 것입니다.

이를 수행하는 가장 쉬운 방법은 핵심 애니메이션의 힘을 사용하여 대부분의 작업을 수행하는 것입니다. 이를 위해 원 그리기 코드를 drawRect함수에서 . 그런 다음을 사용하여 의 속성을 에서 . 여기서 마법의 큰 부분을 차지합니다. 문서에서 :CAShapeLayerCABasicAnimationCAShapeLayerstrokeEnd0.01.0strokeEnd
strokeStart 속성과 결합 된이 속성은 채팅 경로의 하위 영역을 정의합니다. 이 속성의 값은 시작 속성이 시작점을 정의하는 동안 문장을 완료 할 경로를 따라 최강 지점을 나타냅니다. 0.0 값은 경로의 시작을 실수 1.0 값은 경로의 끝을 나타냅니다. 그 사이의 값은 경로 길이를 따라 선형으로 해석됩니다.
로 설정 strokeEnd하면 0.0아무것도 그려지지 않습니다. 로 설정하면 1.0완전한 원이 그려집니다. 로 설정하면 0.5반원이 그려집니다. 기타
그래서 시작 가능한 만들 수 있습니다 CAShapeLayer당신의 CircleView의 init에 해당 레이어를 기능을 추가 뷰의 sublayers제거해야 할 drawRect레이어 이제 원을 그리기되기 때문에 기능) :
let circleLayer: CAShapeLayer!
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.clearColor()
// Use UIBezierPath as an easy way to create the CGPath for the layer.
// The path should be the entire circle.
let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: (frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(M_PI * 2.0), clockwise: true)
// Setup the CAShapeLayer with the path, colors, and line width
circleLayer = CAShapeLayer()
circleLayer.path = circlePath.CGPath
circleLayer.fillColor = UIColor.clearColor().CGColor
circleLayer.strokeColor = UIColor.redColor().CGColor
circleLayer.lineWidth = 5.0;
// Don't draw the circle initially
circleLayer.strokeEnd = 0.0
// Add the circleLayer to the view's layer's sublayers
layer.addSublayer(circleLayer)
}
참고 :circleLayer.strokeEnd = 0.0원이 바로 그려지지 않도록 설정 하고 있습니다.
이제 원 애니메이션을 트리거하기 위해 호출 할 수있는 함수를 추가해 보겠습니다.
func animateCircle(duration: NSTimeInterval) {
// We want to animate the strokeEnd property of the circleLayer
let animation = CABasicAnimation(keyPath: "strokeEnd")
// Set the animation duration appropriately
animation.duration = duration
// Animate from 0 (no circle) to 1 (full circle)
animation.fromValue = 0
animation.toValue = 1
// Do a linear animation (i.e. the speed of the animation stays the same)
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
// Set the circleLayer's strokeEnd property to 1.0 now so that it's the
// right value when the animation ends.
circleLayer.strokeEnd = 1.0
// Do the actual animation
circleLayer.addAnimation(animation, forKey: "animateCircle")
}
그런 다음, 우리가해야 할 일은 당신의 변화 addCircleView는 당신이 추가 애니메이션 트리거 기능을 CircleView보충 할 것입니다 superview:
func addCircleView() {
let diceRoll = CGFloat(Int(arc4random_uniform(7))*50)
var circleWidth = CGFloat(200)
var circleHeight = circleWidth
// Create a new CircleView
var circleView = CircleView(frame: CGRectMake(diceRoll, 0, circleWidth, circleHeight))
view.addSubview(circleView)
// Animate the drawing of the circle over the course of 1 second
circleView.animateCircle(1.0)
}
합쳐진 모든 것은 다음과 같은 생각입니다.

참고 : 이렇게 반복되지 않고 애니메이션 된 후에는 완전한 원으로 유지됩니다.
Swift 3.0에 대한 Mikes 답변 업데이트
var circleLayer: CAShapeLayer!
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.clear
// Use UIBezierPath as an easy way to create the CGPath for the layer.
// The path should be the entire circle.
let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: (frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(M_PI * 2.0), clockwise: true)
// Setup the CAShapeLayer with the path, colors, and line width
circleLayer = CAShapeLayer()
circleLayer.path = circlePath.cgPath
circleLayer.fillColor = UIColor.clear.cgColor
circleLayer.strokeColor = UIColor.red.cgColor
circleLayer.lineWidth = 5.0;
// Don't draw the circle initially
circleLayer.strokeEnd = 0.0
// Add the circleLayer to the view's layer's sublayers
layer.addSublayer(circleLayer)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func animateCircle(duration: TimeInterval) {
// We want to animate the strokeEnd property of the circleLayer
let animation = CABasicAnimation(keyPath: "strokeEnd")
// Set the animation duration appropriately
animation.duration = duration
// Animate from 0 (no circle) to 1 (full circle)
animation.fromValue = 0
animation.toValue = 1
// Do a linear animation (i.e The speed of the animation stays the same)
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
// Set the circleLayer's strokeEnd property to 1.0 now so that it's the
// Right value when the animation ends
circleLayer.strokeEnd = 1.0
// Do the actual animation
circleLayer.add(animation, forKey: "animateCircle")
}
함수를 호출 비용 :
func addCircleView() {
let diceRoll = CGFloat(Int(arc4random_uniform(7))*50)
var circleWidth = CGFloat(200)
var circleHeight = circleWidth
// Create a new CircleView
let circleView = CircleView(frame: CGRect(x: diceRoll, y: 0, width: circleWidth, height: circleHeight))
//let test = CircleView(frame: CGRect(x: diceRoll, y: 0, width: circleWidth, height: circleHeight))
view.addSubview(circleView)
// Animate the drawing of the circle over the course of 1 second
circleView.animateCircle(duration: 1.0)
}
Mike의 대답은 훌륭합니다! 또 다른 멋지고 간단한 방법은 setNeedsDisplay ()와 결합 된 drawRect를 사용하는 것입니다. 느슨해 보이지만 말씀드립니다 :-)
-90 °이고 270 °에서 끝나는 상단에서 시작하여 원을 그리려고합니다. 원의 중심은 (centerX, centerY)이며 주어진 반경입니다. CurrentAngle은 minAngle (-90)에서 maxAngle (270)로 이동하는 원 끝점의 현재 각도입니다.
// MARK: Properties
let centerX:CGFloat = 55
let centerY:CGFloat = 55
let radius:CGFloat = 50
var currentAngle:Float = -90
let minAngle:Float = -90
let maxAngle:Float = 270
drawRect에서 원이 표시되는 방식을 지정합니다.
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
let path = CGPathCreateMutable()
CGPathAddArc(path, nil, centerX, centerY, radius, CGFloat(GLKMathDegreesToRadians(minAngle)), CGFloat(GLKMathDegreesToRadians(currentAngle)), false)
CGContextAddPath(context, path)
CGContextSetStrokeColorWithColor(context, UIColor.blueColor().CGColor)
CGContextSetLineWidth(context, 3)
CGContextStrokePath(context)
}
문제는 currentAngle이 변경되지 않으므로 currentAngle = minAngle과 같이 원이 정적이며 표시되지 않습니다.
그런 다음 타이머를 만들고 해당 타이머가 실행될 때마다 currentAngle을 개선합니다. 수업 맨 위에 두 번의 화재 사이에 타이밍을 추가합니다.
let timeBetweenDraw:CFTimeInterval = 0.01
초기화에서 타이머를 추가하십시오.
NSTimer.scheduledTimerWithTimeInterval(timeBetweenDraw, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
타이머가 실행될 때 호출 될 함수를 추가 할 수 있습니다.
func updateTimer() {
if currentAngle < maxAngle {
currentAngle += 1
}
}
슬프게도 앱을 때 다시 그려야하는 시스템을 지정하지 않습니다. 이 setNeedsDisplay ()를 호출하여 수행합니다. 업데이트 된 타이머 기능은 다음과 가변합니다.
func updateTimer() {
if currentAngle < maxAngle {
currentAngle += 1
setNeedsDisplay()
}
}
_ _ _
필요한 모든 코드가 여기에 요약되어 있습니다.
import UIKit
import GLKit
class CircleClosing: UIView {
// MARK: Properties
let centerX:CGFloat = 55
let centerY:CGFloat = 55
let radius:CGFloat = 50
var currentAngle:Float = -90
let timeBetweenDraw:CFTimeInterval = 0.01
// MARK: Init
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup() {
self.backgroundColor = UIColor.clearColor()
NSTimer.scheduledTimerWithTimeInterval(timeBetweenDraw, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
}
// MARK: Drawing
func updateTimer() {
if currentAngle < 270 {
currentAngle += 1
setNeedsDisplay()
}
}
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
let path = CGPathCreateMutable()
CGPathAddArc(path, nil, centerX, centerY, radius, -CGFloat(M_PI/2), CGFloat(GLKMathDegreesToRadians(currentAngle)), false)
CGContextAddPath(context, path)
CGContextSetStrokeColorWithColor(context, UIColor.blueColor().CGColor)
CGContextSetLineWidth(context, 3)
CGContextStrokePath(context)
}
}
속도를 변경 비용 updateTimer 함수 또는이 함수가 호출되는 속도를 수정하면됩니다. 또한 서클이 완료되면 타이머를 무효화하고 싶을 수도 있습니다.
NB : 스토리 보드에 추가 비용을 추가하고 선택하고 Identity Inspector 로 이동 한 다음 Class 로 CircleClosing을 지정 하면 됩니다.
건배! bRo
완료 완료 완료하신 것을 스위프트 3.0에서 수행 한 Mike S의 솔루션과 또 다른 솔루션입니다.
func animateCircleFull(duration: TimeInterval) {
CATransaction.begin()
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 0
animation.toValue = 1
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
circleLayer.strokeEnd = 1.0
CATransaction.setCompletionBlock {
print("animation complete")
}
// Do the actual animation
circleLayer.add(animation, forKey: "animateCircle")
CATransaction.commit()
}
완료 할 때 사용하면 동일한 함수를 재귀 적으로 호출하여 애니메이션을 다시 수행하여 애니메이션을 다시 사용할 수 있습니다. (매우 멋지지 않을 것임) 또는 조건이 계속 될 때까지 계속 연결되는 반전 함수를 누를 수 있습니다. 예 :
func animate(duration: TimeInterval){
self.isAnimating = true
self.animateCircleFull(duration: 1)
}
func endAnimate(){
self.isAnimating = false
}
func animateCircleFull(duration: TimeInterval) {
if self.isAnimating{
CATransaction.begin()
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 0
animation.toValue = 1
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
circleLayer.strokeEnd = 1.0
CATransaction.setCompletionBlock {
self.animateCircleEmpty(duration: duration)
}
// Do the actual animation
circleLayer.add(animation, forKey: "animateCircle")
CATransaction.commit()
}
}
func animateCircleEmpty(duration: TimeInterval){
if self.isAnimating{
CATransaction.begin()
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 1
animation.toValue = 0
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
circleLayer.strokeEnd = 0
CATransaction.setCompletionBlock {
self.animateCircleFull(duration: duration)
}
// Do the actual animation
circleLayer.add(animation, forKey: "animateCircle")
CATransaction.commit()
}
}
더 멋지게 만들기 다음과 같이 애니메이션의 방향을 위해 다음과 같이 있습니다.
func setCircleClockwise(){
let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: (frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(M_PI * 2.0), clockwise: true)
self.circleLayer.removeFromSuperlayer()
self.circleLayer = formatCirle(circlePath: circlePath)
self.layer.addSublayer(self.circleLayer)
}
func setCircleCounterClockwise(){
let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: (frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(M_PI * 2.0), clockwise: false)
self.circleLayer.removeFromSuperlayer()
self.circleLayer = formatCirle(circlePath: circlePath)
self.layer.addSublayer(self.circleLayer)
}
func formatCirle(circlePath: UIBezierPath) -> CAShapeLayer{
let circleShape = CAShapeLayer()
circleShape.path = circlePath.cgPath
circleShape.fillColor = UIColor.clear.cgColor
circleShape.strokeColor = UIColor.red.cgColor
circleShape.lineWidth = 10.0;
circleShape.strokeEnd = 0.0
return circleShape
}
func animate(duration: TimeInterval){
self.isAnimating = true
self.animateCircleFull(duration: 1)
}
func endAnimate(){
self.isAnimating = false
}
func animateCircleFull(duration: TimeInterval) {
if self.isAnimating{
CATransaction.begin()
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 0
animation.toValue = 1
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
circleLayer.strokeEnd = 1.0
CATransaction.setCompletionBlock {
self.setCircleCounterClockwise()
self.animateCircleEmpty(duration: duration)
}
// Do the actual animation
circleLayer.add(animation, forKey: "animateCircle")
CATransaction.commit()
}
}
func animateCircleEmpty(duration: TimeInterval){
if self.isAnimating{
CATransaction.begin()
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 1
animation.toValue = 0
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
circleLayer.strokeEnd = 0
CATransaction.setCompletionBlock {
self.setCircleClockwise()
self.animateCircleFull(duration: duration)
}
// Do the actual animation
circleLayer.add(animation, forKey: "animateCircle")
CATransaction.commit()
}
}
참고 URL : https://stackoverflow.com/questions/26578023/animate-drawing-of-a-circle
'IT' 카테고리의 다른 글
| 캐스트 목록 (0) | 2020.08.21 |
|---|---|
| Node.JS : 요청 모듈을 사용하여 양식 데이터와 함께 헤더를 이용하는 방법 (0) | 2020.08.21 |
| CSS를 사용하여 멋진 화살표를 만드는 방법? (0) | 2020.08.21 |
| node.js, 오류 : 'express'오류를 수 없습니다. (0) | 2020.08.21 |
| 배치 파일 내에서 출력 리디렉션 (0) | 2020.08.21 |