So fügen Sie einen Rahmen direkt über einer UIView hinzu
144
Meine Frage ist auf den Titel.
Ich weiß nicht, wie ich einen Rand auf einer bestimmten Seite, oben oder unten, auf einer beliebigen Seite hinzufügen soll ...
layer.borderzeichnet den Rand für die gesamte Ansicht ...
Ich denke hier über das Unterklassen UIViewund Überschreiben von drawRectOverkill nach. Warum nicht eine Erweiterung UIViewhinzufügen und Rahmenunteransichten hinzufügen?
@discardableResult
func addBorders(edges:UIRectEdge,
color:UIColor,
inset:CGFloat=0.0,
thickness:CGFloat=1.0)->[UIView]{
var borders =[UIView]()@discardableResult
func addBorder(formats:String...)->UIView{
let border =UIView(frame:.zero)
border.backgroundColor = color
border.translatesAutoresizingMaskIntoConstraints =false
addSubview(border)
addConstraints(formats.flatMap {NSLayoutConstraint.constraints(withVisualFormat: $0,
options:[],
metrics:["inset": inset,"thickness": thickness],
views:["border": border])})
borders.append(border)return border
}if edges.contains(.top)|| edges.contains(.all){
addBorder(formats:"V:|-0-[border(==thickness)]","H:|-inset-[border]-inset-|")}if edges.contains(.bottom)|| edges.contains(.all){
addBorder(formats:"V:[border(==thickness)]-0-|","H:|-inset-[border]-inset-|")}if edges.contains(.left)|| edges.contains(.all){
addBorder(formats:"V:|-inset-[border]-inset-|","H:|-0-[border(==thickness)]")}if edges.contains(.right)|| edges.contains(.all){
addBorder(formats:"V:|-inset-[border]-inset-|","H:[border(==thickness)]-0-|")}return borders
}// Usage:
view.addBorder(edges:[.all])// All with default arguments
view.addBorder(edges:[.top], color:.green)// Just Top, green, default thickness
view.addBorder(edges:[.left,.right,.bottom], color:.red, thickness:3)// All except Top, red, thickness 3
Mit diesem Code sind Sie auch nicht an Ihre Unterklasse gebunden. Sie können ihn auf alles anwenden, was erbt UIView- wiederverwendbar in Ihrem Projekt und auf alle anderen. Übergeben Sie andere Argumente an Ihre Methoden, um andere Farben und Breiten zu definieren. Viele Optionen.
Der einzige Nachteil hier ist, dass die Größe nicht geändert werden kann.
Peter DeWeese
2
Könnte eine UIView verwenden und Einschränkungen für das automatische Layout hinzufügen. Gleiches Prinzip.
Adam Waite
1
@PeterDeWeese Dies ist auch kein Nachteil - wenn Sie die Größe des Rahmens steuern möchten, müssen Sie lediglich Folgendes tun: - (void) addUpperBorderWithSize: (CGFloat) size Und dann die Konstante durch einen Parameter in der Funktion ersetzen . Gleiches gilt für andere Parameter wie Farben.
o.shnn
1
@AdamWaite, diese Auto-Layout-Variante sieht sehr gut aus. Danke !
Manonthemoon
2
Vielen Dank für die gemeinsame Nutzung, mache ich eine Version von Objective-C mit Zwang Auto Layout hier .
Itachi
99
Adam Waites ursprünglicher Beitrag und die mehrfachen Änderungen wurden um Funktionen für abgerundete Ecken erweitert
Wichtig!: Vergessen Sie nicht, 'label.layoutIfNeeded ()' hinzuzufügen, bevor Sie 'addborder' aufrufen, wie zuvor kommentiert
Hinweis: Ich habe dies nur auf UILabels getestet.
Erweiterung CALayer {
enumBorderSide{case top
case right
case bottom
case left
case notRight
case notLeft
case topAndBottom
case all
}enumCorner{case topLeft
case topRight
case bottomLeft
case bottomRight
}
func addBorder(side:BorderSide, thickness:CGFloat, color:CGColor, maskedCorners:CACornerMask?= nil){
var topWidth = frame.size.width; var bottomWidth = topWidth
var leftHeight = frame.size.height; var rightHeight = leftHeight
var topXOffset:CGFloat=0; var bottomXOffset:CGFloat=0
var leftYOffset:CGFloat=0; var rightYOffset:CGFloat=0// Draw the corners and set side offsetsswitch maskedCorners {case[.layerMinXMinYCorner,.layerMaxXMinYCorner]:// Top only
addCorner(.topLeft, thickness: thickness, color: color)
addCorner(.topRight, thickness: thickness, color: color)
topWidth -= cornerRadius*2
leftHeight -= cornerRadius; rightHeight -= cornerRadius
topXOffset = cornerRadius; leftYOffset = cornerRadius; rightYOffset = cornerRadius
case[.layerMinXMaxYCorner,.layerMaxXMaxYCorner]:// Bottom only
addCorner(.bottomLeft, thickness: thickness, color: color)
addCorner(.bottomRight, thickness: thickness, color: color)
bottomWidth -= cornerRadius*2
leftHeight -= cornerRadius; rightHeight -= cornerRadius
bottomXOffset = cornerRadius
case[.layerMinXMinYCorner,.layerMinXMaxYCorner]:// Left only
addCorner(.topLeft, thickness: thickness, color: color)
addCorner(.bottomLeft, thickness: thickness, color: color)
topWidth -= cornerRadius; bottomWidth -= cornerRadius
leftHeight -= cornerRadius*2
leftYOffset = cornerRadius; topXOffset = cornerRadius; bottomXOffset = cornerRadius;case[.layerMaxXMinYCorner,.layerMaxXMaxYCorner]:// Right only
addCorner(.topRight, thickness: thickness, color: color)
addCorner(.bottomRight, thickness: thickness, color: color)
topWidth -= cornerRadius; bottomWidth -= cornerRadius
rightHeight -= cornerRadius*2
rightYOffset = cornerRadius
case[.layerMaxXMinYCorner,.layerMaxXMaxYCorner,// All.layerMinXMaxYCorner,.layerMinXMinYCorner]:
addCorner(.topLeft, thickness: thickness, color: color)
addCorner(.topRight, thickness: thickness, color: color)
addCorner(.bottomLeft, thickness: thickness, color: color)
addCorner(.bottomRight, thickness: thickness, color: color)
topWidth -= cornerRadius*2; bottomWidth -= cornerRadius*2
topXOffset = cornerRadius; bottomXOffset = cornerRadius
leftHeight -= cornerRadius*2; rightHeight -= cornerRadius*2
leftYOffset = cornerRadius; rightYOffset = cornerRadius
default:break}// Draw the sidesswitch side {case.top:
addLine(x: topXOffset, y:0, width: topWidth, height: thickness, color: color)case.right:
addLine(x: frame.size.width - thickness, y: rightYOffset, width: thickness, height: rightHeight, color: color)case.bottom:
addLine(x: bottomXOffset, y: frame.size.height - thickness, width: bottomWidth, height: thickness, color: color)case.left:
addLine(x:0, y: leftYOffset, width: thickness, height: leftHeight, color: color)// Multiple Sidescase.notRight:
addLine(x: topXOffset, y:0, width: topWidth, height: thickness, color: color)
addLine(x:0, y: leftYOffset, width: thickness, height: leftHeight, color: color)
addLine(x: bottomXOffset, y: frame.size.height - thickness, width: bottomWidth, height: thickness, color: color)case.notLeft:
addLine(x: topXOffset, y:0, width: topWidth, height: thickness, color: color)
addLine(x: frame.size.width - thickness, y: rightYOffset, width: thickness, height: rightHeight, color: color)
addLine(x: bottomXOffset, y: frame.size.height - thickness, width: bottomWidth, height: thickness, color: color)case.topAndBottom:
addLine(x: topXOffset, y:0, width: topWidth, height: thickness, color: color)
addLine(x: bottomXOffset, y: frame.size.height - thickness, width: bottomWidth, height: thickness, color: color)case.all:
addLine(x: topXOffset, y:0, width: topWidth, height: thickness, color: color)
addLine(x: frame.size.width - thickness, y: rightYOffset, width: thickness, height: rightHeight, color: color)
addLine(x: bottomXOffset, y: frame.size.height - thickness, width: bottomWidth, height: thickness, color: color)
addLine(x:0, y: leftYOffset, width: thickness, height: leftHeight, color: color)}}private func addLine(x:CGFloat, y:CGFloat, width:CGFloat, height:CGFloat, color:CGColor){
let border =CALayer()
border.frame =CGRect(x: x, y: y, width: width, height: height)
border.backgroundColor = color
addSublayer(border)}private func addCorner(_ corner:Corner, thickness:CGFloat, color:CGColor){// Set default to top left
let width = frame.size.width; let height = frame.size.height
var x = cornerRadius
var startAngle:CGFloat=.pi; var endAngle:CGFloat=.pi*3/2switch corner {case.bottomLeft: startAngle =.pi/2; endAngle =.pi
case.bottomRight:
x = width - cornerRadius
startAngle =0; endAngle =.pi/2case.topRight:
x = width - cornerRadius
startAngle =.pi*3/2; endAngle =0default:break}
let cornerPath =UIBezierPath(arcCenter:CGPoint(x: x, y: height /2),
radius: cornerRadius - thickness,
startAngle: startAngle,
endAngle: endAngle,
clockwise:true)
let cornerShape =CAShapeLayer()
cornerShape.path = cornerPath.cgPath
cornerShape.lineWidth = thickness
cornerShape.strokeColor = color
cornerShape.fillColor = nil
addSublayer(cornerShape)}
Damit es funktioniert, müssen Sie view.layoutIfNeeded()direkt vor dem Anruf hinzufügen view.layer.addBorder(...). Dann funktioniert es in Swift 3
Adam Studenic
es funktioniert gut. Fügen Sie die Zeile in dieser Methode hinzuoverride func viewDidLayoutSubviews()
Antony Raphel
60
Der beste Weg für mich ist eine Kategorie in UIView, aber adding viewsanstelle von CALayers, damit wir es könnentake advantage of AutoresizingMasks sicherstellen , dass die Größe der Rahmen zusammen mit der Übersicht geändert wird.
Dies ist bei weitem eine der besten Lösungen für dieses Problem. Die meisten anderen Lösungsangebote berücksichtigen KEINE Ansichtsänderungen (und damit Gerätedrehung oder geteilte Ansichten). Dieser tut es.
Womble
1
Wie kann dies angepasst werden, um abgerundete Ecken zu unterstützen?
Dies funktioniert nicht, wenn die Größe der Ansicht geändert wird, z. B. wenn sich die Ausrichtung ändert.
Nestor
Wenn Sie ein rahmenbasiertes Layout verwenden, müssen Sie layoutSubviews implementieren und alle darin enthaltenen Subview- (oder Sublayer-) Frames neu berechnen
Trapper
22
Unterklasse UIViewund Implementierung drawRect:in Ihrer Unterklasse, z.
Dadurch wird eine rote Linie mit 2 Pixeln als oberer Rand gezeichnet. Alle anderen Variationen, die Sie erwähnen, bleiben dem Leser als triviale Übung.
Ist es der einzige Weg dafür ??? Wenn ich also eine Ansicht mit einem oberen Rand und eine andere Ansicht mit einem unteren Rand und eine andere Ansicht erstellen muss ... Ich meine immer eine bestimmte Ansicht mit einem oder zwei Rändern, muss ich für jeden bestimmten Fall eine Unterklasse erstellen ??? Ich weiß nicht, ob es wirklich schön ist, eine Klasse zu erstellen, nur um Grenzen hinzuzufügen ...
Manonthemoon
1
Denk darüber nach. Ihre UIViewUnterklasse könnte eine Eigenschaft haben, die bestimmt, welche Rahmen gezogen werden drawRect:. Diese Eigenschaft kann mit definiert werden, NS_OPTIONSsodass eine Bitmaske wie die UIViewAutoresizingBitmaske definiert wird. Wenn Sie - aus welchem Grund auch immer - wirklich stark gegen Unterklassen sind, UIViewfügen Sie einfach eine kleine Unteransicht mit einer Höhe von 1 bis 2 Pixel (oder einer breiten Breite) hinzu und geben Sie ihr die gewünschten Abmessungen, um einen Rand zu simulieren.
FluffulousChimp
Hey Leute, ich habe eine Swift-Unterklasse erstellt, die von diesem Code inspiriert ist. Ich hoffe, es gefällt
asiviero
19
Code für die ausgewählte Antwort, falls jemand dies wünscht.
HINWEIS: Dies funktioniert nicht mit Autolayout (auch bekannt als Drehen des Geräts in Querformat usw.).
Definieren Sie zuerst eine Dicke:
NSInteger borderThickness =1;
Kopieren Sie dann einfach einige oder alle, um den Rahmen festzulegen, den Sie festlegen möchten.
Einfache Lösung ... mit einem UIView-Overhead im Vergleich zu nacktem CALayer
Soberman
Nachdem ich alle anderen Lösungen gelesen hatte, dachte ich, ich würde auch nur eine winzige Ansicht hinzufügen. All das funktioniert für eine Grenze! Diese Lösung benötigt nur ein paar Stifte, um auch im automatischen Layout zu funktionieren. Viel einfacher, den Kopf herumzukriegen.
Noobsmcgoobs
Vielen Dank, ich habe oben einen Hinweis hinzugefügt, damit Codierer nur verwenden, wenn sich ihre App nicht dreht.
Travis M.
15
Alte Frage, aber die Autolayout-Lösung mit Laufzeitrahmenanpassungen fehlt noch.
borders(for:[.left,.bottom], width:2, color:.red)
Die folgende UIView-Erweiterung fügt den Rand nur an den angegebenen Kanten hinzu. Wenn Sie die Kanten zur Laufzeit ändern, werden die Ränder entsprechend angepasst.
extension UIView{
func borders(for edges:[UIRectEdge], width:CGFloat=1, color:UIColor=.black){if edges.contains(.all){
layer.borderWidth = width
layer.borderColor = color.cgColor
}else{
let allSpecificBorders:[UIRectEdge]=[.top,.bottom,.left,.right]for edge in allSpecificBorders {if let v = viewWithTag(Int(edge.rawValue)){
v.removeFromSuperview()}if edges.contains(edge){
let v =UIView()
v.tag =Int(edge.rawValue)
v.backgroundColor = color
v.translatesAutoresizingMaskIntoConstraints =false
addSubview(v)
var horizontalVisualFormat ="H:"
var verticalVisualFormat ="V:"switch edge {caseUIRectEdge.bottom:
horizontalVisualFormat +="|-(0)-[v]-(0)-|"
verticalVisualFormat +="[v(\(width))]-(0)-|"caseUIRectEdge.top:
horizontalVisualFormat +="|-(0)-[v]-(0)-|"
verticalVisualFormat +="|-(0)-[v(\(width))]"caseUIRectEdge.left:
horizontalVisualFormat +="|-(0)-[v(\(width))]"
verticalVisualFormat +="|-(0)-[v]-(0)-|"caseUIRectEdge.right:
horizontalVisualFormat +="[v(\(width))]-(0)-|"
verticalVisualFormat +="|-(0)-[v]-(0)-|"default:break}
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: horizontalVisualFormat, options:.directionLeadingToTrailing, metrics: nil, views:["v": v]))
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: verticalVisualFormat, options:.directionLeadingToTrailing, metrics: nil, views:["v": v]))}}}}}
Ich nahm sowohl Adam Waites als auch Pauls Antworten und kombinierte sie. Ich habe auch die Möglichkeit hinzugefügt, die ausgewählten Kanten zusammenzuleiten, sodass Sie nur eine Funktion wie folgt aufrufen müssen:
Ich habe die angebotenen Lösungen durchgesehen. Viele basieren auf Frames. Dies ist eine einfache Erweiterung, die mit AutoLayout funktioniert. Verwenden Sie Ansicht anstelle von Ebene, um sicherzustellen, dass AutoLayout - Einzelne Unteransicht mit 4 Einschränkungen verwendet werden kann
Aufbauend auf der Antwort von NSBum habe ich einen ähnlichen Ansatz gewählt und diese einfache UIView-Unterklasse so erstellt, dass sie in Interface Builder funktioniert und mit Einschränkungen funktioniert: Github-Link
Durch die Verwendung von CGContextFillRect anstelle von CGContextStrokePath konnte ich die Linien vorhersehbar vollständig fest und innerhalb halten die Grenzen der Sicht.
- Legen Sie einfach eine UIView in Interface Builder ab und ändern Sie ihren Klassentyp in NAUIViewWithBorders.
- Dann machen Sie in viewDidLoad Ihres VC etwas wie:
/* For a top border only ———————————————- */
self.myBorderView.borderColorTop =[UIColor redColor];
self.myBorderView..borderWidthsAll =1.0f;/* For borders with different colors and widths ————————— */
self.myBorderView.borderWidths =UIEdgeInsetsMake(2.0,4.0,6.0,8.0);
self.myBorderView.borderColorTop =[UIColor blueColor];
self.myBorderView.borderColorRight =[UIColor redColor];
self.myBorderView.borderColorBottom =[UIColor greenColor];
self.myBorderView.borderColorLeft =[UIColor darkGrayColor];
Hier ist ein direkter Link zur .m-Datei, damit Sie die Implementierung sehen können. Es gibt auch ein Demo-Projekt. Hoffe das hilft jemandem :)
Meine Antwort auf eine ähnliche Frage: https://stackoverflow.com/a/27141956/435766
Ich persönlich bevorzuge es, in dieser Kategorie den Weg der Kategorie zu gehen, da ich sie in jeder Unterklasse von UIView verwenden möchte.
Hier ist eine einfache Lösung. Fügen Sie eine Beschriftung hinzu UIView, löschen Sie den Text auf der Beschriftung und legen Sie die Hintergrundfarbe der Beschriftung als Rahmenfarbe fest. Legen Sie den Ursprung (x,y)Ihres Etiketts als Ursprung (x,y)Ihrer Ansicht fest. und stellen Sie die Breite des Etiketts auf die Breite Ihres Etiketts ein UIView, stellen Sie die Höhe auf 1 oder 2 ein (für Ihre Rahmenhöhe oben auf Ihrem UIView). Und das sollte den Trick machen.
Es macht keinen Sinn, ein Label zu haben, es könnte genauso gut ein anderes UIView sein
maor10
1
Dies beantwortet nicht wirklich die Frage, ob einer uiview nur der obere Rand hinzugefügt wird. Dies ist eine schnelle Lösung, die bei komplexeren Problemen wahrscheinlich nicht funktioniert.
Wird es 'addSublayer' aufrufen, wenn das Layout aktualisiert wird?
Jeevan
1
Posten Sie einfach hier, um jemandem zu helfen, der nach dem Hinzufügen von Rahmen sucht. Ich habe ein paar Änderungen in der akzeptierten Antwort hier gemacht rasches Etikett nur linken Rand . Geänderte Breite bei Fall UIRectEdge.Topvon CGRectGetHeight(self.frame)bis CGRectGetWidth(self.frame)und bei Fall UIRectEdge.Bottomvon UIScreen.mainScreen().bounds.widthbisCGRectGetWidth(self.frame) , um die Ränder korrekt zu erhalten. Verwenden von Swift 2.
Inspiriert von @Addison habe ich die Erweiterung ohne Verwendung eines Frameworks von Drittanbietern umgeschrieben, da er SnapKit und CocoaLumberjack verwendet hat.
Wie beim @ Addisons-Ansatz entferne ich auch zuvor hinzugefügte Rahmen, sodass diese Implementierung mit wiederverwendbaren Ansichten als Tabellenzellen und Sammlungszellen gut funktionieren sollte.
fileprivate classBorderView:UIView{}// dummy class to help us differentiate among border views and other views// to enabling us to remove existing borders and place new ones
extension UIView{
func setBorders(toEdges edges:[UIRectEdge], withColor color:UIColor, inset:CGFloat=0, thickness:CGFloat){// Remove existing edgesfor view in subviews {if view is BorderView{
view.removeFromSuperview()}}// Add new edgesif edges.contains(.all){
addSidedBorder(toEdge:[.left,.right,.top,.bottom], withColor: color, inset: inset, thickness: thickness)}if edges.contains(.left){
addSidedBorder(toEdge:[.left], withColor: color, inset: inset, thickness: thickness)}if edges.contains(.right){
addSidedBorder(toEdge:[.right], withColor: color, inset: inset, thickness: thickness)}if edges.contains(.top){
addSidedBorder(toEdge:[.top], withColor: color, inset: inset, thickness: thickness)}if edges.contains(.bottom){
addSidedBorder(toEdge:[.bottom], withColor: color, inset: inset, thickness: thickness)}}private func addSidedBorder(toEdge edges:[RectangularEdges], withColor color:UIColor, inset:CGFloat=0, thickness:CGFloat){for edge in edges {
let border =BorderView(frame:.zero)
border.backgroundColor = color
addSubview(border)
border.translatesAutoresizingMaskIntoConstraints =falseswitch edge {case.left:NSLayoutConstraint.activate([
border.leftAnchor.constraint(equalTo: self.leftAnchor, constant: inset),
border.topAnchor.constraint(equalTo: self.topAnchor, constant: inset),
border.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant:-inset),NSLayoutConstraint(item: border, attribute:.width, relatedBy:.equal, toItem: nil, attribute:.width, multiplier:1, constant: thickness)])case.right:NSLayoutConstraint.activate([
border.rightAnchor.constraint(equalTo: self.rightAnchor, constant:-inset),
border.topAnchor.constraint(equalTo: self.topAnchor, constant: inset),
border.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant:-inset),NSLayoutConstraint(item: border, attribute:.width, relatedBy:.equal, toItem: nil, attribute:.width, multiplier:1, constant: thickness)])case.top:NSLayoutConstraint.activate([
border.leftAnchor.constraint(equalTo: self.leftAnchor, constant: inset),
border.rightAnchor.constraint(equalTo: self.rightAnchor, constant:-inset),
border.topAnchor.constraint(equalTo: self.topAnchor, constant: inset),NSLayoutConstraint(item: border, attribute:.height, relatedBy:.equal, toItem: nil, attribute:.height, multiplier:1, constant: thickness)])case.bottom:NSLayoutConstraint.activate([
border.leftAnchor.constraint(equalTo: self.leftAnchor, constant: inset),
border.rightAnchor.constraint(equalTo: self.rightAnchor, constant:-inset),
border.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant:-inset),NSLayoutConstraint(item: border, attribute:.height, relatedBy:.equal, toItem: nil, attribute:.height, multiplier:1, constant: thickness)])}}}privateenumRectangularEdges{case left
case right
case top
case bottom
}}
Wenn ich aus dem Storyboard heraus baue, füge ich lieber ein UIViewhinter meinem nützlichen hinzu UIView... Wenn ich einen Rand über meinem erstellen möchte, UIViewerhöhe ich einfach die Höhe des Hintergrunds UIViewum meine Randbreite. Das Gleiche kann für jede andere Seite gemacht werden :)
Persönlich mag ich die Unterklassifizierung von view + drawRect, aber hier ist nur eine andere Vorgehensweise (und sie funktioniert in etwa so, wie die von @If Pollavith akzeptierte Antwort):
Ihre neue Randebene kann so eingerichtet werden, dass sie beliebige Abmessungen aufweist. Wie bei der Antwort von @If Pollavith erstellen Sie eine Ebene, die so hoch ist, wie Sie möchten, und so breit wie die Ansicht, die Sie umrandet haben möchten. Verwenden Sie die Rahmendefinition der Ebene, um sie an der gewünschten Stelle zu platzieren, und fügen Sie sie dann als Unterebene zu Ihrer Ansicht hinzu.
Als Referenz bestand meine eigene Anforderung darin, einen Rand auf der LINKEN HAND-Seite der Ansicht einzufügen (bitte schneiden Sie diesen Code nicht aus und fügen Sie ihn ein, und deaktivieren Sie mich einfach, da er keinen Rand oben in der Ansicht einfügt - Das Ändern des folgenden Codes ist einfach genug):
Ich denke, der einzige moderate Vorteil gegenüber diesem und dem Erstellen eines kleinen UIView oder UILabel ist, dass der CALayer angeblich "leichter" ist und es viele interessante Ansichten (wie in Meinungen) über das Überschreiben von drawRect im Vergleich zur Verwendung von CALayers (wie hier) gibt : iOS: Verwenden von 'drawRect:' von UIView im Vergleich zu 'drawLayer: inContext:' ).
Zusätzlich zu n8tr kann hinzugefügt werden, dass es eine Verfügbarkeit gibt, um sie über das Storyboard festzulegen :
- Hinzufügen von zwei Eigenschaften wie borderColorund borderWidthin der .h-Datei;
- Dann können Sie keyPathsdirekt im Storyboard hinzufügen , siehe Link zum Screenshot
Hinweis: Die meisten Lösungen hier sind nicht adaptiv und werden nicht in der Größe geändert. Die Lösungen, deren Größe geändert wird, werden massiv sein auf Ihre Startzeit aus, da sie viel CPU verbrauchen.
Sie können diese Lösung unten verwenden. Es funktioniert mit UIBezierPaths, die leichter als Ebenen sind und schnelle Startzeiten verursachen. Es ist einfach zu bedienen, siehe Anweisungen unten.
Antworten:
Ich denke hier über das Unterklassen
UIView
und Überschreiben vondrawRect
Overkill nach. Warum nicht eine ErweiterungUIView
hinzufügen und Rahmenunteransichten hinzufügen?Mit diesem Code sind Sie auch nicht an Ihre Unterklasse gebunden. Sie können ihn auf alles anwenden, was erbt
UIView
- wiederverwendbar in Ihrem Projekt und auf alle anderen. Übergeben Sie andere Argumente an Ihre Methoden, um andere Farben und Breiten zu definieren. Viele Optionen.quelle
Adam Waites ursprünglicher Beitrag und die mehrfachen Änderungen wurden um Funktionen für abgerundete Ecken erweitert
Wichtig!: Vergessen Sie nicht, 'label.layoutIfNeeded ()' hinzuzufügen, bevor Sie 'addborder' aufrufen, wie zuvor kommentiert
Hinweis: Ich habe dies nur auf UILabels getestet.
Erweiterung CALayer {
}}
quelle
view.layoutIfNeeded()
direkt vor dem Anruf hinzufügenview.layer.addBorder(...)
. Dann funktioniert es in Swift 3override func viewDidLayoutSubviews()
Der beste Weg für mich ist eine Kategorie in UIView, aber
adding views
anstelle von CALayers, damit wir es könnentake advantage of AutoresizingMasks
sicherstellen , dass die Größe der Rahmen zusammen mit der Übersicht geändert wird.Ziel c
Swift 5
quelle
Swift 3.0
Swift 4.1
quelle
Unterklasse
UIView
und ImplementierungdrawRect:
in Ihrer Unterklasse, z.Ziel c
Swift 4
Dadurch wird eine rote Linie mit 2 Pixeln als oberer Rand gezeichnet. Alle anderen Variationen, die Sie erwähnen, bleiben dem Leser als triviale Übung.
Quartz 2D Programming Guide wird empfohlen.
quelle
UIView
Unterklasse könnte eine Eigenschaft haben, die bestimmt, welche Rahmen gezogen werdendrawRect:
. Diese Eigenschaft kann mit definiert werden,NS_OPTIONS
sodass eine Bitmaske wie dieUIViewAutoresizing
Bitmaske definiert wird. Wenn Sie - aus welchem Grund auch immer - wirklich stark gegen Unterklassen sind,UIView
fügen Sie einfach eine kleine Unteransicht mit einer Höhe von 1 bis 2 Pixel (oder einer breiten Breite) hinzu und geben Sie ihr die gewünschten Abmessungen, um einen Rand zu simulieren.Code für die ausgewählte Antwort, falls jemand dies wünscht.
HINWEIS: Dies funktioniert nicht mit Autolayout (auch bekannt als Drehen des Geräts in Querformat usw.).
Definieren Sie zuerst eine Dicke:
Kopieren Sie dann einfach einige oder alle, um den Rahmen festzulegen, den Sie festlegen möchten.
Oberer Rand
Untere Grenze
Linker Rand
Rechter Rand
quelle
Alte Frage, aber die Autolayout-Lösung mit Laufzeitrahmenanpassungen fehlt noch.
Die folgende UIView-Erweiterung fügt den Rand nur an den angegebenen Kanten hinzu. Wenn Sie die Kanten zur Laufzeit ändern, werden die Ränder entsprechend angepasst.
quelle
Schnelle Version:
Bearbeiten: Für aktualisierte Versionen überprüfen Sie mein Repo hier: https://github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/UIViewExtensions.swift
Schauen Sie sich die addBorder-Teile an
quelle
Ich nahm sowohl Adam Waites als auch Pauls Antworten und kombinierte sie. Ich habe auch die Möglichkeit hinzugefügt, die ausgewählten Kanten zusammenzuleiten, sodass Sie nur eine Funktion wie folgt aufrufen müssen:
oder so:
Was Sie implementieren müssen, ist eine Kategorie in UIView, wie in anderen Antworten mit der folgenden Implementierung vorgeschlagen:
quelle
// MARK: - LeftBorder For View hinzufügen
// MARK: - RightBorder für Ansicht hinzufügen
// MARK: - Unteren Rand für Ansicht hinzufügen
quelle
Swift 4.2 und AutoLayout
Ich habe die angebotenen Lösungen durchgesehen. Viele basieren auf Frames. Dies ist eine einfache Erweiterung, die mit AutoLayout funktioniert. Verwenden Sie Ansicht anstelle von Ebene, um sicherzustellen, dass AutoLayout - Einzelne Unteransicht mit 4 Einschränkungen verwendet werden kann
Verwenden Sie wie folgt:
quelle
Ich habe einige Änderungen an Dans Antwort vorgenommen, damit ich mit einem Befehl mehreren Kanten Ränder hinzufügen kann:
Hier ist der vollständige Code:
quelle
Aufbauend auf der Antwort von NSBum habe ich einen ähnlichen Ansatz gewählt und diese einfache UIView-Unterklasse so erstellt, dass sie in Interface Builder funktioniert und mit Einschränkungen funktioniert: Github-Link
Durch die Verwendung von CGContextFillRect anstelle von CGContextStrokePath konnte ich die Linien vorhersehbar vollständig fest und innerhalb halten die Grenzen der Sicht.
Hier ist mein Blog-Beitrag dazu: http://natrosoft.com/?p=55
- Legen Sie einfach eine UIView in Interface Builder ab und ändern Sie ihren Klassentyp in NAUIViewWithBorders.
- Dann machen Sie in viewDidLoad Ihres VC etwas wie:
Hier ist ein direkter Link zur .m-Datei, damit Sie die Implementierung sehen können. Es gibt auch ein Demo-Projekt. Hoffe das hilft jemandem :)
quelle
Meine Antwort auf eine ähnliche Frage: https://stackoverflow.com/a/27141956/435766 Ich persönlich bevorzuge es, in dieser Kategorie den Weg der Kategorie zu gehen, da ich sie in jeder Unterklasse von UIView verwenden möchte.
quelle
quelle
Hier ist eine einfache Lösung. Fügen Sie eine Beschriftung hinzu
UIView
, löschen Sie den Text auf der Beschriftung und legen Sie die Hintergrundfarbe der Beschriftung als Rahmenfarbe fest. Legen Sie den Ursprung(x,y)
Ihres Etiketts als Ursprung(x,y)
Ihrer Ansicht fest. und stellen Sie die Breite des Etiketts auf die Breite Ihres Etiketts einUIView
, stellen Sie die Höhe auf 1 oder 2 ein (für Ihre Rahmenhöhe oben auf IhremUIView
). Und das sollte den Trick machen.quelle
Swift 3 Version
Um den entsprechenden Rahmen festzulegen, sollten Sie die Methode viewDidLayoutSubviews () überschreiben :
quelle
Posten Sie einfach hier, um jemandem zu helfen, der nach dem Hinzufügen von Rahmen sucht. Ich habe ein paar Änderungen in der akzeptierten Antwort hier gemacht rasches Etikett nur linken Rand . Geänderte Breite bei Fall
UIRectEdge.Top
vonCGRectGetHeight(self.frame)
bisCGRectGetWidth(self.frame)
und bei FallUIRectEdge.Bottom
vonUIScreen.mainScreen().bounds.width
bisCGRectGetWidth(self.frame)
, um die Ränder korrekt zu erhalten. Verwenden von Swift 2.Schließlich lautet die Erweiterung:
quelle
Für den Fall, dass jemand jemals eine Xamarin-Version benötigt:
quelle
Hier ist eine Swift 4-Version von Pauls 'Antwort
quelle
Inspiriert von @Addison habe ich die Erweiterung ohne Verwendung eines Frameworks von Drittanbietern umgeschrieben, da er SnapKit und CocoaLumberjack verwendet hat.
Wie beim @ Addisons-Ansatz entferne ich auch zuvor hinzugefügte Rahmen, sodass diese Implementierung mit wiederverwendbaren Ansichten als Tabellenzellen und Sammlungszellen gut funktionieren sollte.
quelle
Wenn ich aus dem Storyboard heraus baue, füge ich lieber ein
UIView
hinter meinem nützlichen hinzuUIView
... Wenn ich einen Rand über meinem erstellen möchte,UIView
erhöhe ich einfach die Höhe des HintergrundsUIView
um meine Randbreite. Das Gleiche kann für jede andere Seite gemacht werden :)quelle
Persönlich mag ich die Unterklassifizierung von view + drawRect, aber hier ist nur eine andere Vorgehensweise (und sie funktioniert in etwa so, wie die von @If Pollavith akzeptierte Antwort):
Ihre neue Randebene kann so eingerichtet werden, dass sie beliebige Abmessungen aufweist. Wie bei der Antwort von @If Pollavith erstellen Sie eine Ebene, die so hoch ist, wie Sie möchten, und so breit wie die Ansicht, die Sie umrandet haben möchten. Verwenden Sie die Rahmendefinition der Ebene, um sie an der gewünschten Stelle zu platzieren, und fügen Sie sie dann als Unterebene zu Ihrer Ansicht hinzu.
Als Referenz bestand meine eigene Anforderung darin, einen Rand auf der LINKEN HAND-Seite der Ansicht einzufügen (bitte schneiden Sie diesen Code nicht aus und fügen Sie ihn ein, und deaktivieren Sie mich einfach, da er keinen Rand oben in der Ansicht einfügt - Das Ändern des folgenden Codes ist einfach genug):
Ich denke, der einzige moderate Vorteil gegenüber diesem und dem Erstellen eines kleinen UIView oder UILabel ist, dass der CALayer angeblich "leichter" ist und es viele interessante Ansichten (wie in Meinungen) über das Überschreiben von drawRect im Vergleich zur Verwendung von CALayers (wie hier) gibt : iOS: Verwenden von 'drawRect:' von UIView im Vergleich zu 'drawLayer: inContext:' ).
Animal451
Ich mag die Farbe blau.
quelle
Zusätzlich zu n8tr kann hinzugefügt werden, dass es eine Verfügbarkeit gibt, um sie über das Storyboard festzulegen :
- Hinzufügen von zwei Eigenschaften wie
borderColor
undborderWidth
in der .h-Datei;- Dann können Sie
keyPaths
direkt im Storyboard hinzufügen , siehe Link zum Screenshotquelle
Konvertieren Sie die DanShev- Antwort in Swift 3
quelle
Für Xamarin in C # erstelle ich beim Hinzufügen der Unterebene einfach den Rahmen inline
Sie können dies (wie von anderen vorgeschlagen) für den unteren, linken und rechten Rand anordnen.
quelle
Sie können auch diese Sammlung von UIKit- und Foundation-Kategorien überprüfen: https://github.com/leszek-s/LSCategories
Es ermöglicht das Hinzufügen eines Rahmens auf einer Seite von UIView mit einer einzigen Codezeile:
und es handhabt die Ansichtsrotation richtig, während die meisten hier veröffentlichten Antworten nicht gut damit umgehen.
quelle
Hinweis: Die meisten Lösungen hier sind nicht adaptiv und werden nicht in der Größe geändert. Die Lösungen, deren Größe geändert wird, werden massiv sein auf Ihre Startzeit aus, da sie viel CPU verbrauchen.
Sie können diese Lösung unten verwenden. Es funktioniert mit UIBezierPaths, die leichter als Ebenen sind und schnelle Startzeiten verursachen. Es ist einfach zu bedienen, siehe Anweisungen unten.
quelle
Zum Festlegen des oberen und unteren Randes für eine UIView in Swift.
quelle
In Swift 4 und 3
quelle