2016-04-30 29 views
0

我有一個帶有白色虛線邊框的藍色視圖。正如你可以從下面的圖片看到的,一旦應用程序被旋轉,視圖改變其尺寸,邊框不會調整到視圖的新寬度和高度。當應用程序更改大小類時刪除UIView的邊框

enter image description here

我需要找到一種方法來

  • 當視圖控制器改變其大小知道 - 也許使用viewWillTransitionToSize
  • 刪除以前繪製的邊框(如果有的話)。
  • 向視圖添加一個新邊框 - 在視圖的drawRect方法中。

如何刪除先前繪製在視圖上的邊框?

@IBOutlet weak var myView: UIView! 

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { 
    coordinator.animateAlongsideTransition(nil, completion: { 
    _ in 
     self.myView.setNeedsDisplay() 
    }) 
} 

class RenderView: UIView { 
    override func drawRect(rect: CGRect) { 
     self.addDashedBorder() 
    } 
} 

extension UIView { 
    func addDashedBorder() { 
     let color = UIColor.whiteColor().CGColor 
     let shapeLayer:CAShapeLayer = CAShapeLayer() 
     let frameSize = self.frame.size 
     let shapeRect = CGRect(x: 0, y: 0, width: frameSize.width, height: frameSize.height) 
     shapeLayer.bounds = shapeRect 
     shapeLayer.position = CGPoint(x: frameSize.width/2, y: frameSize.height/2) 
     shapeLayer.fillColor = UIColor.clearColor().CGColor 
     shapeLayer.strokeColor = color 
     shapeLayer.lineWidth = 6 
     shapeLayer.lineJoin = kCALineJoinRound 
     shapeLayer.lineDashPattern = [6,3] 
     shapeLayer.path = UIBezierPath(roundedRect: shapeRect, cornerRadius: 5).CGPath 
     self.layer.addSublayer(shapeLayer) 
    } 
} 

Download sample project here

+1

不要求人們下載您的項目,找到相關的代碼並提供解決方案,您應該僅使用代碼的相關部分更新您的問題。 – rmaddy

回答

1

這不是做事的正確方法。每次您的RenderView重新繪製時,將調用其drawRect方法,並且addDashedBorder添加到您的視圖的新圖層

drawRect用於使用CoreGraphics或UIKit繪製視圖,而不是CoreAnimation。在這個方法裏面,你應該畫畫,沒有別的。如果你想使用它一層,layoutSubviews是一個更好的地方添加它,並更新它以匹配視圖。

以下是解決問題的兩種方法。正確更新邊框,並在設備旋轉時平滑地設置邊框的動畫效果。

替代方案1:只需在drawRect中繪製邊框,而不是使用單獨的形狀圖層。此外,請設置您的視圖contentMode,以便在其大小更改時自動重新繪製。

class ViewController: UIViewController { 

    @IBOutlet weak var myView: UIView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.myView.contentMode = .Redraw 
    } 
} 

class RenderView: UIView { 
    override func drawRect(rect: CGRect) { 
     let path = UIBezierPath(roundedRect: self.bounds, cornerRadius: 5) 

     path.lineWidth = 6 

     let pattern: [CGFloat] = [6.0, 3.0] 
     path.setLineDash(pattern, count: 2, phase: 0) 

     UIColor.whiteColor().setStroke() 
     path.stroke() 
    } 
} 

選擇2:繼續使用CAShapeLayer,但只能創建一個單獨的一個,用lazy stored property。在覆蓋layoutSubviews的覆蓋中更新圖層,並在必要時將其與視圖邊界中的任何更改一起進行動畫處理。

class ViewController: UIViewController { 
    @IBOutlet weak var myView: UIView! 
} 

class RenderView: UIView { 
    // Create the borderLayer, and add it to our view's layer, on demand, only once. 
    lazy var borderLayer: CAShapeLayer = { 
     let shapeLayer = CAShapeLayer() 
     shapeLayer.fillColor = nil 
     shapeLayer.strokeColor = UIColor.whiteColor().CGColor 
     shapeLayer.lineWidth = 6 
     shapeLayer.lineDashPattern = [6,3] 

     self.layer.addSublayer(shapeLayer) 

     return shapeLayer 
    }() 

    override func layoutSubviews() { 
     super.layoutSubviews() 

     // We will update the borderLayer's path to match the view's current bounds. 
     let newPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: 5).CGPath 

     // We may be animating from the old bounds to the new bounds. 
     // If so, we want the borderLayer to animate alongside that. 
     // (UIView does not do this automatically, since it does not know 
     // anything about our borderLayer; it's at the the CoreAnimation level, 
     // below UIKit.) 
     // 
     // We want an animation that uses the same properties as the existing 
     // animation, but applies to a different value: the borderLayer's path. 
     // We'll find the existing animation on the view's bounds.size, 
     // and if it exists, add our own animation based on it that will 
     // apply the path change. 

     if let viewBoundsAnimation = self.layer.animationForKey("bounds.size") { 
      let pathAnimation = CABasicAnimation() 
      pathAnimation.beginTime = viewBoundsAnimation.beginTime 
      pathAnimation.duration = viewBoundsAnimation.duration 
      pathAnimation.speed = viewBoundsAnimation.speed 
      pathAnimation.timeOffset = viewBoundsAnimation.timeOffset 
      pathAnimation.timingFunction = viewBoundsAnimation.timingFunction 
      pathAnimation.keyPath = "path" 
      pathAnimation.fromValue = borderLayer.path 
      pathAnimation.toValue = newPath 
      borderLayer.addAnimation(pathAnimation, forKey: "path") 
     } 

     // Finally, whether we are animating or not, make the border layer show the new path. 
     // If we are animating, this will appear when the animation is finished. 
     // If we are not animating, this will appear immediately. 
     self.borderLayer.path = newPath 
    } 
} 

注意,無論是這些替代品的需要壓倒一切的viewWillTransitionToSizetraitCollectionDidChange。這些是更高層次的概念,可能會在設備輪換期間調用,但如果其他代碼更改視圖的大小則不會發生這種情況。最好使用簡單的UIView級別的drawRectlayoutSubviews方法,因爲它們將始終有效。

+0

感謝您的出色答案! – Cesare

-1

調用設置需要顯示時transitions.You可以使用此function.It檢測它的視圖完美的作品來檢測方向變化

override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) { 
self.myView.setNeedsDisplay() 
} 
+0

這並沒有解決他的代碼的根本問題。 –

+0

它修復了基本問題,你可以嘗試它@KurtRevis我們只需要刪除以前添加的圖層,其餘的將自己照顧 –

+0

我試過了,它不起作用。第一:如果刪除以前添加的圖層的代碼是必要的,那麼爲什麼你沒有在你的答案中包含這些?第二:如果我確實補充說明,邊框不會與藍色視圖一起順利地進行動畫。第三:當手機旋轉時,這將工作,但不會在iPad上,或者視圖的邊界以其他方式更改。 –