Cocoa Touch: 如何更改UIView的边框颜色和厚度?

281

我在检查工具中看到可以更改背景颜色,但我还想更改边框颜色和宽度,这是否可行?


1
https://dev59.com/LGsz5IYBdhLWcg3wxq4V#21881788 - Daniel Conde Marin
14个回答

601

您需要使用视图的层(layer)来设置边框属性。例如:

#import <QuartzCore/QuartzCore.h>
...
view.layer.borderColor = [UIColor redColor].CGColor;
view.layer.borderWidth = 3.0f;

您还需要链接QuartzCore.framework才能访问此功能。


有没有办法为每个边设置不同的宽度/颜色? - llullulluis
2
@lluismontero 我恐怕你必须使用drawRect:方法创建自定义UIView来实现该功能。 - Vladimir
1
如果我这样做,而且在这个视图上面还有一个动画,比如模态UINavigationController消失,我会看到很多故障发生,很难描述。如果我停用边框,一切都恢复正常。 - Nicu Surdu
@NicolaeSurdu,设定边框可能确实是一个性能问题,在这种情况下,您可以使用自定义视图的方法。 - Vladimir
5
提醒其他人注意:Xcode建议将UIColor转换为CGColorRef时使用__bridge CGColorRef,但这种方法不起作用。正确的写法是使用[UIColor blackColor].CGColor,就像回答中提到的那样。 - GoodSp33d
7
不再需要 #import <QuartzCore/QuartzCore.h> - meaning-matters

43

Xcode 6 更新

自从 Xcode 的最新版本,这个问题有了更好的解决方案:

使用 @IBInspectable,你可以直接在 Attributes Inspector 中设置属性。

My Custom View @IBInspectable Attributes

这会为您设置 User Defined Runtime Attributes

enter image description here

有两种方法可以设置:

选项 1(在故事板中实时更新)

  1. 创建一个 MyCustomView
  2. 继承自 UIView
  3. 设置 @IBDesignable(这使得视图实时更新)。*
  4. 使用 @IBInspectable 设置运行时属性(边框等)
  5. 将视图类更改为 MyCustomView
  6. 在属性面板中编辑并在故事板中查看更改 :)
@IBDesignable
class MyCustomView: UIView {
    @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            layer.cornerRadius = cornerRadius
            layer.masksToBounds = cornerRadius > 0
        }
    }
    @IBInspectable var borderWidth: CGFloat = 0 {
        didSet {
            layer.borderWidth = borderWidth
        }
    }
    @IBInspectable var borderColor: UIColor? {
        didSet {
            layer.borderColor = borderColor?.CGColor
        }
    }
}

* 只有在 class MyCustomView 开始处设置 @IBDesignable 才起作用。

选项2(自Swift 1.2以来不可行,请查看注释)

扩展你的 UIView 类:

extension UIView {
    @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            layer.cornerRadius = cornerRadius
            layer.masksToBounds = cornerRadius > 0
        }
    }
    @IBInspectable var borderWidth: CGFloat = 0 {
        didSet {
            layer.borderWidth = borderWidth
        }
    }
    @IBInspectable var borderColor: UIColor? {
        didSet {
            layer.borderColor = borderColor?.CGColor
        }
    }
}

这样做,您的默认视图始终Attributes Inspector中具有额外的可编辑字段。另一个优点是,您不必每次更改类别为MycustomView

然而,这种方法的一个缺点是,您只能在运行应用程序时看到更改。


1
截至今天,您的扩展在最新版本的Xcode中无法工作。 - user1971598
1
我只是确认@EdgarAroutiounian的说法,即在Swift 1.2中第二种方法不再适用。 - Sergey Grischyov
Objective-C怎么样? - Nike Kov
请查看下面spencery2的答案,他花时间用Objective-C编写了它。 - MMachinegun
将扩展更新为不存储值,并使用set(value){}和get {}直接访问图层,然后它就可以工作了。 - LightningStryk

17

您还可以使用您想要的颜色创建边框。

view.layer.borderColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0].CGColor;

*r,g,b的值在0到255之间。


6
值得注意的是,rgb应该使用浮点数;除数也应该是浮点数:r / 255.0 - user577537
不,C语法并不是你所说的那样。r、g和b可以是int类型,因为C语言(以及Objective-C是C语言)会在进行r/255.0运算时将int类型自动转换为double类型。顺便提一下,你得到的是double类型,而Clang会将其转换为CGFloat类型。 - ingconti

10

在 UIView 的扩展中添加以下 @IBInspectables

extension UIView {

  @IBInspectable var borderWidth: CGFloat {
    get {
      return layer.borderWidth
    }
    set(newValue) {
      layer.borderWidth = newValue
    }
  }

  @IBInspectable var borderColor: UIColor? {
    get {
      if let color = layer.borderColor {
        return UIColor(CGColor: color)
      }
      return nil
    }
    set(newValue) {
      layer.borderColor = newValue?.CGColor
    }
  }
}

接下来,您应该能够直接从属性检查器中设置borderColor和borderWidth属性。请参见附图。

属性检查器


9
view.layer.borderWidth = 1.0
view.layer.borderColor = UIColor.lightGray.cgColor

1
我真的不喜欢人们被莫名其妙地贬低,而没有任何解释。这对任何人都没有好处。 - ICL1901

8
当我使用Vladimir的CALayer解决方案时,在视图顶部有一个动画,比如模态UINavigationController取消,会看到许多故障发生,并且存在绘制性能问题。
因此,另一种实现方式是使用自定义UIView并实现drawRect消息,这样可以避免故障和性能损失,具体方法如下:
- (void)drawRect:(CGRect)rect
{
    CGContextRef contextRef = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(contextRef, 1);
    CGContextSetRGBStrokeColor(contextRef, 255.0, 255.0, 255.0, 1.0);
    CGContextStrokeRect(contextRef, rect);    
}

@Krish 你可以将颜色存储在一个变量中,当需要改变边框颜色时,改变变量的值并在视图上调用 setNeedsDisplay。这将强制重新绘制 UIView,并隐式地重新调用 drawRect。尚未测试... - Nicu Surdu

7
尝试这段代码:

请看以下代码:

view.layer.borderColor =  [UIColor redColor].CGColor;
view.layer.borderWidth= 2.0;
[view setClipsToBounds:YES];

4

我想在@marczking的答案(选项1)下面添加评论,但是我的StackOverflow低级别身份阻止了这一点。

我将@marczking的答案移植到Objective C中。效果很好,谢谢@marczking!

UIView+Border.h:

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface UIView (Border)

-(void)setBorderColor:(UIColor *)color;
-(void)setBorderWidth:(CGFloat)width;
-(void)setCornerRadius:(CGFloat)radius;

@end

UIView+Border.m:

#import "UIView+Border.h"

@implementation UIView (Border)
// Note: cannot use synthesize in a Category

-(void)setBorderColor:(UIColor *)color
{
    self.layer.borderColor = color.CGColor;
}

-(void)setBorderWidth:(CGFloat)width
{
    self.layer.borderWidth = width;
}

-(void)setCornerRadius:(CGFloat)radius
{
    self.layer.cornerRadius = radius;
    self.layer.masksToBounds = radius > 0;
}

@end

4

我不建议重写drawRect方法,因为这会导致性能下降。

相反,我建议在自定义的UIView中修改类的属性,如下所示:

  - (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
      self.layer.borderWidth = 2.f;
      self.layer.borderColor = [UIColor redColor].CGColor;
    }
  return self;

采用以上方法时我没有看到任何故障 - 不确定为什么加入initWithFrame会停止这些故障;-)


2

@IBInspectable在iOS 9和Swift 2.0上对我有效

extension UIView {

@IBInspectable var borderWidth: CGFloat {
get {
        return layer.borderWidth
    }
    set(newValue) {
        layer.borderWidth = newValue
    }
}

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

@IBInspectable var borderColor: UIColor? {
    get {
        if let color = layer.borderColor {
            return UIColor(CGColor: color)
        }
        return nil
    }
    set(newValue) {
        layer.borderColor = newValue?.CGColor
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接