90

如果使用视图中的代码添加视图的边框,例如

self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = 2.0f;

边框被添加到视图中,如下所示: 在此处输入图像描述

右视图是原始视图,可以看到,边框视图的黑色区域小于原始视图。但我想要得到的是原始视图之外的边框,如下所示:在此处输入图像描述. 黑色区域等于原始区域,我该如何实现?

4

11 回答 11

106

不幸的是,您不能简单地设置一个小属性来将边框与外部对齐。它与内部对齐绘制,因为 UIViews 默认绘制操作在其边界内绘制。

想到的最简单的解决方案是在应用边框时将 UIView 扩展边框宽度的大小:

CGFloat borderWidth = 2.0f;

self.frame = CGRectInset(self.frame, -borderWidth, -borderWidth);
self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = borderWidth;
于 2013-03-03T09:23:31.787 回答
25

好的,已经有一个公认的答案,但我认为有更好的方法来做到这一点,你只需要有一个比你的视图大一点的新层,并且不要将它掩盖到视图层的边界(实际上是默认行为)。这是示例代码:

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图层的框架。这比使用稍大一点的第二个视图要好,因为 aCALayer比 a 轻,UIView并且您不必修改 的框架myView,这很好,例如如果myView是 aUIImageView

注意:对我来说,模拟器上的结果并不完美(该层并不完全位于正确的位置,因此该层有时在一侧较厚)但正是真实设备上所要求的。

编辑

其实我在NB里说的问题只是因为我把模拟器的屏幕缩小了,正常大小是绝对没有问题的

希望能帮助到你

于 2015-11-06T09:03:31.250 回答
25

通过上述公认的最佳答案,我体验到了这样不好的结果和难看的边缘:

没有贝塞尔路径的边框

因此,我将与您分享我的 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()
于 2017-11-07T22:48:51.800 回答
24

对于 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()
    }

}
于 2016-03-02T19:44:57.973 回答
13

那么没有直接的方法可以做到这一点您可以考虑一些解决方法。

  1. 像你一样改变和增加框架并添加边框颜色
  2. 在当前视图后面添加一个尺寸较大的视图,使其显示为边框。可以作为自定义视图类
  3. 如果您不需要明确的边界(清晰的边界),那么您可以依靠阴影来达到目的

    [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;
    
于 2013-03-03T12:08:58.003 回答
2

在添加边框之前,使用边框宽度增加视图框架的宽度和高度:

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;
于 2013-03-03T09:20:08.710 回答
2

斯威夫特 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()
    }
}
于 2019-11-25T09:42:33.540 回答
1

我喜欢@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

    }
于 2018-06-29T04:51:51.193 回答
1

实际上有一个非常简单的解决方案。只需像这样设置它们:

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
于 2019-03-16T01:46:00.250 回答
0

我喜欢@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
}
于 2019-01-29T07:19:38.157 回答
0

在 Storyboard 中,我如何在我的 UI 视图(主 - SubscriptionAd)周围放置边框是将其放置在另一个 UI 视图(背景 - BackgroundAd)中。Background UIView 的背景颜色与我想要的边框颜色相匹配,而 Main UIView 的每一侧都有约束值 2。

我将背景视图链接到我的 ViewController,然后通过更改背景颜色来打开和关闭边框。

嵌套 UIView 的图像,周围有 Top View 2px 约束,使其更小而不是更大

于 2019-10-28T21:50:01.493 回答