如何在Swift中创建一个不漏边框的圆形头像或圆角头像?
How To Create in Swift a Circular Profile Picture or Rounded Corner Image with a border which does not leak?
基于下面的source code:
@IBOutlet var myUIImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.makingRoundedImageProfileWithRoundedBorder()
}
private func makingRoundedImageProfileWithRoundedBorder() {
// Making a circular image profile.
// self.myUIImageView.layer.cornerRadius = self.myUIImageView.frame.size.width / 2
// Making a rounded image profile.
self.myUIImageView.layer.cornerRadius = 20.0
self.myUIImageView.clipsToBounds = true
// Adding a border to the image profile
self.myUIImageView.layer.borderWidth = 10.0
self.myUIImageView.layer.borderColor = UIColor.whiteColor().CGColor
}
确实我可以渲染圆形或圆形的 UIImageView,但问题是如果我们添加边框,图像会泄漏一点。圆形的 UIImageView 更糟糕,每当边框弯曲时它就会泄漏,所以到处都是泄漏!您可以在下面找到结果的屏幕截图:
在 Swift 中有什么方法可以解决这个问题?任何回答此问题的示例代码将不胜感激。
注意:解决方案必须尽可能与 iOS 7 和 8+ 兼容。
我致力于改进代码,但它总是崩溃。我会处理它,但我似乎有一个(粗略的)版本可以工作:
编辑 更新了一个稍微好一点的版本。我不喜欢 init:coder
方法,但也许可以考虑 out/improved
class RoundedImageView: UIView {
var image: UIImage? {
didSet {
if let image = image {
self.frame = CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
}
}
var cornerRadius: CGFloat?
private class func frameForImage(image: UIImage) -> CGRect {
return CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
override func drawRect(rect: CGRect) {
if let image = self.image {
image.drawInRect(rect)
let cornerRadius = self.cornerRadius ?? rect.size.width/10
let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
UIColor.whiteColor().setStroke()
path.lineWidth = cornerRadius
path.stroke()
}
}
}
let image = UIImage(named: "big-teddy-bear.jpg")
let imageView = RoundedImageView()
imageView.image = image
如果这就是您要找的东西,请告诉我。
一点解释:
我相信您已经发现,iOS 可以应用的 "border" 并不完美,并且由于某种原因显示了角落。我找到了其他一些解决方案,但 none 似乎有效。这是 UIView
的子类而不是 UIImageView
的原因是 drawRect:
is not called for subclasses of UIImageView
。我不确定这段代码的性能,但从我的(有限)测试来看它似乎不错
原代码:
class RoundedImageView: UIView {
var image: UIImage? {
didSet {
if let image = image {
self.frame = CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
}
}
private class func frameForImage(image: UIImage) -> CGRect {
return CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
override func drawRect(rect: CGRect) {
if let image = self.image {
self.image?.drawInRect(rect)
let path = UIBezierPath(roundedRect: rect, cornerRadius: 50)
UIColor.whiteColor().setStroke()
path.lineWidth = 10
path.stroke()
}
}
}
let image = UIImage(named: "big-teddy-bear.jpg")
let imageView = RoundedImageView()
imageView.image = image
imageView.layer.cornerRadius = 50
imageView.clipsToBounds = true
如果我可以提出一个快速而肮脏的解决方案:
您可以在图像视图下方添加另一个白色视图,而不是向图像视图添加边框。使视图在任一方向延伸 10 个点,并为其指定 20.0 的角半径。给图像视图一个 10.0 的角半径。
第一个解
基于@Jesper Schläger 的建议
“如果我可以建议一个快速而肮脏的解决方案:
您可以在图像视图下方添加另一个白色视图,而不是向图像视图添加边框。使视图在任一方向延伸 10 个点,并为其指定 20.0 的角半径。给图像视图一个 10.0 的角半径。"
请在下面找到 Swift 实现:
import UIKit
class ViewController: UIViewController {
@IBOutlet var myUIImageView: UIImageView!
@IBOutlet var myUIViewBackground: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Making a circular UIView: cornerRadius = self.myUIImageView.frame.size.width / 2
// Making a rounded UIView: cornerRadius = 10.0
self.roundingUIView(self.myUIImageView, cornerRadiusParam: 10)
self.roundingUIView(self.myUIViewBackground, cornerRadiusParam: 20)
}
private func roundingUIView(let aView: UIView!, let cornerRadiusParam: CGFloat!) {
aView.clipsToBounds = true
aView.layer.cornerRadius = cornerRadiusParam
}
}
第二种解法
会在 CALayer 上设置一个圆形遮罩。
请在下面找到第二个解决方案的Objective-C实现:
CALayer *maskedLayer = [CALayer layer];
[maskedLayer setFrame:CGRectMake(50, 50, 100, 100)];
[maskedLayer setBackgroundColor:[UIColor blackColor].CGColor];
UIBezierPath *maskingPath = [UIBezierPath bezierPath];
[maskingPath addArcWithCenter:maskedLayer.position
radius:40
startAngle:0
endAngle:360
clockwise:TRUE];
CAShapeLayer *maskingLayer = [CAShapeLayer layer];
[maskingLayer setPath:maskingPath.CGPath];
[maskedLayer setMask:maskingLayer];
[self.view.layer addSublayer:maskedLayer];
如果您注释掉第 UIBezierPath *maskingPath = [UIBezierPath bezierPath];
行到 [maskedLayer setMask:maskingLayer];
行,您会看到图层是一个正方形。然而,当这些行没有注释时,图层是一个圆圈。
注意:我既没有测试第二个解决方案也没有提供 Swift 实现,所以请随意测试它并通过下面的评论部分告诉我它是否有效。也可以随意编辑此 post 添加第二个解决方案的 Swift 实现。
基于下面的source code:
@IBOutlet var myUIImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.makingRoundedImageProfileWithRoundedBorder()
}
private func makingRoundedImageProfileWithRoundedBorder() {
// Making a circular image profile.
// self.myUIImageView.layer.cornerRadius = self.myUIImageView.frame.size.width / 2
// Making a rounded image profile.
self.myUIImageView.layer.cornerRadius = 20.0
self.myUIImageView.clipsToBounds = true
// Adding a border to the image profile
self.myUIImageView.layer.borderWidth = 10.0
self.myUIImageView.layer.borderColor = UIColor.whiteColor().CGColor
}
确实我可以渲染圆形或圆形的 UIImageView,但问题是如果我们添加边框,图像会泄漏一点。圆形的 UIImageView 更糟糕,每当边框弯曲时它就会泄漏,所以到处都是泄漏!您可以在下面找到结果的屏幕截图:
在 Swift 中有什么方法可以解决这个问题?任何回答此问题的示例代码将不胜感激。
注意:解决方案必须尽可能与 iOS 7 和 8+ 兼容。
我致力于改进代码,但它总是崩溃。我会处理它,但我似乎有一个(粗略的)版本可以工作:
编辑 更新了一个稍微好一点的版本。我不喜欢 init:coder
方法,但也许可以考虑 out/improved
class RoundedImageView: UIView {
var image: UIImage? {
didSet {
if let image = image {
self.frame = CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
}
}
var cornerRadius: CGFloat?
private class func frameForImage(image: UIImage) -> CGRect {
return CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
override func drawRect(rect: CGRect) {
if let image = self.image {
image.drawInRect(rect)
let cornerRadius = self.cornerRadius ?? rect.size.width/10
let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
UIColor.whiteColor().setStroke()
path.lineWidth = cornerRadius
path.stroke()
}
}
}
let image = UIImage(named: "big-teddy-bear.jpg")
let imageView = RoundedImageView()
imageView.image = image
如果这就是您要找的东西,请告诉我。
一点解释:
我相信您已经发现,iOS 可以应用的 "border" 并不完美,并且由于某种原因显示了角落。我找到了其他一些解决方案,但 none 似乎有效。这是 UIView
的子类而不是 UIImageView
的原因是 drawRect:
is not called for subclasses of UIImageView
。我不确定这段代码的性能,但从我的(有限)测试来看它似乎不错
原代码:
class RoundedImageView: UIView {
var image: UIImage? {
didSet {
if let image = image {
self.frame = CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
}
}
private class func frameForImage(image: UIImage) -> CGRect {
return CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
override func drawRect(rect: CGRect) {
if let image = self.image {
self.image?.drawInRect(rect)
let path = UIBezierPath(roundedRect: rect, cornerRadius: 50)
UIColor.whiteColor().setStroke()
path.lineWidth = 10
path.stroke()
}
}
}
let image = UIImage(named: "big-teddy-bear.jpg")
let imageView = RoundedImageView()
imageView.image = image
imageView.layer.cornerRadius = 50
imageView.clipsToBounds = true
如果我可以提出一个快速而肮脏的解决方案:
您可以在图像视图下方添加另一个白色视图,而不是向图像视图添加边框。使视图在任一方向延伸 10 个点,并为其指定 20.0 的角半径。给图像视图一个 10.0 的角半径。
第一个解
基于@Jesper Schläger 的建议
“如果我可以建议一个快速而肮脏的解决方案:
您可以在图像视图下方添加另一个白色视图,而不是向图像视图添加边框。使视图在任一方向延伸 10 个点,并为其指定 20.0 的角半径。给图像视图一个 10.0 的角半径。"
请在下面找到 Swift 实现:
import UIKit
class ViewController: UIViewController {
@IBOutlet var myUIImageView: UIImageView!
@IBOutlet var myUIViewBackground: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Making a circular UIView: cornerRadius = self.myUIImageView.frame.size.width / 2
// Making a rounded UIView: cornerRadius = 10.0
self.roundingUIView(self.myUIImageView, cornerRadiusParam: 10)
self.roundingUIView(self.myUIViewBackground, cornerRadiusParam: 20)
}
private func roundingUIView(let aView: UIView!, let cornerRadiusParam: CGFloat!) {
aView.clipsToBounds = true
aView.layer.cornerRadius = cornerRadiusParam
}
}
第二种解法
会在 CALayer 上设置一个圆形遮罩。
请在下面找到第二个解决方案的Objective-C实现:
CALayer *maskedLayer = [CALayer layer];
[maskedLayer setFrame:CGRectMake(50, 50, 100, 100)];
[maskedLayer setBackgroundColor:[UIColor blackColor].CGColor];
UIBezierPath *maskingPath = [UIBezierPath bezierPath];
[maskingPath addArcWithCenter:maskedLayer.position
radius:40
startAngle:0
endAngle:360
clockwise:TRUE];
CAShapeLayer *maskingLayer = [CAShapeLayer layer];
[maskingLayer setPath:maskingPath.CGPath];
[maskedLayer setMask:maskingLayer];
[self.view.layer addSublayer:maskedLayer];
如果您注释掉第 UIBezierPath *maskingPath = [UIBezierPath bezierPath];
行到 [maskedLayer setMask:maskingLayer];
行,您会看到图层是一个正方形。然而,当这些行没有注释时,图层是一个圆圈。
注意:我既没有测试第二个解决方案也没有提供 Swift 实现,所以请随意测试它并通过下面的评论部分告诉我它是否有效。也可以随意编辑此 post 添加第二个解决方案的 Swift 实现。