2016-06-03 2 views
5

У меня есть анимация рисования прямоугольника с определенным процентом его.CABasicИзменение чертежа пути не масштабируется при изменении масштаба шкалы супервизора

Для этого я рисую CAShapeLayer:

func drawTheLayer() -> CAShapeLayer { 

    let lineWidth: CGFloat = borderWidth * bounds.size.width/standardSizeWidth 
    let cornerRadiusResized: CGFloat = cornerRadiusRanged * bounds.size.width/standardSizeWidth 
    let insetRect = CGRectInset(bounds, lineWidth/2.0, lineWidth/2.0) 
    let apath = ShapeDraw.createRoundedCornerPath(insetRect, cornerRadius: cornerRadiusResized, percent: percentageRanged) 
    let apathLayer = CAShapeLayer() 

    apathLayer.frame = bounds 
    apathLayer.bounds = insetRect 
    apathLayer.path = apath 
    apathLayer.strokeColor = AppColor.OnColor.CGColor 
    apathLayer.fillColor = nil 
    apathLayer.lineWidth = lineWidth 
    apathLayer.lineJoin = kCALineJoinRound 
    apathLayer.lineCap = kCALineCapRound 
    apathLayer.geometryFlipped = true 

    let flipTransform = CGAffineTransformMakeScale(1, -1) 

    apathLayer.setAffineTransform(flipTransform) 
    return apathLayer 

} 

Чтобы оживить рисунок:

func animateToLevel() { 
    if percentage <= 0 { 
     return 
    } 

    pathLayer?.removeFromSuperlayer() 
    pathLayer?.removeAllAnimations() 

    animating = true 
    let apathLayer = drawTheLayer() 
    layer.addSublayer(apathLayer) 
    let pathAnimation = CABasicAnimation(keyPath: "strokeEnd") 
    pathAnimation.delegate = self 
    pathAnimation.duration = 0.5 
    pathAnimation.fromValue = 0.0 
    pathAnimation.setValue("levelAnimation", forKey: "animationId") 
    apathLayer.addAnimation(pathAnimation, forKey: nil) 

    pathLayer = apathLayer 
} 

нерелевантные для этой анимации, есть еще одна анимация, которая может случиться. Масштабирование прямоугольника superView. Проблема возникает, когда я начинаю рисовать путь, рисуется в соответствии с малым размером superView, а затем, когда кадр становится больше, путь анимации рисования остается таким же, как ожидалось, но есть ли для этого логическое не хакерское решение? Или я должен сделать это в drawRect

Для надтаблицы анимация изменения постоянной высоты UILayout в качестве UIView анимации:

heightOfContainerConstraint.constant = 100 // or 400 when it is expanded 
UIView.animateWithDuration(animated ? animationDuration : 0) { 
    self.view.layoutIfNeeded() 
} 

код создания закругленный угол:

import UIKit 

class ShapeDraw { 

static func createRoundedCornerPath(rect: CGRect, cornerRadius: CGFloat, percent: CGFloat) -> CGMutablePathRef { 

    let piNumber: CGFloat = CGFloat(M_PI) 

    // get the 4 corners of the rect 
    let topLeft = CGPointMake(rect.origin.x, rect.origin.y) 
    let topRight = CGPointMake(rect.origin.x + rect.size.width, rect.origin.y) 
    let bottomRight = CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height) 
    let bottomLeft = CGPointMake(rect.origin.x, rect.origin.y + rect.size.height) 

    // Set 4 corner arc starting angles 
    let startAngleTopRight: CGFloat = 3 * piNumber/2 
    let startAngleBottomRight: CGFloat = 0 
    let startAngleBottomLeft: CGFloat = piNumber/2 
    let startAngleTopLeft: CGFloat = piNumber 

    let slices = (CGRectGetWidth(rect)/cornerRadius) * 4 
    let partValue: CGFloat = 100/slices // %100 is total -> 1 piece is 100/16 percent 

    let wayToGoLine = CGRectGetWidth(rect) - 2 * cornerRadius 
    let linePartValue = partValue * (slices/4 - 2) 

    var remainingPercent: CGFloat = percent 
    let path = CGPathCreateMutable() 
    // move to top left 
    CGPathMoveToPoint(path, nil, topRight.x/2, topRight.y) 

    // add top right half line 
    remainingPercent = addLine(path, x: topRight.x/2 + (wayToGoLine/2 * getConstantForThis(remainingPercent, partValue: linePartValue/2)), y: topRight.y, remainingPercent: remainingPercent, currentPartPercent: linePartValue/2) 

    // add top right curve 
    let endingAngleTopRight = endingAngleForThis(startAngleTopRight, remainingPercent: remainingPercent, partValue: partValue) 
    remainingPercent = addArc(path, x: topRight.x - cornerRadius, y: topRight.y + cornerRadius, radius: cornerRadius, startAngle: startAngleTopRight, endingAngle: endingAngleTopRight, remainingPercent: remainingPercent, currentPartPercent: partValue * 2) 

    // add right line 
    remainingPercent = addLine(path, x: bottomRight.x, y: topRight.y + cornerRadius + (wayToGoLine * getConstantForThis(remainingPercent, partValue: linePartValue)), remainingPercent: remainingPercent, currentPartPercent: linePartValue) 

    // add bottom right curve 
    let endingAngleBottomRight = endingAngleForThis(startAngleBottomRight, remainingPercent: remainingPercent, partValue: partValue) 
    remainingPercent = addArc(path, x: bottomRight.x - cornerRadius, y: bottomRight.y - cornerRadius, radius: cornerRadius, startAngle: startAngleBottomRight, endingAngle: endingAngleBottomRight, remainingPercent: remainingPercent, currentPartPercent: partValue * 2) 

    // add bottom line 
    remainingPercent = addLine(path, x: bottomRight.x - cornerRadius - (wayToGoLine * getConstantForThis(remainingPercent, partValue: linePartValue)), y: bottomLeft.y, remainingPercent: remainingPercent, currentPartPercent: linePartValue) 

    // add bottom left curve 
    let endingAngleBottomLeft = endingAngleForThis(startAngleBottomLeft, remainingPercent: remainingPercent, partValue: partValue) 
    remainingPercent = addArc(path, x: bottomLeft.x + cornerRadius, y: bottomLeft.y - cornerRadius, radius: cornerRadius, startAngle: startAngleBottomLeft, endingAngle: endingAngleBottomLeft, remainingPercent: remainingPercent, currentPartPercent: partValue * 2) 

    // add left line 
    remainingPercent = addLine(path, x: topLeft.x, y: bottomLeft.y - cornerRadius - (wayToGoLine * getConstantForThis(remainingPercent, partValue: linePartValue)), remainingPercent: remainingPercent, currentPartPercent: linePartValue) 

    // add top left curve 
    let endingAngleTopLeft = endingAngleForThis(startAngleTopLeft, remainingPercent: remainingPercent, partValue: partValue) 
    remainingPercent = addArc(path, x: topLeft.x + cornerRadius, y: topLeft.y + cornerRadius, radius: cornerRadius, startAngle: startAngleTopLeft, endingAngle: endingAngleTopLeft, remainingPercent: remainingPercent, currentPartPercent: partValue * 2) 

    // add top left half line 
    remainingPercent = addLine(path, x: topLeft.x + cornerRadius + (wayToGoLine/2 * getConstantForThis(remainingPercent, partValue: linePartValue/2)), y: topRight.y, remainingPercent: remainingPercent, currentPartPercent: linePartValue/2) 

    return path 
} 

static func endingAngleForThis(startAngle: CGFloat, remainingPercent: CGFloat, partValue: CGFloat) -> CGFloat { 
    return startAngle + (CGFloat(M_PI) * getConstantForThis(remainingPercent, partValue: partValue * 2)/2) 
} 

static func getConstantForThis(percent: CGFloat, partValue: CGFloat) -> CGFloat { 
    let percentConstant = percent - partValue > 0 ? 1 : percent/partValue 
    return percentConstant 
} 

static func addLine(path: CGMutablePath?, x: CGFloat, y: CGFloat, remainingPercent: CGFloat, currentPartPercent: CGFloat) -> CGFloat { 
    if remainingPercent > 0 { 
     CGPathAddLineToPoint(path, nil, x, y) 
     return remainingPercent - currentPartPercent 
    } 
    return 0 
} 

static func addArc(path: CGMutablePath?, x: CGFloat, y: CGFloat, radius: CGFloat, startAngle: CGFloat, endingAngle: CGFloat, remainingPercent: CGFloat, currentPartPercent: CGFloat) -> CGFloat { 
    if remainingPercent > 0 { 

     CGPathAddArc(path, nil, x, y, radius, startAngle, endingAngle, false) 
     return remainingPercent - currentPartPercent 
    } 
    return 0 
} 

} 
+0

@AlessandroOrnano я добавил код, но я не думаю, что это необходимо, чтобы один возвращается в CGMutablePathRef и сама функция не имеет большого значения. –

+0

Я добавил экран gif также, надеюсь, что кто-то ответит сейчас: D @AlessandroOrnano –

+0

Хорошо, это ясный вопрос. Я не знаю, правильно ли я понимаю, но я попытался дать ответ. –

ответ

1

По существу , у нас есть две анимации:

  • следить за правилом угол наклона траектории к определенному проценту
  • масштабирования прямоугольника надтаблицы или анимации границ, которые изменяют

Цель состоит в том: эти анимации должны работать вместе в то же самое время (группы), а не последовательно ,

Приведенный ниже код является только примером и не следуют точные свойства или пользовательские задачи, я хочу объяснить, что я буду делать в этом случае:

// follow the rectangle path 
    let pathAnimation = CABasicAnimation(keyPath: "strokeEnd") 
    let cornerRadiusResized: CGFloat = cornerRadiusRanged * bounds.size.width/standardSizeWidth 
    let apath = ShapeDraw.createRoundedCornerPath(insetRect, cornerRadius: cornerRadiusResized, percent: percentageRanged) 
    pathAnimation.toValue = apath 

    // scaling of the rectangle superview 
    let newBounds = CGRectMake(self.view.bounds.origin.x, self.view.bounds.origin.y, self.view.bounds.width, self.view.bounds.height) 
    let boundsAnimation = CABasicAnimation(keyPath: "bounds") 
    boundsAnimation.toValue = NSValue(CGRect:newBounds) 

    // The group 
    var theGroup: CAAnimationGroup = CAAnimationGroup() 
    theGroup.animations = [pathAnimation,boundsAnimation] 
    theGroup.duration = 2.0 
    theGroup.repeatCount = 1 
    theGroup.fillMode = kCAFillModeForwards 
    apathLayer.addAnimation(theGroup, forKey: "theGroup") 

EDIT:

Если вам нужна третья анимация, как вы говорите в своих комментариях, чтобы изменить UIButton измерение можно также добавить:

var buttonAnimation:CABasicAnimation = CABasicAnimation(keyPath: "transform.scale") 
pulseAnimation.duration = 2.0 
pulseAnimation.toValue = NSNumber(float: 0.5) 
pulseAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 

и добавить его в массив:

theGroup.animations = [pathAnimation,buttonAnimation, boundsAnimation] 
+0

Я пробовал это раньше, но путь, который я создаю с помощью createRoundedCornerPath, не масштабируется, пока масштабируется вид. Когда я использую dispatch_after (delayTime, dispatch_get_main_queue()) {анимация рисования начинается после масштабирования. –

+0

Обе анимации должны запускаться в основной очереди. Они запускаются последовательно или это просто проблема длительности (разные NSTimeInterval)?Вы пытались изменить оба параметра продолжительности, например pathAnimation более длинный, чем boundAnimation? –

+0

На самом деле есть 3 анимации 1. рисование дорожки внутри кнопки, 2. масштабирование кнопки 3. масштабирование контейнера View. и если я устанавливаю основную очередь анимации, то первая 3 работает, чем 1 и 2, конечно, работает одновременно, поскольку это групповая анимация. все они работают одинаково, я уже проверил, что продолжительность 10,0 секунд для всех анимаций будет лучше. –

Смежные вопросы