2016-11-03 76 views
0

在我的應用程序中,我有一個方形的UIView,我想從上面切出一個孔/凹槽。網上的所有教程都是一樣的,看起來很直接,但他們中的每一個人總是提供與我想要的完全相反的東西。使用蒙版從UIView中切出一個圓圈

例如,這是自定義的UIView代碼:

class BottomOverlayView: UIView { 

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

    fileprivate func drawCircle(){ 

     let circleRadius: CGFloat = 80 
     let topMidRectangle = CGRect(x: 0, y: 0, width: circleRadius*2, height: circleRadius*2) 

     let circle: CAShapeLayer = CAShapeLayer() 
     circle.position = CGPoint(x: (frame.width/2)-circleRadius, y: 0-circleRadius) 
     circle.fillColor = UIColor.black.cgColor 
     circle.path = UIBezierPath(ovalIn: topMidRectangle).cgPath 
     circle.fillRule = kCAFillRuleEvenOdd 

     self.layer.mask = circle 
     self.clipsToBounds = true 
    } 
} 

這是我希望達到什麼樣的(淡藍色是UIView的,深藍色的背景):

What I want

但是,這是我取而代之的。 (每一次都不管我怎麼努力)

What I get

我不知道我怎麼會作出一個面具已經是我所需要的精確形狀實現這一目標,除了。但如果我能夠做到這一點,那麼我就不會在這個問題上擺在首位。有沒有人有任何提示如何實現這一目標?

編輯:這個問題,這應該是我已經嘗試過,但無法工作的副本。也許我做錯了,或者在錯誤的背景下使用它。我不熟悉任何給定的方法,並且使用指針使它看起來有些過時。被接受的答案在解釋如何使用更廣泛使用的UIBezierPaths以及在自定義UIView的上下文中解釋如何實現這個方面做得更好。

+0

Reilem - 如果您想使用Matt的雙路徑和奇數的填充規則來繪製所有未被屏蔽的路徑,它就可以工作。我個人覺得,當我能夠畫出面具的路徑時,它是違反直覺的,但是對於他自己而言。無論如何,我用兩種方法更新了我的答案。 – Rob

回答

2

我會建議爲你的面具畫一條路徑,在斯威夫特3

// BottomOverlayView.swift 

import UIKit 

@IBDesignable 
class BottomOverlayView: UIView { 

    @IBInspectable 
    var radius: CGFloat = 100 { didSet { updateMask() } } 

    override func layoutSubviews() { 
     super.layoutSubviews() 

     updateMask() 
    } 

    private func updateMask() { 
     let path = UIBezierPath() 
     path.move(to: bounds.origin) 
     let center = CGPoint(x: bounds.origin.x + bounds.size.width/2.0, y: bounds.origin.y) 
     path.addArc(withCenter: center, radius: radius, startAngle: .pi, endAngle: 0, clockwise: false) 
     path.addLine(to: CGPoint(x: bounds.origin.x + bounds.size.width, y: bounds.origin.y)) 
     path.addLine(to: CGPoint(x: bounds.origin.x + bounds.size.width, y: bounds.origin.y + bounds.size.height)) 
     path.addLine(to: CGPoint(x: bounds.origin.x, y: bounds.origin.y + bounds.size.height)) 
     path.close() 

     let mask = CAShapeLayer() 
     mask.path = path.cgPath 

     layer.mask = mask 
    } 
} 

注意,我調整了這個設定遮擋在兩個地方:

  • layoutSubviews:這樣,如果框架的變化,例如自動佈局的結果(或通過手動更改frame或其他),它會相應更新;和

  • 如果更新radius:這樣,如果您在故事板中使用此功能,或者如果以編程方式更改半徑,則會反映該更改。

所以,你可以在一個深藍色UIView之上覆蓋一個半高,淡藍色BottomOverlayView,就像這樣:

enter image description here

國債收益率:

enter image description here


如果你想用「剪一個洞」,在重複的回答表明技術,updateMask方法是:

private func updateMask() { 
    let center = CGPoint(x: bounds.origin.x + bounds.size.width/2.0, y: bounds.origin.y) 

    let path = CGMutablePath() 
    path.addArc(center: center, radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: false) 
    path.addRect(bounds) 

    let mask = CAShapeLayer() 
    mask.fillRule = kCAFillRuleEvenOdd 
    mask.path = path 

    layer.mask = mask 
} 

我個人覺得與奇偶規則的路徑中的路徑是有點計數器,直觀。我可以在哪裏(比如這種情況),我只想繪製掩模的路徑。但是如果你需要一個具有裁剪的面具,這種偶數的填充規則方法會很有用。

+0

非常感謝你!一個非常好的答案我的問題,我甚至沒有意識到路徑可以用這種方式,所以感謝指出我。我已經把它放到了我的代碼中,它看起來好像全部解決了。我已經把這作爲接受的答案。 :) – Reilem