【问题标题】:Can't put circular layer that surrounds imageView on different iPhone devices不能在不同的 iPhone 设备上放置围绕 imageView 的圆形层
【发布时间】:2018-01-17 12:00:27
【问题描述】:

我该如何解决这个问题? 图像在情节提要中设置了约束;另一个圆圈是用这些代码行设置的:

let centerY = profileImage.center.y+20+(self.navigationController?.navigationBar.frame.size.height)!
let centerX = profileImage.center.x
let center = CGPoint(x: centerX, y: centerY)
let trackLayer = CAShapeLayer()
let circularPath = UIBezierPath(arcCenter: center, radius: (profileImage.frame.width/2)+2, startAngle: -CGFloat.pi-CGFloat.pi/2, endAngle: CGFloat.pi/2, clockwise: true)
trackLayer.path = circularPath.cgPath
trackLayer.strokeColor = Functions.hexStringToUIColor(hex: "#3859B9").cgColor
trackLayer.lineWidth = 3
trackLayer.lineCap = kCALineCapRound
trackLayer.fillColor = UIColor.clear.cgColor
view.layer.addSublayer(trackLayer)

在 iPhone 7 上(右边那个)似乎是正确的。

【问题讨论】:

  • 你在哪个函数里加圈?很可能在布局完成之前调用您的代码。顺便说一句,您还可以以编程方式将自动布局约束添加到您以编程方式创建的圆圈中。
  • 你的代码在加载方法中吗?那么你可以使用延迟为 0.5 的调度队列
  • 你为什么不把子层添加到 profileImage 中呢?
  • 是的,我的代码在viewDidLoad中,放在那里有错吗?
  • viewDidlayoutSubviews.......

标签: ios swift uiimageview layer


【解决方案1】:

对导航栏或状态栏的高度使用固定值会导致此类错误。您应该根据图像视图定位图层。为此,您可以简单地将图像视图的框架分配给您的图层:

trackLayer.frame = profileImage.frame

由于布局可能因多种原因(例如设备旋转)而发生变化,您应该在视图控制器的viewDidLayoutSubviews 中执行此操作。

由于图层的框架现在比您的示例中小,您应该使用以下方法创建中心:

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

【讨论】:

  • 但是我应该在 UIBezierPath 的定义中放入什么来替换变量 center 呢?
【解决方案2】:
override func viewDidLayoutSubviews() {

    let centerY = profileImage.center.y+20+(self.navigationController?.navigationBar.frame.size.height)!
    let centerX = profileImage.center.x
    let center = CGPoint(x: centerX, y: centerY)
    let trackLayer = CAShapeLayer()
    let circularPath = UIBezierPath(arcCenter: center, radius: (profileImage.frame.width/2)+2, startAngle: -CGFloat.pi-CGFloat.pi/2, endAngle: CGFloat.pi/2, clockwise: true)
    trackLayer.path = circularPath.cgPath
    trackLayer.strokeColor = Functions.hexStringToUIColor(hex: "#3859B9").cgColor
    trackLayer.lineWidth = 3
    trackLayer.lineCap = kCALineCapRound
    trackLayer.fillColor = UIColor.clear.cgColor
    view.layer.addSublayer(trackLayer)

 }

或者直接在 viewDidAppear 中写代码

【讨论】:

  • 在计算布局时使用延迟执行来强制创建是一种非常糟糕的方法。你不应该那样做。 UIViewController 有关于布局的回调方法已更改。
【解决方案3】:

这将解决问题。

  1. layer 添加到profileImage.layer
  2. trackLayer.frame = profileImage.bounds

完整的代码应该是这样的:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let center = CGPoint(x: profileImage.bounds.midX,
                         y: profileImage.bounds.midY)
    let trackLayer = CAShapeLayer()
    trackLayer.frame = profileImage.frame
    let circularPath = UIBezierPath(arcCenter: center,
                                    radius: (profileImage.frame.width / 2) + 2,
                                    startAngle: -CGFloat.pi - CGFloat.pi / 2,
                                    endAngle: CGFloat.pi / 2, clockwise: true)
    trackLayer.path = circularPath.cgPath
    trackLayer.strokeColor = Functions.hexStringToUIColor(hex: "#3859B9").cgColor
    trackLayer.lineWidth = 3
    trackLayer.lineCap = kCALineCapRound
    trackLayer.fillColor = UIColor.clear.cgColor
    profileImage.layer.addSublayer(trackLayer)
}

【讨论】:

    【解决方案4】:

    使用界面生成器:

    1. 将 UIView 拖放到 imageview 上方
    2. 将视图自定义类更改为 CirculerProgressView
    3. 使用图像视图中心设置中心 X 和 Y 约束
    4. 设置高度和宽度约束(大于 imageView 高度和宽度)

      @IBDesignable class CirculerProgressView: UIView {
      
                  override class var layerClass: AnyClass {
                      return CAShapeLayer.self
                  }
      
                  override func draw(_ rect: CGRect) {
                      super.draw(rect)
                      setupLayer()
                  }
      
                  private func setupLayer() {
                      let trackLayer = layer as! CAShapeLayer
                      let center = CGPoint(x: frame.width/2, y: frame.height/2)
                      let circularPath = UIBezierPath(arcCenter: center, radius: frame.width/2, startAngle: -CGFloat.pi-CGFloat.pi/2, endAngle: CGFloat.pi/2, clockwise: true)
                      trackLayer.path = circularPath.cgPath
                      trackLayer.strokeColor = UIColor.blue.cgColor
                      trackLayer.lineWidth = 3
                      trackLayer.lineCap = kCALineCapRound
                      trackLayer.fillColor = UIColor.clear.cgColor
                  }}
      

    【讨论】:

    • 由于您使用图层进行绘图,因此您不应该在draw(rect:) 中更新它。您应该在layoutSubviews 中更新它,或者使用circularPath.stroke() 直接在draw(rect:) 中绘图。您的代码不应有太大变化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多