Rozważam tutaj podklasy UIViewi drawRectprzesadę. Dlaczego nie dodać rozszerzenia UIViewi dodać podglądy obramowań?
@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
Dzięki temu kodowi nie jesteś również powiązany ze swoją podklasą, możesz go zastosować do wszystkiego i wszystkiego, co dziedziczy UIView- wielokrotnego użytku w projekcie i wszystkich innych. Przekaż inne argumenty do swoich metod, aby zdefiniować inne kolory i szerokości. Dużo opcji.
Jedynym minusem jest to, że nie można zmienić rozmiaru.
Peter DeWeese,
2
Może użyć UIView i dodać ograniczenia automatycznego układu. Ta sama zasada.
Adam Waite,
1
@PeterDeWeese To też nie jest wada - jeśli chcesz mieć kontrolę nad rozmiarem obramowania, wszystko co musisz zrobić, to coś w stylu: - (void) addUpperBorderWithSize: (CGFloat) size A potem zamień stałą na parametr w funkcji . To samo dotyczy innych parametrów, takich jak kolory.
o.shnn
1
@AdamWaite, ten wariant automatycznego układu wygląda bardzo dobrze. Dziękuję Ci !
manonthemoon
2
Dzięki za udostępnienie, tworzę wersję Objective-C z ograniczeniem automatycznego układu tutaj .
Itachi,
99
Dodano możliwość zaokrąglania rogów do oryginalnego postu Adama Waite'a i wielu edycji
Ważne !: Nie label.layoutIfNeeded()zapomnij dodać „ ” tuż przed wywołaniem „addborder”, jak wcześniej komentowano
Uwaga: testowałem to tylko na UILabels.
extension 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)}}
Aby to działało, musisz dodać view.layoutIfNeeded()tuż przed wywołaniem view.layer.addBorder(...). Następnie działa w Swift 3
Adam Studenic
działa dobrze. dodaj linię w tej metodzieoverride func viewDidLayoutSubviews()
Antony Raphel
60
Najlepszym sposobem dla mnie jest kategoria na UIView, ale adding viewszamiast CALayers, więc możemy take advantage of AutoresizingMasksupewnić się, że granice zmieniają się wraz z superviewem.
To zdecydowanie jedno z najlepszych rozwiązań tego problemu. Większość innych oferowanych rozwiązań NIE uwzględnia zmian widoku (a tym samym rotacji urządzeń lub podzielonych widoków). Ten ma.
Womble,
1
jak można to dostosować, aby wspierać zaokrąglone rogi?
Spowoduje to narysowanie 2-pikselowej czerwonej linii jako górnej granicy. Wszystkie inne odmiany, o których wspomniałeś, pozostawiamy jako trywialne ćwiczenie dla czytelnika.
Czy to jedyny sposób na to ??? Więc jeśli potrzebuję zrobić widok z górną ramką, a inny widok z dolną ramką i inny widok ... Mam na myśli zawsze konkretny widok z jedną lub dwiema ramkami, będę musiał utworzyć podklasę dla każdego konkretnego przypadku ??? Nie wiem, czy naprawdę fajnie jest tworzyć klasę tylko po to, by dodawać obramowania ...
manonthemoon
1
Nie. Pomyśl o tym. Twoja UIViewpodklasa może mieć właściwość, która określa, jakie granice drawRect:rysują. Tę właściwość można zdefiniować za pomocą, NS_OPTIONSaby definiowała maskę bitową, taką jak UIViewAutoresizingmaska bitowa. Jeśli - z jakiegoś powodu - naprawdę sprzeciwiasz się podklasom, UIViewpo prostu dodaj mały podgląd podrzędny o wysokości 1-2 pikseli (lub szerokości) i nadaj mu dowolne wymiary, które chcesz symulować obramowanie.
po przeczytaniu wszystkich innych rozwiązań pomyślałem, że dodam również mały widok. Wszystko to działa na granicy! To rozwiązanie wymaga tylko kilku pinów do pracy również w układzie automatycznym. O wiele łatwiej się poruszać.
noobsmcgoobs
Dzięki, dodałem powyżej notatkę, aby programiści używali tylko wtedy, gdy ich aplikacja się nie obraca.
Travis M.
15
Stare pytanie, ale wciąż brakuje rozwiązania z automatycznym układaniem i dostosowaniem granic czasu wykonywania.
borders(for:[.left,.bottom], width:2, color:.red)
Następujące rozszerzenie UIView doda obramowanie tylko na podanych krawędziach. Jeśli zmienisz krawędzie w czasie wykonywania, krawędzie zostaną odpowiednio dostosowane.
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]))}}}}}
Przejrzałem proponowane rozwiązania. Wiele z nich jest opartych na ramkach To jest proste rozszerzenie, które działa z AutoLayout - użyj widoku zamiast warstwy, aby upewnić się, że możemy użyć AutoLayout - Pojedynczy widok podrzędny z 4 ograniczeniami
Wziąłem odpowiedzi Adama Waite'a i Paulsa i połączyłem je. Dodałem również możliwość łączenia wybranych krawędzi ze sobą, więc wystarczy wywołać tylko jedną funkcję:
Opierając się na odpowiedzi NSBum , przyjąłem podobne podejście i stworzyłem tę prostą podklasę UIView, aby działała w Interface Builder i działała z ograniczeniami: link github
Używając CGContextFillRect zamiast CGContextStrokePath, byłem w stanie przewidzieć, że linie są całkowicie solidne i mieszczą się w granice widoku.
- Po prostu wrzuć UIView w Interface Builder i zmień jego typ klasy na NAUIViewWithBorders.
- Następnie w widoku VC DidLoad zrób coś takiego:
/* 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];
Oto bezpośredni link do pliku .m, dzięki czemu możesz zobaczyć implementację. Jest też projekt demo. Mam nadzieję, że to komuś pomoże :)
Moja odpowiedź na podobne pytanie: https://stackoverflow.com/a/27141956/435766
Osobiście wolę podążać drogą kategorii na tym, ponieważ chcę móc go używać w dowolnej podklasie UIView.
Oto proste rozwiązanie. Dodaj etykietę do swojej UIView, wyczyść tekst na etykiecie i ustaw kolor tła etykiety jako kolor obramowania. Ustaw źródło (x,y)etykiety jako źródło (x,y)swojego widoku. i ustaw szerokość etykiety na szerokość swojej UIView, ustaw wysokość na 1 lub 2 (dla wysokości obramowania na górze UIView). I to powinno załatwić sprawę.
W takim razie nie ma sensu mieć wytwórni, równie dobrze może to być kolejny UIView
maor10
1
To tak naprawdę nie odpowiada na pytanie o dodanie tylko górnej granicy do widoku uiview. Jest to szybka poprawka, która prawdopodobnie nie zadziała w przypadku bardziej złożonych problemów.
Czy wywoła „addSublayer”, gdy układ zostanie zaktualizowany?
doJeevan
1
Po prostu publikuję tutaj, aby pomóc komuś, kto chce dodać obramowanie. Dokonałem kilku zmian w zaakceptowanej odpowiedzi tutaj szybka etykieta tylko obramowanie . Zmieniono szerokość w przypadku UIRectEdge.Topod CGRectGetHeight(self.frame)do CGRectGetWidth(self.frame)iw przypadku UIRectEdge.Bottomod UIScreen.mainScreen().bounds.widthdo, CGRectGetWidth(self.frame)aby poprawnie uzyskać obramowanie. Korzystanie ze Swift 2.
Zainspirowany @Addisonem przepisałem rozszerzenie bez użycia jakiegokolwiek frameworka stron trzecich, ponieważ użył SnapKit i CocoaLumberjack.
Podobnie jak w podejściu @Addisons, usuwam również dodane wcześniej ramki, więc ta implementacja powinna dobrze wyglądać z widokami wielokrotnego użytku, takimi jak komórki tabeli i komórki kolekcji.
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
}}
Jeśli buduję z poziomu storyboardu, wolę dodać UIViewza moją użyteczną UIView... Jeśli chcę utworzyć obramowanie na górze mojej UIView, po prostu zwiększam wysokość tła UIViewo szerokość mojej obramowania. To samo może być zrobione dla każdej innej strony :)
Osobiście podoba mi się podklasa view + drawRect, ale oto inny sposób na to (i działa w ten sam sposób, co zaakceptowana odpowiedź @If Pollavith):
Twoja nowa warstwa obramowania może mieć dowolne wymiary. Tak więc, podobnie jak odpowiedź @If Pollavith, tworzysz warstwę tak wysoką, jak chcesz, i tak szeroką, jak widok, który chcesz, aby graniczył. Użyj definicji ramki warstwy, aby umieścić ją tam, gdzie chcesz, a następnie dodaj ją jako warstwę podrzędną do widoku.
Dla porównania, moim własnym wymaganiem było umieszczenie obramowania po LEWEJ STRONIE widoku (proszę nie wycinać i wklejać tego kodu i oznaczać „ja tylko”, ponieważ nie powoduje to umieszczenia obramowania u góry widoku - modyfikacja poniższego kodu jest dość prosta):
Oprócz n8tr można dodać, że istnieje możliwość ustawienia ich z storyboardu albo:
- dodaj dwie właściwości takie jak borderColoriw borderWidthpliku .h;
- wtedy możesz dodać keyPathsbezpośrednio w scenorysie, patrz link do zrzutu ekranu
Uwaga: większość rozwiązań tutaj nie jest adaptacyjna i nie zmienia rozmiaru. Rozwiązania, które zmienią rozmiar, będą miały ogromny wpływ na czas uruchamiania, ponieważ wykorzystują dużo procesora.
Możesz skorzystać z tego rozwiązania poniżej. Działa na ścieżkach UIBezierPath, które są lżejsze niż warstwy, powodując szybki czas uruchamiania. Jest łatwy w użyciu, zobacz instrukcje poniżej.
Odpowiedzi:
Rozważam tutaj podklasy
UIView
idrawRect
przesadę. Dlaczego nie dodać rozszerzeniaUIView
i dodać podglądy obramowań?Dzięki temu kodowi nie jesteś również powiązany ze swoją podklasą, możesz go zastosować do wszystkiego i wszystkiego, co dziedziczy
UIView
- wielokrotnego użytku w projekcie i wszystkich innych. Przekaż inne argumenty do swoich metod, aby zdefiniować inne kolory i szerokości. Dużo opcji.źródło
Dodano możliwość zaokrąglania rogów do oryginalnego postu Adama Waite'a i wielu edycji
Ważne !: Nie
label.layoutIfNeeded()
zapomnij dodać „ ” tuż przed wywołaniem „addborder”, jak wcześniej komentowanoUwaga: testowałem to tylko na
UILabels
.źródło
view.layoutIfNeeded()
tuż przed wywołaniemview.layer.addBorder(...)
. Następnie działa w Swift 3override func viewDidLayoutSubviews()
Najlepszym sposobem dla mnie jest kategoria na UIView, ale
adding views
zamiast CALayers, więc możemytake advantage of AutoresizingMasks
upewnić się, że granice zmieniają się wraz z superviewem.Cel C
Szybki 5
źródło
Swift 3.0
Swift 4.1
źródło
Podklasę
UIView
i zaimplementujdrawRect:
w swojej podklasie, np .:Cel C
Szybki 4
Spowoduje to narysowanie 2-pikselowej czerwonej linii jako górnej granicy. Wszystkie inne odmiany, o których wspomniałeś, pozostawiamy jako trywialne ćwiczenie dla czytelnika.
Zalecany jest Quartz 2D Programming Guide .
źródło
UIView
podklasa może mieć właściwość, która określa, jakie granicedrawRect:
rysują. Tę właściwość można zdefiniować za pomocą,NS_OPTIONS
aby definiowała maskę bitową, taką jakUIViewAutoresizing
maska bitowa. Jeśli - z jakiegoś powodu - naprawdę sprzeciwiasz się podklasom,UIView
po prostu dodaj mały podgląd podrzędny o wysokości 1-2 pikseli (lub szerokości) i nadaj mu dowolne wymiary, które chcesz symulować obramowanie.Kod wybranej odpowiedzi na wypadek, gdyby ktoś chciał.
UWAGA: To nie działa z automatycznym układem (czyli obracaniem urządzenia w poziomie itp.).
Najpierw zdefiniuj grubość:
Następnie po prostu skopiuj, użyj dowolnego lub wszystkich z nich, aby ustawić obramowanie, które chcesz ustawić.
Górna granica
Dolna granica
Lewa krawędź
Prawa krawędź
źródło
Stare pytanie, ale wciąż brakuje rozwiązania z automatycznym układaniem i dostosowaniem granic czasu wykonywania.
Następujące rozszerzenie UIView doda obramowanie tylko na podanych krawędziach. Jeśli zmienisz krawędzie w czasie wykonywania, krawędzie zostaną odpowiednio dostosowane.
źródło
Wersja Swift:
Edycja: Aby uzyskać zaktualizowane wersje, sprawdź moje repozytorium tutaj: https://github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/UIViewExtensions.swift
Spójrz na części addBorder
źródło
Swift 4.2 i AutoLayout
Przejrzałem proponowane rozwiązania. Wiele z nich jest opartych na ramkach To jest proste rozszerzenie, które działa z AutoLayout - użyj widoku zamiast warstwy, aby upewnić się, że możemy użyć AutoLayout - Pojedynczy widok podrzędny z 4 ograniczeniami
Użyj w następujący sposób:
źródło
Wziąłem odpowiedzi Adama Waite'a i Paulsa i połączyłem je. Dodałem również możliwość łączenia wybranych krawędzi ze sobą, więc wystarczy wywołać tylko jedną funkcję:
lub tak:
To, co musisz zaimplementować, to kategoria w UIView, jak sugerują inne odpowiedzi z następującą implementacją:
źródło
// MARK: - Dodaj lewą granicę do widoku
// MARK: - Dodaj RightBorder do widoku
// MARK: - Dodaj dolną ramkę do widoku
źródło
Wprowadziłem kilka zmian w odpowiedzi Dana, aby móc dodać obramowanie do wielu krawędzi jednym poleceniem:
Oto pełny kod:
źródło
Opierając się na odpowiedzi NSBum , przyjąłem podobne podejście i stworzyłem tę prostą podklasę UIView, aby działała w Interface Builder i działała z ograniczeniami: link github
Używając CGContextFillRect zamiast CGContextStrokePath, byłem w stanie przewidzieć, że linie są całkowicie solidne i mieszczą się w granice widoku.
Oto mój wpis na blogu na ten temat: http://natrosoft.com/?p=55
- Po prostu wrzuć UIView w Interface Builder i zmień jego typ klasy na NAUIViewWithBorders.
- Następnie w widoku VC DidLoad zrób coś takiego:
Oto bezpośredni link do pliku .m, dzięki czemu możesz zobaczyć implementację. Jest też projekt demo. Mam nadzieję, że to komuś pomoże :)
źródło
Moja odpowiedź na podobne pytanie: https://stackoverflow.com/a/27141956/435766 Osobiście wolę podążać drogą kategorii na tym, ponieważ chcę móc go używać w dowolnej podklasie UIView.
źródło
źródło
Oto proste rozwiązanie. Dodaj etykietę do swojej
UIView
, wyczyść tekst na etykiecie i ustaw kolor tła etykiety jako kolor obramowania. Ustaw źródło(x,y)
etykiety jako źródło(x,y)
swojego widoku. i ustaw szerokość etykiety na szerokość swojejUIView
, ustaw wysokość na 1 lub 2 (dla wysokości obramowania na górzeUIView
). I to powinno załatwić sprawę.źródło
Wersja Swift 3
Aby ustawić odpowiednie obramowanie, należy nadpisać metodę viewDidLayoutSubviews () :
źródło
Po prostu publikuję tutaj, aby pomóc komuś, kto chce dodać obramowanie. Dokonałem kilku zmian w zaakceptowanej odpowiedzi tutaj szybka etykieta tylko obramowanie . Zmieniono szerokość w przypadku
UIRectEdge.Top
odCGRectGetHeight(self.frame)
doCGRectGetWidth(self.frame)
iw przypadkuUIRectEdge.Bottom
odUIScreen.mainScreen().bounds.width
do,CGRectGetWidth(self.frame)
aby poprawnie uzyskać obramowanie. Korzystanie ze Swift 2.Wreszcie rozszerzenie to:
źródło
Na wypadek, gdyby ktoś kiedykolwiek potrzebował wersji Xamarin:
źródło
Oto wersja Swift 4 odpowiedzi Paulsa
źródło
Zainspirowany @Addisonem przepisałem rozszerzenie bez użycia jakiegokolwiek frameworka stron trzecich, ponieważ użył SnapKit i CocoaLumberjack.
Podobnie jak w podejściu @Addisons, usuwam również dodane wcześniej ramki, więc ta implementacja powinna dobrze wyglądać z widokami wielokrotnego użytku, takimi jak komórki tabeli i komórki kolekcji.
źródło
Jeśli buduję z poziomu storyboardu, wolę dodać
UIView
za moją użytecznąUIView
... Jeśli chcę utworzyć obramowanie na górze mojejUIView
, po prostu zwiększam wysokość tłaUIView
o szerokość mojej obramowania. To samo może być zrobione dla każdej innej strony :)źródło
Osobiście podoba mi się podklasa view + drawRect, ale oto inny sposób na to (i działa w ten sam sposób, co zaakceptowana odpowiedź @If Pollavith):
Twoja nowa warstwa obramowania może mieć dowolne wymiary. Tak więc, podobnie jak odpowiedź @If Pollavith, tworzysz warstwę tak wysoką, jak chcesz, i tak szeroką, jak widok, który chcesz, aby graniczył. Użyj definicji ramki warstwy, aby umieścić ją tam, gdzie chcesz, a następnie dodaj ją jako warstwę podrzędną do widoku.
Dla porównania, moim własnym wymaganiem było umieszczenie obramowania po LEWEJ STRONIE widoku (proszę nie wycinać i wklejać tego kodu i oznaczać „ja tylko”, ponieważ nie powoduje to umieszczenia obramowania u góry widoku - modyfikacja poniższego kodu jest dość prosta):
Myślę, że jedyną umiarkowaną korzyścią z tego i zrobienia małego UIView lub UILabel jest to, że CALayer jest podobno `` lżejszy '' i istnieje wiele interesujących poglądów (jak w opiniach) na temat przeważania drawRect w porównaniu z używaniem CALayers (jak tutaj : iOS: Korzystanie z funkcji „drawRect:” UIView w porównaniu z delagate warstwy „drawLayer: inContext:” ).
Zwierzę451
Podoba mi się kolor niebieski.
źródło
Oprócz n8tr można dodać, że istnieje możliwość ustawienia ich z storyboardu albo:
- dodaj dwie właściwości takie jak
borderColor
iwborderWidth
pliku .h;- wtedy możesz dodać
keyPaths
bezpośrednio w scenorysie, patrz link do zrzutu ekranuźródło
Przekonwertuj odpowiedź DanShev na Swift 3
źródło
W przypadku platformy Xamarin w języku C # po prostu tworzę obramowanie w wierszu podczas dodawania warstwy podrzędnej
Możesz to ustawić (zgodnie z sugestiami innych) dla dolnej, lewej i prawej krawędzi.
źródło
Możesz również sprawdzić tę kolekcję kategorii UIKit i Foundation: https://github.com/leszek-s/LSCategories
Pozwala na dodanie obramowania po jednej stronie UIView za pomocą jednej linii kodu:
i prawidłowo obsługuje rotację widoku, podczas gdy większość zamieszczonych tutaj odpowiedzi nie obsługuje tego dobrze.
źródło
Uwaga: większość rozwiązań tutaj nie jest adaptacyjna i nie zmienia rozmiaru. Rozwiązania, które zmienią rozmiar, będą miały ogromny wpływ na czas uruchamiania, ponieważ wykorzystują dużo procesora.
Możesz skorzystać z tego rozwiązania poniżej. Działa na ścieżkach UIBezierPath, które są lżejsze niż warstwy, powodując szybki czas uruchamiania. Jest łatwy w użyciu, zobacz instrukcje poniżej.
źródło
Do ustawiania górnej i dolnej granicy dla UIView w Swift.
źródło
W Swift 4 i 3
źródło