【问题标题】:UIBezierPath doesn't work on a some framesUIBezierPath 在某些帧上不起作用
【发布时间】:2018-07-08 07:18:43
【问题描述】:

我正在尝试使用 UIView 子类运行此代码:

bgShapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: self.frame.midX , y: self.frame.midY), radius:
            100, startAngle: -90.degreesToRadians, endAngle: 270.degreesToRadians, clockwise: true).cgPath
bgShapeLayer.strokeColor = UIColor.white.cgColor
bgShapeLayer.fillColor = UIColor.clear.cgColor
bgShapeLayer.lineWidth = 15
self.layer.addSublayer(bgShapeLayer)

由于某种原因,此代码在我使用 375x667 帧时有效(显示某些内容),但在我使用其他帧(例如 120x120 或 74x74)时无效。也许形状超出了界限?但是为什么呢?

如果有人能找出问题,如果你能告诉我,我将不胜感激。

已回答的完整代码

    let timeLeftShapeLayer = CAShapeLayer()
    let bgShapeLayer = CAShapeLayer()
    var timeLeft: TimeInterval = 3783
    var endTime: Date?
    var timeLabel =  UILabel()
    var timer = Timer()
    let strokeIt = CABasicAnimation(keyPath: "strokeEnd")

    func drawBgShape() {
        bgShapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: self.frame.midX , y: self.frame.midY), radius:
            min(frame.width/2, frame.height/2), startAngle: -90.degreesToRadians, endAngle: 270.degreesToRadians, clockwise: true).cgPath
        bgShapeLayer.strokeColor = UIColor.white.cgColor
        bgShapeLayer.fillColor = UIColor.clear.cgColor
        bgShapeLayer.lineWidth = 15
        self.layer.addSublayer(bgShapeLayer)
    }
    func drawTimeLeftShape() {
        timeLeftShapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: self.frame.midX , y: self.frame.midY), radius:
            min(frame.width/2, frame.height/2), startAngle: -90.degreesToRadians, endAngle: 270.degreesToRadians, clockwise: true).cgPath
        timeLeftShapeLayer.strokeColor = UIColor.red.cgColor
        timeLeftShapeLayer.fillColor = UIColor.clear.cgColor
        timeLeftShapeLayer.lineWidth = 15
        self.layer.addSublayer(timeLeftShapeLayer)
    }
    func addTimeLabel() {
        timeLabel = UILabel(frame: CGRect(x: self.frame.midX-50 ,y: self.frame.midY-25, width: 100, height: 50))
        timeLabel.textAlignment = .center
        timeLabel.text = timeLeft.time
        self.addSubview(timeLabel)
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        self.backgroundColor = UIColor(white: 0.94, alpha: 1.0)
        drawBgShape()
        drawTimeLeftShape()
        addTimeLabel()
        // here you define the fromValue, toValue and duration of your animation
        strokeIt.fromValue = 0
        strokeIt.toValue = 1
        strokeIt.duration = 60
        // add the animation to your timeLeftShapeLayer
        timeLeftShapeLayer.add(strokeIt, forKey: nil)
        // define the future end time by adding the timeLeft to now Date()
        endTime = Date().addingTimeInterval(timeLeft)
        timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
    }

    @objc func updateTime() {
        if timeLeft > 0 {
            timeLeft = endTime?.timeIntervalSinceNow ?? 0
            timeLabel.text = timeLeft.time
        } else {
            timeLabel.text = "00:00"
            timer.invalidate()
        }
    }

谢谢!

【问题讨论】:

  • 你换框架的时候也换radius吗?否则,您的直径(半径的两倍)将大于框架。

标签: ios iphone swift cocoa-touch uibezierpath


【解决方案1】:

因为半径100至少需要200的高度

所以改成这个

 let radius = min(frame.width/2, frame.height/2);

编辑这个对我有用

    let df = qw()

    df.frame = CGRect.init(x: 0, y: 0, width: 100, height: 100)

    self.view.addSubview(df)

导入 UIKit

class qw: UIView {


    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code


        self.drawTimeLeftShape()
    }



    let timeLeftShapeLayer = CAShapeLayer()
    let bgShapeLayer = CAShapeLayer()
    var timeLeft: TimeInterval = 3783
    var endTime: Date?
    var timeLabel =  UILabel()
    var timer = Timer()
    let strokeIt = CABasicAnimation(keyPath: "strokeEnd")

    func drawBgShape() {
        bgShapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: self.frame.midX , y: self.frame.midY), radius:
            min(frame.width/2, frame.height/2), startAngle: -90.degreesToRadians, endAngle: 270.degreesToRadians, clockwise: true).cgPath
        bgShapeLayer.strokeColor = UIColor.white.cgColor
        bgShapeLayer.fillColor = UIColor.clear.cgColor
        bgShapeLayer.lineWidth = 15
        self.layer.addSublayer(bgShapeLayer)
    }
    func drawTimeLeftShape() {
        timeLeftShapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: self.frame.midX , y: self.frame.midY), radius:
            min(frame.width/2, frame.height/2), startAngle: -90.degreesToRadians, endAngle: 270.degreesToRadians, clockwise: true).cgPath
        timeLeftShapeLayer.strokeColor = UIColor.red.cgColor
        timeLeftShapeLayer.fillColor = UIColor.clear.cgColor
        timeLeftShapeLayer.lineWidth = 15
        self.layer.addSublayer(timeLeftShapeLayer)
    }




}

这里有演示CircleView

【讨论】:

  • 仍然无法使用您的代码...可能是因为我使用的是layoutSubviews?我应该在哪里添加它?
  • UIView 子类中(在layoutSubviews() 中)。我已经根据你的回答用完整的代码更新了我的问题,你能帮我找出问题所在吗?谢谢!
  • 哦,当我以编程方式执行此操作时,它可以工作。但是,当我尝试使用 xib(qa 类在 UIViewController xib 文件中的 UIView 组件)添加它时,它没有。知道为什么吗?
  • 我试过它甚至可以与 xib 一起使用,我现在为您上传演示
  • 谢谢。你会上传到哪里?
【解决方案2】:

你有一个 100 的固定半径,在一个较小的框架中,圆圈被画出它的边界。更改您的半径以灵活使用框架。我通常使用类似

radius = min(canvasWidth/1.5, canvasHeight/1.5);

【讨论】:

  • 你的意思是min(self.frame.width/1.5, self.frame.height/1.5)?我已经从 100 改了,还是不行
  • 我已经用完整的代码更新了我的问题,你能帮我找出问题所在吗?谢谢!
  • 您是否尝试过用较小的框架硬编码较小的半径?选项可能是它的添加方式,老实说,我对将它添加为子视图并不熟悉,我通常将 UIView 子类化并像这样添加它。它可能无法从尺寸创建更小的半径,因为它还不知道。
  • 什么意思?我应该尝试什么?
  • 如果你是 UIView 的子类,你不需要在绘制视图时物理添加视图,你只需要绘制它们。按照您希望它们绘制的顺序从绘图函数中调用它们。然后将 UIView 添加到您的情节提要中,并将此类作为其自定义类。这也确保了您使用的宽度和高度是实际关联的父视图。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-17
  • 2012-09-09
  • 2011-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多