在 UIView 外部(而不是内部)添加边框
Posted
技术标签:
【中文标题】在 UIView 外部(而不是内部)添加边框【英文标题】:Add a border outside of a UIView (instead of inside) 【发布时间】:2013-03-03 09:06:12 【问题描述】:如果使用类似视图中的代码添加视图的边框
self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = 2.0f;
边框被添加到视图中,如下所示:
右视图是原始视图,可以看到,边框视图的黑色区域小于原始视图。但我想要的是原始视图之外的边框,例如:。黑色区域和原来的一样,怎么实现呢?
【问题讨论】:
【参考方案1】:不幸的是,您不能简单地设置一个小属性来将边框与外部对齐。它与内部对齐绘制,因为 UIViews 默认绘制操作在其边界内绘制。
想到的最简单的解决方案是在应用边框时将 UIView 扩展边框宽度的大小:
CGFloat borderWidth = 2.0f;
self.frame = CGRectInset(self.frame, -borderWidth, -borderWidth);
self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = borderWidth;
【讨论】:
我在 uitableviewcell 的视图上使用了这个。但是就行了,self.frame = CGRectInset(self.frame, -borderWidth, -borderWidth);如果我们继续滚动表格视图,视图的宽度和高度会不断增加。所以我最终删除了它。 此方法不断增加视图高度,因此我删除此代码并使用以下代码 self.view.layer.borderColor = [[UIColor colorWithRed:209.0f/255.0f green:33.0f/255.0f blue :8.0f/255.0f 阿尔法:1.0f] CGColor]; self.view.layer.borderWidth = 1.0f; 在 Swift 中尝试过这个解决方案,不幸的是不起作用,边框一直在 UIImageView 内绘制 如果这段代码在一个被多次调用的方法中,那么它的大小会不断增加,因为 self.frame 会重复自己。为了防止这种情况,请声明一个属性来存储 self.frame 并将其设置在 viewDidload 中。例如,_originalSize = self.frame;其中 originalSize 是一个 CGRect 属性。然后把代码改成self.frame = CGRectInset(_originalSize, -borderWidth, -borderWidth); 当这在 ViewDidLoad 中实现时,视图会自动调整到屏幕大小(即视图调整到原始大小,因此边框变得可见)。如果在 ViewDidAppear 中实现,它根本不会在原始视图之外创建边框。关于如何实现它以便在原始视图之外创建边框并且视图不会调整大小的任何想法?【参考方案2】:好的,已经有一个公认的答案,但我认为有更好的方法,你只需要有一个比你的视图大一点的新层,并且不要将它掩盖到视图层的边界(这实际上是默认行为)。这是示例代码:
CALayer * externalBorder = [CALayer layer];
externalBorder.frame = CGRectMake(-1, -1, myView.frame.size.width+2, myView.frame.size.height+2);
externalBorder.borderColor = [UIColor blackColor].CGColor;
externalBorder.borderWidth = 1.0;
[myView.layer addSublayer:externalBorder];
myView.layer.masksToBounds = NO;
当然,如果您希望边框为 1 个单位大,如果您想要更多,则相应地调整 borderWidth
和图层的框架。
这比使用稍大一点的第二个视图要好,因为CALayer
比UIView
轻,而且您不必修改myView
的框架,这很好,例如myView
是a@ 987654327@
NB : 对我来说,模拟器上的结果并不完美(该层并不完全在正确的位置,因此该层有时在一侧较厚)但正是实际要求的设备。
编辑
其实我在NB中说的问题只是因为我把模拟器的屏幕缩小了,正常大小完全没有问题
希望对你有帮助
【讨论】:
myView.layer.masksToBounds = NO;当 myView 有 CornerRadius 时会产生问题。 .masksToBounds = no // 如果缩放模式是 aspectFill,这也会溢出你的图像【参考方案3】:根据上述公认的最佳答案,我体验了这种不好的结果和难看的边缘:
所以我将与你分享我的 UIView Swift 扩展,它使用 UIBezierPath 作为边框轮廓 - 没有难看的边缘(灵感来自 @Fattie):
// UIView+BezierPathBorder.swift
import UIKit
extension UIView
fileprivate var bezierPathIdentifier:String return "bezierPathBorderLayer"
fileprivate var bezierPathBorder:CAShapeLayer?
return (self.layer.sublayers?.filter( (layer) -> Bool in
return layer.name == self.bezierPathIdentifier && (layer as? CAShapeLayer) != nil
) as? [CAShapeLayer])?.first
func bezierPathBorder(_ color:UIColor = .white, width:CGFloat = 1)
var border = self.bezierPathBorder
let path = UIBezierPath(roundedRect: self.bounds, cornerRadius:self.layer.cornerRadius)
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
if (border == nil)
border = CAShapeLayer()
border!.name = self.bezierPathIdentifier
self.layer.addSublayer(border!)
border!.frame = self.bounds
let pathUsingCorrectInsetIfAny =
UIBezierPath(roundedRect: border!.bounds, cornerRadius:self.layer.cornerRadius)
border!.path = pathUsingCorrectInsetIfAny.cgPath
border!.fillColor = UIColor.clear.cgColor
border!.strokeColor = color.cgColor
border!.lineWidth = width * 2
func removeBezierPathBorder()
self.layer.mask = nil
self.bezierPathBorder?.removeFromSuperlayer()
例子:
let view = UIView(frame: CGRect(x: 20, y: 20, width: 100, height: 100))
view.layer.cornerRadius = view.frame.width / 2
view.backgroundColor = .red
//add white 2 pixel border outline
view.bezierPathBorder(.white, width: 2)
//remove border outline (optional)
view.removeBezierPathBorder()
【讨论】:
在我的情况下它应该在里面:) 很好的思维方式,但您的边框仍然在“内部”,因此需要将其固定为轮廓 :)【参考方案4】:对于 Swift 实现,您可以将其添加为 UIView 扩展。
extension UIView
struct Constants
static let ExternalBorderName = "externalBorder"
func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.whiteColor()) -> CALayer
let externalBorder = CALayer()
externalBorder.frame = CGRectMake(-borderWidth, -borderWidth, frame.size.width + 2 * borderWidth, frame.size.height + 2 * borderWidth)
externalBorder.borderColor = borderColor.CGColor
externalBorder.borderWidth = borderWidth
externalBorder.name = Constants.ExternalBorderName
layer.insertSublayer(externalBorder, atIndex: 0)
layer.masksToBounds = false
return externalBorder
func removeExternalBorders()
layer.sublayers?.filter() $0.name == Constants.ExternalBorderName .forEach()
$0.removeFromSuperlayer()
func removeExternalBorder(externalBorder: CALayer)
guard externalBorder.name == Constants.ExternalBorderName else return
externalBorder.removeFromSuperlayer()
【讨论】:
太棒了!谢谢!有些东西在 Swift 4 中有所改变,现在看起来有所不同,但 Xcode 解释了如何修改代码。并且在方法 'removeExternalBorder' 中必须是 'guard externalBorder.name == '。【参考方案5】:好吧,没有直接的方法可以做到这一点 您可以考虑一些解决方法。
-
更改和增加框架并像您一样添加边框颜色
在当前视图后面添加一个较大尺寸的视图,使其显示为边框。可以作为自定义视图类使用
如果您不需要明确的边界(清晰的边界),那么您可以依赖阴影来达到目的
[view1 setBackgroundColor:[UIColor blackColor]];
UIColor *color = [UIColor yellowColor];
view1.layer.shadowColor = [color CGColor];
view1.layer.shadowRadius = 10.0f;
view1.layer.shadowOpacity = 1;
view1.layer.shadowOffset = CGSizeZero;
view1.layer.masksToBounds = NO;
【讨论】:
【参考方案6】:在添加边框之前用边框宽度增加视图框架的宽度和高度:
float borderWidth = 2.0f
CGRect frame = self.frame;
frame.width += borderWidth;
frame.height += borderWidth;
self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = 2.0f;
【讨论】:
【参考方案7】:斯威夫特 5
extension UIView
fileprivate struct Constants
static let externalBorderName = "externalBorder"
func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white) -> CALayer
let externalBorder = CALayer()
externalBorder.frame = CGRect(x: -borderWidth, y: -borderWidth, width: frame.size.width + 2 * borderWidth, height: frame.size.height + 2 * borderWidth)
externalBorder.borderColor = borderColor.cgColor
externalBorder.borderWidth = borderWidth
externalBorder.name = Constants.ExternalBorderName
layer.insertSublayer(externalBorder, at: 0)
layer.masksToBounds = false
return externalBorder
func removeExternalBorders()
layer.sublayers?.filter() $0.name == Constants.externalBorderName .forEach()
$0.removeFromSuperlayer()
func removeExternalBorder(externalBorder: CALayer)
guard externalBorder.name == Constants.externalBorderName else return
externalBorder.removeFromSuperlayer()
【讨论】:
【参考方案8】:我喜欢 @picciano 的解决方案 如果您想要爆炸圆形而不是方形,请将 addExternalBorder 函数替换为:
func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white)
let externalBorder = CALayer()
externalBorder.frame = CGRect(x: -borderWidth, y: -borderWidth, width: frame.size.width + 2 * borderWidth, height: frame.size.height + 2 * borderWidth)
externalBorder.borderColor = borderColor.cgColor
externalBorder.borderWidth = borderWidth
externalBorder.cornerRadius = (frame.size.width + 2 * borderWidth) / 2
externalBorder.name = Constants.ExternalBorderName
layer.insertSublayer(externalBorder, at: 0)
layer.masksToBounds = false
【讨论】:
【参考方案9】:其实有一个非常简单的解决方案。只需像这样设置它们:
view.layer.borderWidth = 5
view.layer.borderColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.5).cgColor
view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.25).cgColor
【讨论】:
【参考方案10】:我喜欢@picciano 和@Maksim Kniazev 的解决方案。我们还可以使用以下方法创建环形边框:
func addExternalAnnularBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white)
let externalBorder = CALayer()
externalBorder.frame = CGRect(x: -borderWidth*2, y: -borderWidth*2, width: frame.size.width + 4 * borderWidth, height: frame.size.height + 4 * borderWidth)
externalBorder.borderColor = borderColor.cgColor
externalBorder.borderWidth = borderWidth
externalBorder.cornerRadius = (frame.size.width + 4 * borderWidth) / 2
externalBorder.name = Constants.ExternalBorderName
layer.insertSublayer(externalBorder, at: 0)
layer.masksToBounds = false
【讨论】:
【参考方案11】:我在 Storyboard 中的 UI 视图(主 - SubscriptionAd)周围放置边框的方法是将其放置在另一个 UI 视图(背景 - BackgroundAd)中。 Background UIView 的背景颜色与我想要的边框颜色相匹配,而 Main UIView 的每一侧都有约束值 2。
我会将背景视图链接到我的 ViewController,然后通过更改背景颜色来打开和关闭边框。
【讨论】:
以上是关于在 UIView 外部(而不是内部)添加边框的主要内容,如果未能解决你的问题,请参考以下文章
Swift - UIView 包含 UIImageView 包含图像