2017-03-03 45 views
3

我有一個有趣的問題,但我不知道如何解決它。我試圖用@IBInspectable擴展UIView。但是,使用此方法時,角半徑似乎是從nib文件的默認側設置的,而不是視圖的實際大小。圓UIView不是一個完整的圓

因此,在IB中,我將「查看爲」設置爲iPhoneSE併爲iPhoneSE構建,視圖爲圓形。但是,如果我爲iPhone7構建,角落不會完全變成圓形。相反,如果我將「查看爲」設置爲iPhone7併爲iPhone7創建,則該視圖爲圓形,但如果爲iPhoneSE構建角落,則會出現過度圓角。

圖片和下面的代碼:

擴展

extension UIView { 

    @IBInspectable var cornerRadius:Double { 
     get { 
      return Double(layer.cornerRadius) 
     } 
     set { 
      layer.cornerRadius = CGFloat(newValue) 
      layer.masksToBounds = newValue > 0 
     } 
    } 

    @IBInspectable var circleView:Bool { 
     get { 
      return layer.cornerRadius == min(self.frame.width, self.frame.height)/CGFloat(2.0) ? true : false 
     } 
     set { 
      if newValue { 
       layer.cornerRadius = min(self.frame.width, self.frame.height)/CGFloat(2.0) 
       layer.masksToBounds = true 
      } 
      else{ 
       layer.cornerRadius = 0.0 
       layer.masksToBounds = false 
      } 
     } 
    } 

} 

「查看」

專爲iPhoneSE

enter image description here

建立iPhone 7設置爲iPhoneSE在IB

enter image description here

「查看方式」 設置爲iPhone7

建立iPhone SE

enter image description here

建立iPhone 7

enter image description here

IB設置 enter image description here enter image description here

+0

當你在IB中選擇Circular UIView時,你可以截取自動佈局設置和截圖嗎? –

+0

@SamuelTulach在上面添加了這些。 – steventnorris

回答

2

如果您的視圖是方形的,您將只能看到一個完整的圓。

如果您查看的是一個矩形,並且您將cornerRadius的值設置爲小於最小維度的一半,那麼您將獲得第二個視圖,如果它的值大於您將獲得的菱形形狀的值。

檢查您的約束,您應該在視圖完成viewDidLayout中的佈局後計算cornerRadius,以便獲得正確的大小。

這裏是在這個遊樂場(我已經添加了一個動畫來表現出更好的問題):

import UIKit 
import PlaygroundSupport 

extension UIView 
{ 
    func addCornerRadiusAnimation(from: CGFloat, to: CGFloat, duration: CFTimeInterval) 
    { 
    let animation = CABasicAnimation(keyPath:"cornerRadius") 
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 
    animation.fromValue = from 
    animation.toValue = to 
    animation.duration = duration 
    self.layer.add(animation, forKey: "cornerRadius") 
    self.layer.cornerRadius = to 
    } 
} 

let v = UIView(frame: CGRect(x: 0, y: 0, width: 350, height: 450)) 
PlaygroundPage.current.liveView = v 

let squareView = UIView(frame: CGRect(x: 10, y: 10, width: 100, height: 100)) 
squareView.backgroundColor = .red 
squareView.layer.masksToBounds = true 
v.addSubview(squareView) 
var cornerRadius = CGFloat(0.5*min(squareView.frame.width, 
            squareView.frame.height)) 
squareView.addCornerRadiusAnimation(from: 0, to: cornerRadius, duration: 5) 

let rectangleView = UIView(frame: CGRect(x: 10, y: 200, width: 100, height: 200)) 
rectangleView.backgroundColor = .blue 
rectangleView.layer.masksToBounds = true 
v.addSubview(rectangleView) 
cornerRadius = CGFloat(0.5*min(rectangleView.frame.width, 
            rectangleView.frame.height)) 
rectangleView.addCornerRadiusAnimation(from: 0, to: cornerRadius, duration: 5) 

let diamondView = UIView(frame: CGRect(x: 200, y: 200, width: 100, height: 200)) 
diamondView.backgroundColor = .green 
diamondView.layer.masksToBounds = true 
v.addSubview(diamondView) 
cornerRadius = CGFloat(0.5*max(diamondView.frame.width, 
           diamondView.frame.height)) 
diamondView.addCornerRadiusAnimation(from: 0, to: cornerRadius, duration: 5) 

Playground output

+0

視圖是一個正方形。這個問題似乎不是平方,它似乎是在生命週期中運行它的代碼的時候。它在約束完全佈置視圖之前運行,因此圓度不正確。 – steventnorris

+0

@steventnorris因爲你應該在*視圖完成佈局之後計算'cornerRadius' *(它在我的答案中)。一個快速解決方案是對UIView進行子類化並實現該方法。 – FranMowinckel

+0

是的。這是我可能需要做的。我試圖這樣做,它適用於所有UIViews。如果我是子類,那麼就沒有辦法再次子類化。例如,說我把UIView作爲MyRoundView的子類。現在,如果我想要一個UILabel,我必須決定是否繼承UILabel並複製該代碼或子類MyRoundView,並且不具有UILabel提供的方法和參數。 – steventnorris

0

你提到的寬度和高度爲185.5,但你一直寬度約束爲350

+0

這個問題不是約束。這應該適用於非靜態寬度/高度約束,並且它不基於它在我開始思考的生命週期中運行的位置。 – steventnorris

0

如果你不想在viewDidLayout上移動,你可以簡單地通過添加.layoutIfNeeded()來設置你的圓角半徑。

yourCircleView.layoutIfNeeded() 
yourCircleView.layer.cornerRadius = yourCircleView.frame.size.width/2