jjzjj

swift - 当 superView 的比例变化时,CABasicAnimation 绘制路径不会缩放

coder 2023-09-06 原文

我有一个将矩形绘制到特定百分比的动画。

为此,我正在绘制一个 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 绘制的,然后当框架变大时,绘制动画的路径保持不变,这是预期的,但是是否有一个合乎逻辑的非 hacky 解决方案?还是我必须在 drawRect

中完成

对于 super View ,动画正在改变 UIView 动画中的 UILayout 高度常量:

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
}

}

最佳答案

本质上,我们有两个动画:

  • 按照矩形路径到特定百分比
  • 缩放矩形 super View 或变化的边界动画

目标是:这些动画必须同时(一组)一起工作,而不是按顺序工作。

下面的代码只是一个例子,并没有遵循确切的属性或自定义目标,我想解释一下在这种情况下我会做什么:

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

编辑:

如果您需要第三个动画,正如您在评论中所说,要更改 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]

关于swift - 当 superView 的比例变化时,CABasicAnimation 绘制路径不会缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37611826/

有关swift - 当 superView 的比例变化时,CABasicAnimation 绘制路径不会缩放的更多相关文章

  1. ruby - Highline 询问方法不会使用同一行 - 2

    设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案

  2. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  3. ruby-on-rails - 启用 Rack::Deflater 时 ETag 发生变化 - 2

    在启用Rack::Deflater来gzip我的响应主体时偶然发现了一些奇怪的东西。也许我遗漏了一些东西,但启用此功能后,响应被压缩,但是资源的ETag在每个请求上都会发生变化。这会强制应用程序每次都响应,而不是发送304。这在没有启用Rack::Deflater的情况下有效,我已经验证页面源没有改变。我正在运行一个使用thin作为Web服务器的Rails应用程序。Gemfile.lockhttps://gist.github.com/2510816有没有什么方法可以让我从Rack中间件获得更多的输出,这样我就可以看到发生了什么?提前致谢。 最佳答案

  4. ruby-on-rails - Rails - 使用/自定义 URL : '/dashboard' 指定根路径 - 2

    如何使此根路径转到:“/dashboard”而不仅仅是http://example.com?root:to=>'dashboard#index',:constraints=>lambda{|req|!req.session[:user_id].blank?} 最佳答案 您可以通过以下方式实现:root:to=>redirect('/dashboard')match'/dashboard',:to=>"dashboard#index",:constraints=>lambda{|req|!req.session[:user_id].b

  5. ruby - 如何根据长度将路径数组转换为嵌套数组或散列 - 2

    我需要根据字符串路径的长度将字符串路径数组转换为符号、哈希和数组的数组给定以下数组:array=["info","services","about/company","about/history/part1","about/history/part2"]我想生成以下输出,对不同级别进行分组,根据级别的结构混合使用符号和对象。产生以下输出:[:info,:services,about:[:company,history:[:part1,:part2]]]#altsyntax[:info,:services,{:about=>[:company,{:history=>[:part1,:pa

  6. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  7. ruby-on-rails - 如何播种图像的路径? - 2

    Organization和Image具有一对一的关系。Image有一个名为filename的列,它存储文件的路径。我在Assets管道中包含这样一个文件:app/assets/other/image.jpg。播种时如何包含此文件的路径?我已经在我的种子文件中尝试过:@organization=...@organization.image.create!(filename:File.open('app/assets/other/image.jpg'))#Ialsotried:#@organization.image.create!(filename:'app/assets/other/i

  8. ruby-on-rails - prawnto 显示新页面时不会中断的表格 - 2

    我有可变数量的表格和可变数量的行,我想让它们一个接一个地显示,但如果表格不适合当前页面,请将其放在下一页,然后继续。我已将表格放入事务中,以便我可以回滚然后打印它(如果高度适合当前页面),但我如何获得表格高度?我现在有这段代码pdf.transactiondopdf.table@data,:font_size=>12,:border_style=>:grid,:horizontal_padding=>10,:vertical_padding=>3,:border_width=>2,:position=>:left,:row_colors=>["FFFFFF","DDDDDD"]pdf.

  9. ruby-on-rails - ruby 中两个哈希之间的变化 - 2

    我有两个具有以下格式的哈希mydetails[x['Id']]=x['Amount']这将包含如下数据hash1={"A"=>"0","B"=>"1","C"=>"0","F"=>"1"}hash2={"A"=>"0","B"=>"3","C"=>"0","E"=>"1"}我期待这样的输出:Differencesinhash:"B,F,E"非常感谢任何帮助。 最佳答案 这个解决方案可能更容易理解:(hash1.keys|hash2.keys).select{|key|hash1[key]!=hash2[key]}Array#|返回2

  10. Ruby 和指南针路径与 yeoman 项目 - 2

    我安装了ruby​​、yeoman,当我运行我的项目时,出现了这个错误:Warning:Running"compass:dist"(compass)taskWarning:YouneedtohaveRubyandCompassinstalledthistasktowork.Moreinfo:https://github.com/gruUse--forcetocontinue.Use--forcetocontinue.我有进入可变session目标的路径,但它不起作用。谁能帮帮我? 最佳答案 我必须运行这个:geminstallcom

随机推荐