圆形 UIView 不是一个完整的圆圈
Posted
技术标签:
【中文标题】圆形 UIView 不是一个完整的圆圈【英文标题】:Circular UIView Not A Full Circle 【发布时间】:2017-03-03 23:15:44 【问题描述】:我有一个有趣的问题,但我不知道如何解决它。我正在尝试使用@IBInspectable 扩展 UIView。但是,使用这种方法,拐角半径似乎是从 nib 文件默认设置的,而不是视图的实际大小。
所以,当我在 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
IB中“查看为”设置为iPhoneSE
专为 iPhoneSE 打造
为 iPhone 7 构建
“查看方式”设置为iPhone7
为 iPhone SE 构建
为 iPhone 7 构建
IB 设置
【问题讨论】:
当您在 IB 中选择了 Circular UIView 时,您能否截取自动布局设置和屏幕截图? @SamuelTulach 在上面为您添加了这些内容。 【参考方案1】:只有当您的视图是正方形时,您才会得到一个完整的圆。
如果您的视图是一个矩形并且您将cornerRadius
设置为小于最小尺寸一半的值,您将获得第二个视图,如果该值大于该值,您将获得菱形视图。
检查您的约束,您应该在视图完成viewDidLayout
中的布局后计算cornerRadius
,以便获得正确的大小。
这是一个 Playground 展示了这个(我添加了一个动画来更好地展示这个问题):
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)
【讨论】:
视图是一个正方形。问题似乎不是方形,它似乎是在生命周期中运行它的代码时。它在完全布置视图的约束之前运行,因此圆度不正确。 @steventnorris 因为你应该计算cornerRadius
after 视图已经完成布局(它在我的答案中)。一个快速的解决方案是继承 UIView
并实现该方法。
是的。这就是我可能要做的。我试图以适用于所有 UIView 的方式执行此操作。如果我进行子类化,则无法再进行子类化。例如,假设我将 UIView 子类化为 MyRoundView。现在,如果我想要一个 UILabel,我必须决定是子类 UILabel 并复制该代码还是子类 MyRoundView,并且没有 UILabel 附带的方法和参数。
你可以在你的扩展中添加一些makeRound
方法并在你的视图控制器中调用它(例如在viewDidLayoutSubviews()
中)。或者,您可以循环查找 circleView
属性的视图和子视图。或者您可以使用 makeRoundCircleSubviews
... 的方法扩展您的视图控制器【参考方案2】:
您提到宽度和高度为 185.5,但您将宽度限制保持为 350。
【讨论】:
问题不在于约束。这应该适用于非静态宽度/高度约束,并且它不基于它在我开始思考的生命周期中的运行位置。【参考方案3】:如果您不想在 viewDidLayout 上移动,您可以在设置角半径之前简单地通过添加 .layoutIfNeeded() 来实现这一技巧。
yourCircleView.layoutIfNeeded()
yourCircleView.layer.cornerRadius = yourCircleView.frame.size.width/2
【讨论】:
【参考方案4】:如果仍然失败,请在 Xcode 中删除所有 (ALL) 约束并在 Cell Class 中添加以下内容:
override func awakeFromNib()
super.awakeFromNib()
userImageView.layoutIfNeeded()
userImageView.layer.cornerRadius = userImageView.frame.size.width / 2
userImageView.layer.masksToBounds = true
userImageView.clipsToBounds = true
【讨论】:
以上是关于圆形 UIView 不是一个完整的圆圈的主要内容,如果未能解决你的问题,请参考以下文章