Odpowiedzi:
Aby ustawić właściwość obramowania, musisz użyć warstwy widoku. na przykład:
#import <QuartzCore/QuartzCore.h>
...
view.layer.borderColor = [UIColor redColor].CGColor;
view.layer.borderWidth = 3.0f;
Aby uzyskać dostęp do tej funkcji, musisz także połączyć się z QuartzCore.framework.
__bridge CGColorRef
. To nie działa. Musi być [UIColor blackColor].CGColor
tak, jak wspomniano w odpowiedzi.
#import <QuartzCore/QuartzCore.h>
nie jest już potrzebny.
Od najnowszej wersji Xcode istnieje lepsze rozwiązanie tego problemu:
Z @IBInspectable
można ustawić atrybuty bezpośrednio od wewnątrzAttributes Inspector
.
To ustawia User Defined Runtime Attributes
dla ciebie:
Istnieją dwa podejścia do skonfigurowania tego:
Opcja 1 (z aktualizacją na żywo w Storyboard)
MyCustomView
.UIView
.@IBDesignable
(powoduje to, że aktualizacja Wyświetl na żywo). *@IBInspectable
MyCustomView
`
@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
}
}
}
* @IBDesignable
działa tylko, gdy jest ustawiony na początkuclass MyCustomView
Opcja 2 (nie działa od Swift 1.2, patrz komentarze)
Rozszerz swoją klasę 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
}
}
}
W ten sposób domyślny widok zawsze zawiera te dodatkowe pola edytowalne Attributes Inspector
. Kolejną zaletą jest to, że nie musisz za MycustomView
każdym razem zmieniać klasy . Wadą tego jest jednak to, że zmiany będą widoczne dopiero po uruchomieniu aplikacji.
Możesz także utworzyć obramowanie z kolorem swojego życzenia.
view.layer.borderColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0].CGColor;
* r, g, b są wartościami od 0 do 255.
r
, g
i b
powinny prawdopodobnie pływaków; z dzielnikami powinny być również pływaki: r / 255.0
.
Dodaj następujące @IBInspectables w rozszerzeniu UIView
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
}
}
}
A potem powinieneś być w stanie ustawić atrybuty borderColor i borderWidth bezpośrednio z Inspektora atrybutów. Zobacz załączony obraz
Kiedy korzystam z rozwiązania CALayer Vladimira, a na wierzchu mam animację, taką jak modalne odrzucanie UINavigationController, widzę wiele błędów i problemy z wydajnością rysowania.
Tak więc innym sposobem na osiągnięcie tego, ale bez błędów i utraty wydajności, jest utworzenie niestandardowego UIView i zaimplementowanie drawRect
komunikatu w następujący sposób:
- (void)drawRect:(CGRect)rect
{
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(contextRef, 1);
CGContextSetRGBStrokeColor(contextRef, 255.0, 255.0, 255.0, 1.0);
CGContextStrokeRect(contextRef, rect);
}
setNeedsDisplay
widok. Wymusi to przerysowanie UIView i pośrednio nastąpi ponowne wywołanie drawRect
. Nie testowane, choć ...
view.layer.borderWidth = 1.0
view.layer.borderColor = UIColor.lightGray.cgColor
Wypróbuj ten kod:
view.layer.borderColor = [UIColor redColor].CGColor;
view.layer.borderWidth= 2.0;
[view setClipsToBounds:YES];
Nie sugerowałbym przesłonięcia metody drawRect z powodu spowodowania spadku wydajności.
Zamiast tego zmodyfikowałbym właściwości klasy jak poniżej (w niestandardowym uiview):
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.layer.borderWidth = 2.f;
self.layer.borderColor = [UIColor redColor].CGColor;
}
return self;
Nie widziałem żadnych błędów przy powyższym podejściu - nie jestem pewien, dlaczego włożenie initWithFrame zatrzymuje je ;-)
Chciałem dodać to do odpowiedzi @ marczking ( Opcja 1 ) jako komentarz, ale mój niski status na StackOverflow temu zapobiega.
Zrobiłem port odpowiedzi @ marczking na Cel C. Działa jak urok, dzięki @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
@IBInspectable działa dla mnie na 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
}
}
Jeśli nie chcesz edytować warstwy UIView, zawsze możesz osadzić widok w innym widoku. Widok nadrzędny miałby kolor tła ustawiony na kolor obramowania. Byłby również nieco większy, w zależności od tego, jak szeroka ma być granica.
Oczywiście działa to tylko wtedy, gdy twój widok nie jest przezroczysty i potrzebujesz tylko jednego koloru obramowania. OP chciał samej granicy w samym widoku, ale może to być realna alternatywa.
Jeśli chcesz dodać inną ramkę z różnych stron, możesz dodać widok podrzędny z konkretnym stylem, jest to sposób łatwy do wymyślenia.