একটি বৃত্তের অঙ্কন অ্যানিমেট করুন


105

আমি একটি বৃত্তের অঙ্কন সঞ্চার করার জন্য একটি উপায় খুঁজছি। আমি চেনাশোনাটি তৈরি করতে সক্ষম হয়েছি তবে এটি সমস্ত একসাথে আঁকতে পারে।

এখানে আমার 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 সেকেন্ডেরও বেশি অ্যানিমেট করার কোনও উপায় আছে?

উদাহরণস্বরূপ, অ্যানিমেশনের মধ্য দিয়ে কিছু অংশে এটি এই চিত্রের নীল লাইনের মতো দেখায়:

আংশিক অ্যানিমেশন


আমি যখন উপরের ক্লাসটি ব্যবহার করি, তখন বৃত্তটি সম্পূর্ণরূপে ভরাট হয় না, এটির একটি রিং সার্কেল (ডোনোট খুঁজছেন) কোনও ধারণা কেন?
এস গ্রিন

আপনি এই উত্তরটি চেষ্টা করতে পারেন , যা এটি করার চেষ্টা করা অন্যটি
আলী এ। জলিল

উত্তর:


201

এটি করার সবচেয়ে সহজ উপায়টি হল আপনার জন্য বেশিরভাগ কাজ করার জন্য মূল অ্যানিমেশনের শক্তিটি ব্যবহার করা। এটি করতে, আমাদের আপনার বৃত্তের অঙ্কন কোডটি আপনার drawRectফাংশন থেকে a এ স্থানান্তর করতে হবে CAShapeLayer। তারপর, আমরা একটি ব্যবহার করতে পারেন CABasicAnimationঅ্যানিমেট করতে CAShapeLayerএর strokeEndথেকে সম্পত্তি 0.0থেকে 1.0strokeEndএখানে যাদুটির একটি বড় অংশ; ডক্স থেকে:

স্ট্রোকস্টার্ট বৈশিষ্ট্যের সাথে একত্রিত হয়ে এই সম্পত্তি স্ট্রোকের পথে সাবগিওন সংজ্ঞায়িত করে। এই সম্পত্তির মান স্ট্রোক স্টার্ট সম্পত্তি সূচনা পয়েন্টটি সংজ্ঞায়িত করার সময় যেদিকে স্ট্রোকিং শেষ করতে হবে সেই পথের সাথে আপেক্ষিক বিন্দুটি নির্দেশ করে। ০.০ এর একটি মান পাথের প্রারম্ভিক উপস্থাপন করে এবং ০.০ এর মান পাথের প্রান্তটি উপস্থাপন করে। মধ্যবর্তী মানগুলি পথের দৈর্ঘ্য বরাবর রৈখিকভাবে ব্যাখ্যা করা হয়।

যদি আমরা সেট করে 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(Double.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: CAMediaTimingFunctionName.linear)

    // 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)
}

যেগুলি একসাথে রাখা হয়েছে তাদের এই জাতীয় চেহারাটি দেখতে হবে:

বৃত্ত অ্যানিমেশন

দ্রষ্টব্য: এটি এর মতো পুনরাবৃত্তি করবে না, এটি অ্যানিমেট করার পরে এটি একটি পুরো বৃত্তে থাকবে।


2
@ মাইকস আপনার উত্তরটি দুর্দান্ত! এটি কীভাবে কোনও এসকেসিন / এসকেভিউ / এসকেএসপ্রিটনোডের মধ্যে স্প্রিটকিট-এ প্রয়োগ করবেন সে সম্পর্কে আপনার কোনও ধারণা আছে? SKShapeNode অবজেক্টটি রয়েছে তবে এটি খারাপ (বাগগুলি) হিসাবে বিবেচিত হয় এবং সমর্থন করে নাstrokeEnd
কালজেম

এটি খুঁজে self.view?.layer.addSublayer(circleLayer)
পেয়েছে

14
@ কলিনডনন কেবলমাত্র এর startAngle:endAngle:পরামিতি পরিবর্তন করুন UIBezierPath03 অবস্থান, সুতরাং 12 অবস্থানটি 90 that এর চেয়ে কম হবে, যা রেডিয়ানগুলিতে-। / 2 হবে। সুতরাং, পরামিতি হবে startAngle: CGFloat(-M_PI_2), endAngle: CGFloat((M_PI * 2.0) - M_PI_2)
মাইক এস

2
@ মাইকস আমরা কীভাবে এটিকে একটি লুপে প্রয়োগ করতে পারি? - অবিচ্ছিন্নভাবে নিজের উপরে টানা না
রাম্বোসা

2
চেনাশোনাটি শুরু হতে এবং শেষ হতে 12 0 ঘন্টা অবধি, startAngle: (0 - (Double.pi / 2)) + 0.00001এবং endAngle: 0 - (Double.pi / 2)। যদি startAngleএবং endAngleএকই থাকে তবে চেনাশোনাটি টানা হবে না, এজন্য আপনি খুব খুব ছোট একটি অফসেটটি বিয়োগ করেনstartAngle
সিলেয়ান ডি অ্যাশ

25

মাইকস উত্তর সুইফট 3.0 এর জন্য আপডেট হয়েছে

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)
}

2
M_PIঅবচয় করা হয়েছে - CGFloat.piপরিবর্তে ব্যবহার করুন।
টম

অ্যাড সার্কেলভিউ ফাংশনে "অমীমাংসিত শনাক্তকারী 'সার্কেলভিউ' ব্যবহারের ত্রুটি পাওয়া
ব্যবহারকারীদেব

16

মাইকের উত্তর দারুণ! এটি করার আরেকটি দুর্দান্ত এবং সহজ উপায় হ'ল সেটরেক্টস ডিসপ্লে () এর সাথে মিলিত ড্রআরেক্ট ব্যবহার করুন। এটি অচল মনে হচ্ছে তবে এটি নয় :-) এখানে চিত্র বর্ণনা লিখুন

আমরা শীর্ষ থেকে শুরু করে একটি বৃত্ত আঁকতে চাই, যা -90 ° এবং শেষ হয় 270 ° এ ° প্রদত্ত ব্যাসার্ধ সহ বৃত্তের কেন্দ্র (সেন্টার এক্স, সেন্টারওয়াই) Y কারেন্টএঙ্গল হল বৃত্তের শেষ-পয়েন্টের বর্তমান কোণ, মিনএঙ্গেল (-90) থেকে সর্বোচ্চআঙ্গেল (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

ড্রয়ারেক্টে, আমরা নির্দিষ্ট করেছিলাম যে বৃত্তটি কীভাবে প্রদর্শিত হবে:

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)
}

সমস্যাটি এখনই এটি হ'ল কারেন্টএঙ্গল যেমন পরিবর্তন হচ্ছে না তেমনি বৃত্তটি স্থিতিশীল, এমনকি কারেন্টএঙ্গল = মিনিআঙ্গল হিসাবেও দেখাবে না।

তারপরে আমরা একটি টাইমার তৈরি করি এবং যখনই that টাইমার ফায়ার হয় তখন আমরা কারেন্টএঙ্গেল বৃদ্ধি করি। আপনার শ্রেণীর শীর্ষে, দুটি আগুনের মধ্যে সময় যুক্ত করুন:

let timeBetweenDraw:CFTimeInterval = 0.01

আপনার উদ্যোগে, টাইমার যুক্ত করুন:

NSTimer.scheduledTimerWithTimeInterval(timeBetweenDraw, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)

টাইমার যখন জ্বলতে থাকে তখন আমরা সেই ফাংশনটি যুক্ত করতে পারি:

func updateTimer() {

    if currentAngle < maxAngle {
        currentAngle += 1
    }
}

দুঃখের বিষয়, অ্যাপটি চলাকালীন, কিছুই প্রদর্শন করে না কারণ আমরা সিস্টেমটি এটি আবার আঁকতে হবে তা নির্দিষ্ট করে নি। এটি সেটনিডসডিসপ্লে () কল করে সম্পন্ন হয়। এখানে আপডেট করা টাইমার ফাংশনটি রয়েছে:

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)
    }
}

আপনি যদি গতি পরিবর্তন করতে চান তবে কেবল আপডেটটাইমার ফাংশনটি পরিবর্তন করুন বা এই ফাংশনটি যে হারে ডাকা হয় সেটিকেই পরিবর্তন করুন। এছাড়াও, আপনি বৃত্তটি সম্পূর্ণ হয়ে গেলে টাইমারকে অবৈধ করতে চাইতে পারেন, যা আমি করতে ভুলে গিয়েছিলাম :-)

নোট: আপনার স্টোরিবোর্ডে চেনাশোনাটি যুক্ত করতে, কেবল একটি দর্শন যুক্ত করুন, এটি নির্বাচন করুন, এটির পরিচয় পরিদর্শক এবং শ্রেণি হিসাবে , সার্কেলক্লোজিং নির্দিষ্ট করুন

চিয়ার্স! ভাই


অনেক ধন্যবাদ! আপনি কীভাবে এটি কোনও এসকেসিনে রূপায়ণ করবেন জানেন? আমি কোন উপায় খুঁজে পাই না।
অস্কার

আরে, আমি এটি সন্ধান করব, কারণ আমি এখনও এসকে নিয়ে দক্ষ নই :-)
বিআরও

13

আপনি যদি একটি পরিসমাপ্তি হ্যান্ডলার চান, এটি সুইচ ৩.০-এ মাইক এস এর অনুরূপ আর একটি সমাধান

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()
}

সমাপ্তি হ্যান্ডলারটির সাহায্যে আপনি অ্যানিমেশনটি পুনরায় পুনরায় অ্যানিমেশনটি করার জন্য একই ক্রিয়াকলাপটি কল করে আবার অ্যানিমেশনটি চালাতে পারেন (যা খুব সুন্দর দেখায় না), অথবা আপনার কোনও বিপরীত ফাংশন থাকতে পারে যা শর্ত পূরণ না হওয়া অবধি ধারাবাহিকভাবে শৃঙ্খলিত থাকবে will , উদাহরণ স্বরূপ:

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()
    }
}

1

কেবলমাত্র আপনিই একটি সাবক্লাস করতে পারবেন না UIView, আপনি কিছুটা গভীরতর, সাবক্লাস এও যেতে পারেনCALayer

অন্য কথায়, কোরএনিমেশনের স্ট্রোকএন্ড ঠিক আছে। CALayer এর অঙ্ক কল করতে (সিটিএক্সে :) প্রায়শই ঠিক আছে

এবং বৃত্তাকার লাইন ক্যাপ দুর্দান্ত

111

মূল বিষয় হ'ল ক্যালায়ারের পদ্ধতি ওভাররাইড করা action(forKey:)

ক্রিয়াগুলি একটি স্তরের জন্য গতিশীল আচরণগুলি সংজ্ঞায়িত করে। উদাহরণস্বরূপ, কোনও স্তরের অ্যানিমেটেবল বৈশিষ্ট্যগুলিতে প্রকৃত অ্যানিমেশনগুলি শুরু করতে সাধারণত একই ক্রিয়া অবজেক্ট থাকে। যখন সেই সম্পত্তিটি পরিবর্তন হয়, স্তরটি সম্পত্তির নামের সাথে যুক্ত ক্রিয়া অবজেক্টের সন্ধান করে এবং তা সম্পাদন করে।

CAShapeLayer এর অভ্যন্তরীণ সাবক্লাস

/**
 The internal subclass for CAShapeLayer.
 This is the class that handles all the drawing and animation.
 This class is not interacted with, instead
 properties are set in UICircularRing

 */
class UICircularRingLayer: CAShapeLayer {

    // MARK: Properties
    @NSManaged var val: CGFloat

    let ringWidth: CGFloat = 20
    let startAngle = CGFloat(-90).rads

    // MARK: Init

    override init() {
        super.init()
    }

    override init(layer: Any) {
        guard let layer = layer as? UICircularRingLayer else { fatalError("unable to copy layer") }

        super.init(layer: layer)
    }

    required init?(coder aDecoder: NSCoder) { return nil }

    // MARK: Draw

    /**
     Override for custom drawing.
     Draws the ring 
     */
    override func draw(in ctx: CGContext) {
        super.draw(in: ctx)
        UIGraphicsPushContext(ctx)
        // Draw the rings
        drawRing(in: ctx)
        UIGraphicsPopContext()
    }

    // MARK: Animation methods

    /**
     Watches for changes in the val property, and setNeedsDisplay accordingly
     */
    override class func needsDisplay(forKey key: String) -> Bool {
        if key == "val" {
            return true
        } else {
            return super.needsDisplay(forKey: key)
        }
    }

    /**
     Creates animation when val property is changed
     */
    override func action(forKey event: String) -> CAAction? {
        if event == "val"{
            let animation = CABasicAnimation(keyPath: "val")
            animation.fromValue = presentation()?.value(forKey: "val")
            animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
            animation.duration = 2
            return animation
        } else {
            return super.action(forKey: event)
        }
    }


    /**
     Draws the ring for the view.
     Sets path properties according to how the user has decided to customize the view.
     */
    private func drawRing(in ctx: CGContext) {

        let center: CGPoint = CGPoint(x: bounds.midX, y: bounds.midY)

        let radiusIn: CGFloat = (min(bounds.width, bounds.height) - ringWidth)/2
        // Start drawing
        let innerPath: UIBezierPath = UIBezierPath(arcCenter: center,
                                                   radius: radiusIn,
                                                   startAngle: startAngle,
                                                   endAngle: toEndAngle,
                                                   clockwise: true)

        // Draw path
        ctx.setLineWidth(ringWidth)
        ctx.setLineJoin(.round)
        ctx.setLineCap(CGLineCap.round)
        ctx.setStrokeColor(UIColor.red.cgColor)
        ctx.addPath(innerPath.cgPath)
        ctx.drawPath(using: .stroke)

    }


    var toEndAngle: CGFloat {
        return (val * 360.0).rads + startAngle
    }


}

সহায়ক পদ্ধতি

/**
 A private extension to CGFloat in order to provide simple
 conversion from degrees to radians, used when drawing the rings.
 */
extension CGFloat {
    var rads: CGFloat { return self * CGFloat.pi / 180 }
}

অভ্যন্তরীণ কাস্টম ক্যালায়ার সহ একটি ইউআইভিউ সাবক্লাস ব্যবহার করুন

@IBDesignable open class UICircularRing: UIView {

    /**
     Set the ring layer to the default layer, casted as custom layer
     */
    var ringLayer: UICircularRingLayer {
        return layer as! UICircularRingLayer
    }

    /**
     Overrides the default layer with the custom UICircularRingLayer class
     */
    override open class var layerClass: AnyClass {
        return UICircularRingLayer.self
    }

    /**
     Override public init to setup() the layer and view
     */
    override public init(frame: CGRect) {
        super.init(frame: frame)
        // Call the internal initializer
        setup()
    }

    /**
     Override public init to setup() the layer and view
     */
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        // Call the internal initializer
        setup()
    }

    /**
     This method initializes the custom CALayer to the default values
     */
    func setup(){
        // Helps with pixelation and blurriness on retina devices
        ringLayer.contentsScale = UIScreen.main.scale
        ringLayer.shouldRasterize = true
        ringLayer.rasterizationScale = UIScreen.main.scale * 2
        ringLayer.masksToBounds = false

        backgroundColor = UIColor.clear
        ringLayer.backgroundColor = UIColor.clear.cgColor
        ringLayer.val = 0
    }


    func startAnimation() {
        ringLayer.val = 1
    }
}

ব্যবহার:

class ViewController: UIViewController {

    let progressRing = UICircularRing(frame: CGRect(x: 100, y: 100, width: 250, height: 250))


    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(progressRing)
    }

    @IBAction func animate(_ sender: UIButton) {

        progressRing.startAnimation()

    }


}

কোণ সেট আপ করার জন্য একটি সূচক চিত্র সহ

এখানে চিত্র বর্ণনা লিখুন


0

সুইট 5 এর জন্য @ মাইক এস এর উত্তর আপডেট করা

জন্য কাজ করে frame manually, storyboard setup,autolayout setup

class CircleView: UIView {

    let circleLayer: CAShapeLayer = {
        // Setup the CAShapeLayer with the path, colors, and line width
        let circle = CAShapeLayer()
        circle.fillColor = UIColor.clear.cgColor
        circle.strokeColor = UIColor.red.cgColor
        circle.lineWidth = 5.0

        // Don't draw the circle initially
        circle.strokeEnd = 0.0
        return circle
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }

    func setup(){
        backgroundColor = UIColor.clear

        // Add the circleLayer to the view's layer's sublayers
        layer.addSublayer(circleLayer)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        // 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(Double.pi * 2.0), clockwise: true)

        circleLayer.path = circlePath.cgPath
    }

    func animateCircle(duration t: TimeInterval) {
        // We want to animate the strokeEnd property of the circleLayer
        let animation = CABasicAnimation(keyPath: "strokeEnd")

        // Set the animation duration appropriately
        animation.duration = t

        // 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: CAMediaTimingFunctionName.linear)

        // 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")
    }
}

ব্যবহার:

নমুনা কোড frame manually, storyboard setup,autolayout setup

class ViewController: UIViewController {

    @IBOutlet weak var circleV: CircleView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func animateFrame(_ sender: UIButton) {


        let diceRoll = CGFloat(Int(arc4random_uniform(7))*30)
        let circleEdge = CGFloat(200)

        // Create a new CircleView
        let circleView = CircleView(frame: CGRect(x: 50, y: diceRoll, width: circleEdge, height: circleEdge))

        view.addSubview(circleView)

        // Animate the drawing of the circle over the course of 1 second
        circleView.animateCircle(duration: 1.0)


    }

    @IBAction func animateAutolayout(_ sender: UIButton) {

        let circleView = CircleView(frame: CGRect.zero)
        circleView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(circleView)
        circleView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        circleView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        circleView.widthAnchor.constraint(equalToConstant: 250).isActive = true
        circleView.heightAnchor.constraint(equalToConstant: 250).isActive = true
        // Animate the drawing of the circle over the course of 1 second
        circleView.animateCircle(duration: 1.0)
    }

    @IBAction func animateStoryboard(_ sender: UIButton) {
        // Animate the drawing of the circle over the course of 1 second
        circleV.animateCircle(duration: 1.0)

    }

}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.