2016-07-29 26 views
1

我設計了一個自定義標題視圖,用於遮罩圖像並在底部邊緣繪製邊框,即弧線。它看起來像這樣:爲什麼UIView.animateWithDuration不影響這個自定義視圖?

enter image description here

下面是類代碼:

class HeaderView: UIView 
{ 
    private let imageView = UIImageView() 
    private let dimmerView = UIView() 

    private let arcShape = CAShapeLayer() 
    private let maskShape = CAShapeLayer() // Masks the image and the dimmer 

    private let titleLabel = UILabel() 

    @IBInspectable var image: UIImage? { didSet { self.imageView.image = self.image } } 
    @IBInspectable var title: String? { didSet {self.titleLabel.text = self.title} } 

    @IBInspectable var arcHeight: CGFloat? { didSet {self.setupLayers()} } 

    // MARK: Initialization 

    override init(frame: CGRect) 
    { 
     super.init(frame:frame) 
     initMyStuff() 
    } 

    required init?(coder aDecoder: NSCoder) 
    { 
     super.init(coder:aDecoder) 
     initMyStuff() 
    } 

    override func prepareForInterfaceBuilder() 
    { 
     backgroundColor = UIColor.clear() 
    } 

    internal func initMyStuff() 
    { 
     backgroundColor = UIColor.clear() 

     titleLabel.font = Font.AvenirNext_Bold(24) 
     titleLabel.text = "TITLE" 
     titleLabel.textColor = UIColor.white() 
     titleLabel.layer.shadowColor = UIColor.black().cgColor 
     titleLabel.layer.shadowOffset = CGSize(width: 0.0, height: 2.0) 

     titleLabel.layer.shadowRadius = 0.0; 
     titleLabel.layer.shadowOpacity = 1.0; 

     titleLabel.layer.masksToBounds = false 
     titleLabel.layer.shouldRasterize = true 

     imageView.contentMode = UIViewContentMode.scaleAspectFill 
     addSubview(imageView) 

     dimmerView.frame = self.bounds 
     dimmerView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6) 
     addSubview(dimmerView) 
     addSubview(titleLabel) 

     // Add the shapes 
     self.layer.addSublayer(arcShape) 
     self.layer.addSublayer(maskShape) 
     self.layer.masksToBounds = true // This seems to be unneeded...test more 

     // Set constraints 
     imageView.translatesAutoresizingMaskIntoConstraints = false 
     imageView .autoPinEdgesToSuperviewEdges() 
     titleLabel.autoCenterInSuperview() 
    } 

    func setupLayers() 
    { 
     let aHeight = arcHeight ?? 10 

     // Create the arc shape 
     arcShape.path = AppocalypseUI.createHorizontalArcPath(CGPoint(x: 0, y: bounds.size.height), width: bounds.size.width, arcHeight: aHeight) 
     arcShape.strokeColor = UIColor.white().cgColor 
     arcShape.lineWidth = 1.0 
     arcShape.fillColor = UIColor.clear().cgColor 

     // Create the mask shape 
     let maskPath = AppocalypseUI.createHorizontalArcPath(CGPoint(x: 0, y: bounds.size.height), width: bounds.size.width, arcHeight: aHeight, closed: true) 
     maskPath.moveTo(nil, x: bounds.size.width, y: bounds.size.height) 
     maskPath.addLineTo(nil, x: bounds.size.width, y: 0) 
     maskPath.addLineTo(nil, x: 0, y: 0) 
     maskPath.addLineTo(nil, x: 0, y: bounds.size.height) 

     //let current = CGPathGetCurrentPoint(maskPath); 
     //print(current) 

     let mask_Dimmer = CAShapeLayer() 
     mask_Dimmer.path = maskPath.copy() 

     maskShape.fillColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1.0).cgColor 
     maskShape.path = maskPath 

     // Apply the masks 
     imageView.layer.mask = maskShape 
     dimmerView.layer.mask = mask_Dimmer 
    } 

    override func layoutSubviews() 
    { 
     super.layoutSubviews() 

     // Let's go old school here... 
     imageView.frame = self.bounds 
     dimmerView.frame = self.bounds 
     setupLayers() 
    } 
} 

像這樣的事情會導致它只是捕捉到新的大小,而不逐漸改變它的框架:

UIView.animate(withDuration: 1.0) 
{ 
    self.headerView.arcHeight  = self.new_headerView_arcHeight 
    self.headerView.frame   = self.new_headerView_frame 
} 

我認爲它必須與我使用CALayers的事實有關,但我對真正背後的情況並不十分了解網元。

編輯: 下面是我用它來創建ARC路徑的功能:

class func createHorizontalArcPath(_ startPoint:CGPoint, width:CGFloat, arcHeight:CGFloat, closed:Bool = false) -> CGMutablePath 
    { 
     // http://www.raywenderlich.com/33193/core-graphics-tutorial-arcs-and-paths 

     let arcRect = CGRect(x: startPoint.x, y: startPoint.y-arcHeight, width: width, height: arcHeight) 

     let arcRadius = (arcRect.size.height/2) + (pow(arcRect.size.width, 2)/(8*arcRect.size.height)); 
     let arcCenter = CGPoint(x: arcRect.origin.x + arcRect.size.width/2, y: arcRect.origin.y + arcRadius); 

     let angle = acos(arcRect.size.width/(2*arcRadius)); 
     let startAngle = CGFloat(M_PI)+angle // (180 degrees + angle) 
     let endAngle = CGFloat(M_PI*2)-angle // (360 degrees - angle) 
     //  let startAngle = radians(180) + angle; 
     //  let endAngle = radians(360) - angle; 

     let path = CGMutablePath(); 
     path.addArc(nil, x: arcCenter.x, y: arcCenter.y, radius: arcRadius, startAngle: startAngle, endAngle: endAngle, clockwise: false); 
     if(closed == true) 
     {path.addLineTo(nil, x: startPoint.x, y: startPoint.y);} 
     return path; 
    } 

獎金: 設置arcHeight屬性設置爲0的結果中沒有白線被繪製。爲什麼?

回答

0

Path屬性不能動畫。你必須以不同的方式解決問題。您可以立即繪製一條弧線,任何弧線,以便告訴我們需要手動處理動畫。如果您預計整個繪製過程需要3秒鐘,那麼您可能需要將過程拆分爲1000個部分,並且每0.3毫秒調用一次圓弧繪製函數1000次,以便從頭到尾再次繪製圓弧。

0

self.headerView.arcHeight不是動畫屬性。它只是UIView的自有財產動畫

你可以做這樣的事情

let displayLink = CADisplayLink(target: self, selector: #selector(update)) 
displayLink.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode 

let expectedFramesPerSecond = 60 


var diff : CGFloat = 0 
func update() { 
    let diffUpdated = self.headerView.arcHeight - self.new_headerView_arcHeight 
    let done = (fabs(diffUpdated) < 0.1) 
    if(!done){ 
     self.headerView.arcHeight -= diffUpdated/(expectedFramesPerSecond*0.5) 
     self.setNeedsDisplay() 
    } 
} 
相關問題