Cara menambahkan perbatasan tepat di sisi atas UIView
144
Pertanyaan saya ada di judul.
Saya tidak tahu cara menambahkan perbatasan di sisi tertentu, atas atau bawah, sisi mana saja ...
layer.bordermenggambar perbatasan untuk seluruh tampilan ...
Saya menganggap subclassing UIViewdan drawRectoverkill overkill di sini. Mengapa tidak menambahkan ekstensi UIViewdan menambahkan subview perbatasan?
@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
Dengan kode ini Anda tidak terikat dengan subkelas Anda juga, Anda dapat menerapkannya pada apa saja dan semua yang diwarisi dari UIView- dapat digunakan kembali dalam proyek Anda, dan yang lainnya. Berikan argumen lain ke metode Anda untuk menentukan warna dan lebar lain. Banyak pilihan.
Satu-satunya downside di sini adalah bahwa itu tidak dapat mengubah ukuran.
Peter DeWeese
2
Bisa menggunakan UIView dan menambahkan kendala tata letak otomatis. Prinsip yang sama.
Adam Waite
1
@PeterDeWeese Ini bukan kerugian juga - jika Anda ingin kontrol atas ukuran perbatasan, yang perlu Anda lakukan adalah sesuatu seperti: - (batal) addUpperBorderWithSize: (CGFloat) ukuran Dan kemudian ganti konstanta dengan parameter dalam fungsi . Hal yang sama berlaku untuk parameter lain seperti warna.
o.shnn
1
@AdamWaite, varian tata letak otomatis ini terlihat sangat bagus. Terima kasih !
manonthemoon
2
Terima kasih telah berbagi, saya membuat versi Objective-C dengan batasan tata letak otomatis di sini .
Itachi
99
Menambahkan kemampuan untuk sudut membulat ke pos asli Adam Waite, dan beberapa pengeditan
Penting !: Jangan lupa menambahkan ' label.layoutIfNeeded()' tepat sebelum memanggil 'addborder' seperti yang dikomentari sebelumnya
Catatan: Saya baru menguji ini 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)}}
Kode ini tidak berfungsi pada Swift 3 karena alasan tertentu, setelah mengubah tanda tangan CGRectMake dan CGColor per Swift 3.
EmbCoder
Ada artikel bagus di sini medium.com/swift-programming/… yang membahas tentang apa yang perlu Anda lakukan untuk Swift 3.
Micah Montoya
2
Adakah keberuntungan menerapkan ini dalam 3 cepat?
Marquavious Draggon
7
Untuk membuatnya berfungsi, Anda perlu menambahkan view.layoutIfNeeded()tepat sebelum memanggil view.layer.addBorder(...). Kemudian ia bekerja di Swift 3
Adam Studenic
itu bekerja dengan baik. tambahkan baris dalam metode inioverride func viewDidLayoutSubviews()
Antony Raphel
60
Cara terbaik bagi saya adalah kategori di UIView, tapi adding viewsbukannya CALayers, jadi kami bisatake advantage of AutoresizingMasks memastikan batas ukuran diubah bersama dengan superview.
Sejauh ini, ini adalah salah satu solusi terbaik untuk masalah ini. Sebagian besar dari solusi lain yang ditawarkan TIDAK menghormati perubahan tampilan (dan karenanya rotasi perangkat atau Tampilan Split). Yang ini.
Womble
1
bagaimana ini bisa disesuaikan untuk mendukung sudut membulat?
Ini tidak berfungsi saat tampilan diubah ukurannya, mis. Perubahan orientasi.
Nestor
Jika Anda menggunakan tata letak berbasis bingkai maka Anda harus menerapkan layoutSubviews dan menghitung ulang semua frame subview (atau sublayer) di sana
trapper
22
Subkelas UIViewdan implementasikan drawRect:di dalam subkelas Anda, misalnya:
Apakah itu satu-satunya cara untuk itu ??? Jadi jika saya perlu membuat tampilan dengan batas atas, dan tampilan lain dengan batas bawah, dan tampilan lainnya ... Maksud saya selalu tampilan khusus dengan satu perbatasan, atau dua, saya harus membuat subkelas untuk setiap kasus tertentu ??? Saya tidak tahu apakah itu benar-benar baik untuk membuat kelas hanya untuk menambahkan perbatasan ...
manonthemoon
1
Pikirkan itu. UIViewSubkelas Anda dapat memiliki properti yang menentukan batas yang drawRect:diambil. Properti ini dapat didefinisikan dengan NS_OPTIONSsehingga mendefinisikan bitmask seperti UIViewAutoresizingbitmask. Jika - untuk alasan apa pun - Anda benar-benar keberatan dengan subklas UIViewmaka tambahkan saja subview tinggi 1-2 piksel kecil (atau lebar) dan berikan dimensi apa pun yang Anda inginkan untuk mensimulasikan batas.
Solusi mudah langsung ... dengan overhead UIView dibandingkan dengan telanjang CALayer
Soberman
setelah membaca semua solusi lain saya berpikir saya hanya akan menambah tampilan kecil juga. Semua itu berfungsi untuk perbatasan! Solusi ini hanya memerlukan beberapa pin untuk bekerja dalam tata letak otomatis juga. Jauh lebih mudah untuk menggerakkan kepala Anda.
noobsmcgoobs
Terima kasih, saya menambahkan catatan di atas sehingga coders hanya akan digunakan jika aplikasi mereka tidak berputar.
Travis M.
15
Pertanyaan lama, tetapi solusi autolayout-dengan penyesuaian batas runtime masih hilang.
borders(for:[.left,.bottom], width:2, color:.red)
Ekstensi UIView berikut hanya akan menambahkan batas pada tepi yang diberikan. Jika Anda mengubah tepi saat runtime, perbatasan akan menyesuaikan.
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]))}}}}}
Saya mengambil jawaban Adam Waite dan Paul dan menggabungkannya. Saya juga menambahkan kemungkinan untuk menyatukan tepi yang dipilih, jadi Anda hanya perlu memanggil satu fungsi seperti ini:
Saya mencari solusi yang ditawarkan. Banyak yang berbasis di bingkai Ini adalah ekstensi sederhana yang berfungsi dengan AutoLayout - gunakan View alih-alih Layer untuk memastikan kita dapat menggunakan AutoLayout - Subview tunggal dengan 4 kendala
Membangun dari jawaban NSBum , saya mengambil pendekatan yang sama dan membuat subkelas UIView sederhana ini sehingga bekerja di Interface Builder dan bekerja dengan kendala: github link
Dengan menggunakan CGContextFillRect, bukannya CGContextStrokePath, saya bisa memprediksi garis-garisnya tetap solid dan utuh. batas tampilan.
- Pada dasarnya hanya memasukkan UIView di Interface Builder dan mengubah jenis kelasnya menjadi NAUIViewWithBorders.
- Kemudian pada viewDidLoad VC Anda lakukan sesuatu seperti:
/* 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];
Berikut ini tautan langsung ke file .m sehingga Anda dapat melihat implementasinya. Ada proyek demo juga. Semoga ini bisa membantu seseorang :)
Jawaban saya untuk pertanyaan serupa: https://stackoverflow.com/a/27141956/435766
Saya pribadi lebih suka menuruni kategori jalan yang satu itu, karena saya ingin dapat menggunakannya pada subkelas UIView.
Inilah solusi sederhana. Tambahkan label ke Anda UIView, hapus teks pada label dan atur warna latar belakang label menjadi warna tepi Anda. Tetapkan asal (x,y)label Anda menjadi asal (x,y)tampilan Anda. dan atur lebar label menjadi lebar Anda UIView, atur tingginya menjadi 1 atau 2 (untuk tinggi tepi di bagian atas Anda UIView). Dan itu harus melakukan trik.
Tidak ada gunanya memiliki label, mungkin saja hanya UIView lain
maor10
1
Ini tidak benar-benar menjawab pertanyaan menambahkan hanya perbatasan atas ke uiview. Ini adalah perbaikan cepat yang mungkin tidak akan berhasil untuk masalah yang lebih kompleks.
Apakah akan memanggil 'addSublayer' setiap kali tata letak mendapat pembaruan?
Janeevan
1
Cukup posting di sini untuk membantu seseorang yang mencari batas tambahan. Saya telah membuat beberapa perubahan pada jawaban yang diterima di sini, hanya label cepat yang tersisa . Berubah lebar dalam kasusUIRectEdge.Top dari CGRectGetHeight(self.frame)ke CGRectGetWidth(self.frame)dan dalam kasus UIRectEdge.Bottomdari UIScreen.mainScreen().bounds.widthkeCGRectGetWidth(self.frame) untuk mendapatkan perbatasan dengan benar. Menggunakan Swift 2.
Terinspirasi oleh @Addison, saya telah menulis ulang ekstensi tanpa menggunakan kerangka kerja pihak ketiga, karena ia menggunakan SnapKit dan CocoaLumberjack.
Seperti dalam pendekatan @Addisons, saya juga menghapus batas yang ditambahkan sebelumnya, jadi implementasi ini harus bermain bagus dengan tampilan yang dapat digunakan kembali sebagai sel tabel dan sel koleksi.
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
}}
Jika saya membangun dari dalam storyboard, saya lebih suka menambahkan di UIViewbelakang berguna saya UIView... Jika saya ingin membuat perbatasan di atas saya UIView, saya hanya menambah ketinggian latar belakang UIViewdengan lebar perbatasan saya .. kaleng yang sama dilakukan untuk sisi lain :)
Secara pribadi saya suka sub-classing dari view + drawRect, tapi ini hanya cara lain untuk menyelesaikannya (dan ini berfungsi sesuai dengan jawaban yang diterima oleh @If Pollavith):
Lapisan perbatasan baru Anda dapat diatur untuk memiliki dimensi apa pun yang Anda suka. Jadi, seperti jawaban @Jika Pollavith, Anda membuat layer setinggi yang Anda inginkan, dan selebar tampilan yang ingin Anda bataskan. Gunakan definisi bingkai layer untuk menempatkannya di tempat yang Anda inginkan, dan kemudian menambahkannya sebagai sub-layer ke tampilan Anda.
Untuk referensi, persyaratan saya sendiri adalah menempatkan perbatasan di sisi LEFT-HAND dari tampilan (tolong jangan memotong dan menempelkan kode ini dan dis 'me just' karena tidak menempatkan perbatasan di bagian atas tampilan - memodifikasi kode di bawah ini cukup sederhana):
Saya kira satu-satunya manfaat moderat atas ini dan membuat UIView atau UILabel kecil adalah bahwa CALayer seharusnya 'lebih ringan', dan ada banyak pandangan menarik (seperti pendapat) tentang pengundian undian yang berlebihanRect versus menggunakan CALayers (seperti di sini : iOS: Menggunakan 'drawRect:' UIView vs. delagate layernya 'drawLayer: inContext:' ).
Selain n8tr dapat menambahkan bahwa ada ketersediaan untuk mengaturnya dari storyboard baik:
- tambahkan dua properti seperti borderColordan borderWidthdalam file .h;
- maka Anda dapat menambahkan keyPathstepat di storyboard, lihat tautan ke tangkapan layar
Catatan: sebagian besar solusi di sini tidak adaptif dan tidak akan mengubah ukuran. Solusi yang akan mengubah ukuran akan berdampak besar pada waktu startup Anda karena mereka menggunakan banyak CPU.
Anda dapat menggunakan solusi ini di bawah. Ia bekerja pada UIBezierPaths yang lebih ringan dari lapisan, menyebabkan waktu startup yang cepat. Mudah digunakan, lihat instruksi di bawah.
Jawaban:
Saya menganggap subclassing
UIView
dandrawRect
overkill overkill di sini. Mengapa tidak menambahkan ekstensiUIView
dan menambahkan subview perbatasan?Dengan kode ini Anda tidak terikat dengan subkelas Anda juga, Anda dapat menerapkannya pada apa saja dan semua yang diwarisi dari
UIView
- dapat digunakan kembali dalam proyek Anda, dan yang lainnya. Berikan argumen lain ke metode Anda untuk menentukan warna dan lebar lain. Banyak pilihan.sumber
Menambahkan kemampuan untuk sudut membulat ke pos asli Adam Waite, dan beberapa pengeditan
Penting !: Jangan lupa menambahkan '
label.layoutIfNeeded()
' tepat sebelum memanggil 'addborder' seperti yang dikomentari sebelumnyaCatatan: Saya baru menguji ini
UILabels
.sumber
view.layoutIfNeeded()
tepat sebelum memanggilview.layer.addBorder(...)
. Kemudian ia bekerja di Swift 3override func viewDidLayoutSubviews()
Cara terbaik bagi saya adalah kategori di UIView, tapi
adding views
bukannya CALayers, jadi kami bisatake advantage of AutoresizingMasks
memastikan batas ukuran diubah bersama dengan superview.Tujuan C
Cepat 5
sumber
Swift 3.0
Cepat 4.1
sumber
Subkelas
UIView
dan implementasikandrawRect:
di dalam subkelas Anda, misalnya:Objektif-c
Cepat 4
Ini menarik garis merah 2 pixel sebagai batas atas. Semua variasi lain yang Anda sebutkan dibiarkan sebagai latihan sepele bagi pembaca.
Panduan Pemrograman Kuarsa 2D direkomendasikan.
sumber
UIView
Subkelas Anda dapat memiliki properti yang menentukan batas yangdrawRect:
diambil. Properti ini dapat didefinisikan denganNS_OPTIONS
sehingga mendefinisikan bitmask sepertiUIViewAutoresizing
bitmask. Jika - untuk alasan apa pun - Anda benar-benar keberatan dengan subklasUIView
maka tambahkan saja subview tinggi 1-2 piksel kecil (atau lebar) dan berikan dimensi apa pun yang Anda inginkan untuk mensimulasikan batas.Kode untuk jawaban yang dipilih, kalau-kalau ada yang menginginkannya.
CATATAN: Ini tidak berfungsi dengan pembayaran otomatis (alias, perangkat yang berputar ke lanskap, dll).
Pertama-tama tentukan ketebalan:
Kemudian salin saja menggunakan salah satu atau semua ini untuk mengatur batas yang ingin Anda atur.
Batas atas
Batas Bawah
Batas Kiri
Perbatasan Kanan
sumber
Pertanyaan lama, tetapi solusi autolayout-dengan penyesuaian batas runtime masih hilang.
Ekstensi UIView berikut hanya akan menambahkan batas pada tepi yang diberikan. Jika Anda mengubah tepi saat runtime, perbatasan akan menyesuaikan.
sumber
Versi cepat:
Sunting: Untuk versi terbaru, periksa repo saya di sini: https://github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/UIViewExtensions.swift
Lihatlah bagian addBorder
sumber
Saya mengambil jawaban Adam Waite dan Paul dan menggabungkannya. Saya juga menambahkan kemungkinan untuk menyatukan tepi yang dipilih, jadi Anda hanya perlu memanggil satu fungsi seperti ini:
atau lebih:
Yang perlu Anda terapkan adalah kategori pada UIView seperti yang disarankan dalam jawaban lain dengan implementasi berikut:
sumber
// MARK: - Tambahkan LeftBorder For View
// MARK: - Tambahkan RightBorder For View
// MARK: - Tambahkan Batas Bawah Untuk Tampilan
sumber
Swift 4.2 dan AutoLayout
Saya mencari solusi yang ditawarkan. Banyak yang berbasis di bingkai Ini adalah ekstensi sederhana yang berfungsi dengan AutoLayout - gunakan View alih-alih Layer untuk memastikan kita dapat menggunakan AutoLayout - Subview tunggal dengan 4 kendala
Gunakan sebagai berikut:
sumber
Saya membuat beberapa perubahan pada jawaban Dan sehingga saya bisa menambahkan batas ke beberapa sisi dengan satu perintah:
Berikut kode lengkapnya:
sumber
Membangun dari jawaban NSBum , saya mengambil pendekatan yang sama dan membuat subkelas UIView sederhana ini sehingga bekerja di Interface Builder dan bekerja dengan kendala: github link
Dengan menggunakan CGContextFillRect, bukannya CGContextStrokePath, saya bisa memprediksi garis-garisnya tetap solid dan utuh. batas tampilan.
Inilah posting blog saya tentang hal itu: http://natrosoft.com/?p=55
- Pada dasarnya hanya memasukkan UIView di Interface Builder dan mengubah jenis kelasnya menjadi NAUIViewWithBorders.
- Kemudian pada viewDidLoad VC Anda lakukan sesuatu seperti:
Berikut ini tautan langsung ke file .m sehingga Anda dapat melihat implementasinya. Ada proyek demo juga. Semoga ini bisa membantu seseorang :)
sumber
Jawaban saya untuk pertanyaan serupa: https://stackoverflow.com/a/27141956/435766 Saya pribadi lebih suka menuruni kategori jalan yang satu itu, karena saya ingin dapat menggunakannya pada subkelas UIView.
sumber
sumber
Inilah solusi sederhana. Tambahkan label ke Anda
UIView
, hapus teks pada label dan atur warna latar belakang label menjadi warna tepi Anda. Tetapkan asal(x,y)
label Anda menjadi asal(x,y)
tampilan Anda. dan atur lebar label menjadi lebar AndaUIView
, atur tingginya menjadi 1 atau 2 (untuk tinggi tepi di bagian atas AndaUIView
). Dan itu harus melakukan trik.sumber
Versi Swift 3
Untuk menetapkan batas yang sesuai, Anda harus mengganti metode viewDidLayoutSubviews () :
sumber
Cukup posting di sini untuk membantu seseorang yang mencari batas tambahan. Saya telah membuat beberapa perubahan pada jawaban yang diterima di sini, hanya label cepat yang tersisa . Berubah lebar dalam kasus
UIRectEdge.Top
dariCGRectGetHeight(self.frame)
keCGRectGetWidth(self.frame)
dan dalam kasusUIRectEdge.Bottom
dariUIScreen.mainScreen().bounds.width
keCGRectGetWidth(self.frame)
untuk mendapatkan perbatasan dengan benar. Menggunakan Swift 2.Akhirnya ekstensinya adalah:
sumber
Jika seseorang membutuhkan versi Xamarin:
sumber
Inilah versi Swift 4 dari jawaban Pauls
sumber
Terinspirasi oleh @Addison, saya telah menulis ulang ekstensi tanpa menggunakan kerangka kerja pihak ketiga, karena ia menggunakan SnapKit dan CocoaLumberjack.
Seperti dalam pendekatan @Addisons, saya juga menghapus batas yang ditambahkan sebelumnya, jadi implementasi ini harus bermain bagus dengan tampilan yang dapat digunakan kembali sebagai sel tabel dan sel koleksi.
sumber
Jika saya membangun dari dalam storyboard, saya lebih suka menambahkan di
UIView
belakang berguna sayaUIView
... Jika saya ingin membuat perbatasan di atas sayaUIView
, saya hanya menambah ketinggian latar belakangUIView
dengan lebar perbatasan saya .. kaleng yang sama dilakukan untuk sisi lain :)sumber
Secara pribadi saya suka sub-classing dari view + drawRect, tapi ini hanya cara lain untuk menyelesaikannya (dan ini berfungsi sesuai dengan jawaban yang diterima oleh @If Pollavith):
Lapisan perbatasan baru Anda dapat diatur untuk memiliki dimensi apa pun yang Anda suka. Jadi, seperti jawaban @Jika Pollavith, Anda membuat layer setinggi yang Anda inginkan, dan selebar tampilan yang ingin Anda bataskan. Gunakan definisi bingkai layer untuk menempatkannya di tempat yang Anda inginkan, dan kemudian menambahkannya sebagai sub-layer ke tampilan Anda.
Untuk referensi, persyaratan saya sendiri adalah menempatkan perbatasan di sisi LEFT-HAND dari tampilan (tolong jangan memotong dan menempelkan kode ini dan dis 'me just' karena tidak menempatkan perbatasan di bagian atas tampilan - memodifikasi kode di bawah ini cukup sederhana):
Saya kira satu-satunya manfaat moderat atas ini dan membuat UIView atau UILabel kecil adalah bahwa CALayer seharusnya 'lebih ringan', dan ada banyak pandangan menarik (seperti pendapat) tentang pengundian undian yang berlebihanRect versus menggunakan CALayers (seperti di sini : iOS: Menggunakan 'drawRect:' UIView vs. delagate layernya 'drawLayer: inContext:' ).
Animal451
Saya suka warna biru.
sumber
Selain n8tr dapat menambahkan bahwa ada ketersediaan untuk mengaturnya dari storyboard baik:
- tambahkan dua properti seperti
borderColor
danborderWidth
dalam file .h;- maka Anda dapat menambahkan
keyPaths
tepat di storyboard, lihat tautan ke tangkapan layarsumber
Konversi jawaban DanShev ke Swift 3
sumber
Untuk Xamarin di C # saya hanya membuat garis sebaris saat menambahkan sub lapisan
Anda dapat mengatur ini (seperti yang disarankan oleh orang lain) untuk batas bawah, kiri dan kanan.
sumber
Anda juga dapat memeriksa koleksi kategori UIKit dan Yayasan ini: https://github.com/leszek-s/LSCategories
Ini memungkinkan penambahan batas di satu sisi UIView dengan satu baris kode:
dan itu benar menangani rotasi tampilan sementara sebagian besar jawaban yang diposting di sini tidak menanganinya dengan baik.
sumber
Catatan: sebagian besar solusi di sini tidak adaptif dan tidak akan mengubah ukuran. Solusi yang akan mengubah ukuran akan berdampak besar pada waktu startup Anda karena mereka menggunakan banyak CPU.
Anda dapat menggunakan solusi ini di bawah. Ia bekerja pada UIBezierPaths yang lebih ringan dari lapisan, menyebabkan waktu startup yang cepat. Mudah digunakan, lihat instruksi di bawah.
sumber
Untuk mengatur Batas Atas dan Batas Bawah untuk UIView di Swift.
sumber
Dalam Swift 4 dan 3
sumber