Câu hỏi của tôi là về tiêu đề.
Tôi không biết cách thêm đường viền ở một bên cụ thể, trên cùng hoặc dưới cùng, bất kỳ bên nào ...
layer.border
vẽ đường viền cho toàn bộ chế độ xem ...
Câu hỏi của tôi là về tiêu đề.
Tôi không biết cách thêm đường viền ở một bên cụ thể, trên cùng hoặc dưới cùng, bất kỳ bên nào ...
layer.border
vẽ đường viền cho toàn bộ chế độ xem ...
Câu trả lời:
Tôi xem xét phân lớp UIView
và ghi đè drawRect
quá mức cần thiết ở đây. Tại sao không thêm một phần mở rộng trên UIView
và thêm các cuộc phỏng vấn biên giới?
@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
Với mã này, bạn cũng không bị ràng buộc với lớp con của mình, bạn có thể áp dụng nó cho bất kỳ thứ gì và mọi thứ thừa hưởng từ UIView
- có thể tái sử dụng trong dự án của bạn và bất kỳ loại nào khác. Truyền các đối số khác cho các phương thức của bạn để xác định các màu và độ rộng khác. Nhiều lựa chọn.
Đã thêm khả năng cho các góc được làm tròn vào bài đăng gốc của Adam Waite và nhiều chỉnh sửa
Quan trọng!: Đừng quên thêm 'nhãn.layout IfNeeded ()' ngay trước khi gọi 'addborder' như đã nhận xét trước đó
Lưu ý: Tôi chỉ thử nghiệm điều này trên UILabels.
tiện ích mở rộng {
enum BorderSide {
case top
case right
case bottom
case left
case notRight
case notLeft
case topAndBottom
case all
}
enum Corner {
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 offsets
switch 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 sides
switch 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 Sides
case .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/2
switch corner {
case .bottomLeft: startAngle = .pi/2; endAngle = .pi
case .bottomRight:
x = width - cornerRadius
startAngle = 0; endAngle = .pi/2
case .topRight:
x = width - cornerRadius
startAngle = .pi*3/2; endAngle = 0
default: 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)
}
}
view.layoutIfNeeded()
ngay trước khi gọi view.layer.addBorder(...)
. Sau đó, nó hoạt động trong Swift 3
override func viewDidLayoutSubviews()
Cách tốt nhất đối với tôi là một danh mục trên UIView, nhưng adding views
thay vì CALayers, vì vậy chúng tôi có thể take advantage of AutoresizingMasks
đảm bảo các đường viền thay đổi kích thước cùng với giám sát.
Mục tiêu C
- (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin];
border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth);
[self addSubview:border];
}
- (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth);
[self addSubview:border];
}
- (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
UIView *border = [UIView new];
border.backgroundColor = color;
border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height);
[border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin];
[self addSubview:border];
}
- (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin];
border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height);
[self addSubview:border];
}
Swift 5
func addTopBorder(with color: UIColor?, andWidth borderWidth: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin]
border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: borderWidth)
addSubview(border)
}
func addBottomBorder(with color: UIColor?, andWidth borderWidth: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
border.frame = CGRect(x: 0, y: frame.size.height - borderWidth, width: frame.size.width, height: borderWidth)
addSubview(border)
}
func addLeftBorder(with color: UIColor?, andWidth borderWidth: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.frame = CGRect(x: 0, y: 0, width: borderWidth, height: frame.size.height)
border.autoresizingMask = [.flexibleHeight, .flexibleRightMargin]
addSubview(border)
}
func addRightBorder(with color: UIColor?, andWidth borderWidth: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleHeight, .flexibleLeftMargin]
border.frame = CGRect(x: frame.size.width - borderWidth, y: 0, width: borderWidth, height: frame.size.height)
addSubview(border)
}
Swift 3.0
Swift 4.1
extension CALayer {
func addBorder(edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer()
switch edge {
case UIRectEdge.top:
border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
case UIRectEdge.bottom:
border.frame = CGRect(x:0, y: frame.height - thickness, width: frame.width, height:thickness)
case UIRectEdge.left:
border.frame = CGRect(x:0, y:0, width: thickness, height: frame.height)
case UIRectEdge.right:
border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
default: do {}
}
border.backgroundColor = color.cgColor
addSublayer(border)
}
}
Lớp con UIView
và thực hiện drawRect:
trong lớp con của bạn, ví dụ:
Mục tiêu-c
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGContextSetStrokeColorWithColor(context, [[UIColor redColor] CGColor] );
CGContextSetLineWidth(context, 2.0);
CGContextStrokePath(context);
}
Swift 4
override func draw(_ rect: CGRect) {
let cgContext = UIGraphicsGetCurrentContext()
cgContext?.move(to: CGPoint(x: rect.minX, y: rect.minY))
cgContext?.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
cgContext?.setStrokeColor(UIColor.red.cgColor)
cgContext?.setLineWidth(2.0)
cgContext?.strokePath()
}
Điều này vẽ một đường màu đỏ 2 pixel làm đường viền trên cùng. Tất cả các biến thể khác mà bạn đề cập đều để lại như một bài tập tầm thường cho người đọc.
Hướng dẫn lập trình Quartz 2D được khuyến khích.
UIView
Lớp con của bạn có thể có một thuộc tính xác định đường viền drawRect:
vẽ gì . Thuộc tính này có thể được định nghĩa NS_OPTIONS
để nó định nghĩa một bitmask như UIViewAutoresizing
bitmask. Nếu - vì bất kỳ lý do gì - bạn thực sự phản đối mạnh mẽ việc phân lớp UIView
thì chỉ cần thêm một khung nhìn nhỏ (hoặc rộng) cao 1-2 pixel và cung cấp cho nó bất kỳ kích thước nào bạn muốn mô phỏng đường viền.
Mã cho câu trả lời được chọn, trong trường hợp bất cứ ai muốn nó.
LƯU Ý: Điều này không hoạt động với tự động thanh toán (hay còn gọi là thiết bị xoay sang ngang, v.v.).
Đầu tiên xác định độ dày:
NSInteger borderThickness = 1;
Sau đó, chỉ cần sao chép sử dụng bất kỳ hoặc tất cả những thứ này để đặt đường viền bạn muốn đặt.
Biên giới hàng đầu
UIView *topBorder = [UIView new];
topBorder.backgroundColor = [UIColor lightGrayColor];
topBorder.frame = CGRectMake(0, 0, myView.frame.size.width, borderThickness);
[myView addSubview:topBorder];
Biên giới dưới cùng
UIView *bottomBorder = [UIView new];
bottomBorder.backgroundColor = [UIColor lightGrayColor];
bottomBorder.frame = CGRectMake(0, myView.frame.size.height - borderThickness, myView.frame.size.width, borderThickness);
[myView addSubview:bottomBorder];
Biên giới trái
UIView *leftBorder = [UIView new];
leftBorder.backgroundColor = [UIColor lightGrayColor];
leftBorder.frame = CGRectMake(0, 0, borderThickness, myView.frame.size.height);
[myView addSubview:leftBorder];
Biên giới phải
UIView *rightBorder = [UIView new];
rightBorder.backgroundColor = [UIColor lightGrayColor];
rightBorder.frame = CGRectMake(myView.frame.size.width - borderThickness, 0, borderThickness, myView.frame.size.height);
[myView addSubview:rightBorder];
Câu hỏi cũ, nhưng giải pháp tự động thanh toán với các điều chỉnh biên thời gian chạy vẫn còn thiếu.
borders(for: [.left, .bottom], width: 2, color: .red)
Phần mở rộng UIView sau đây sẽ chỉ thêm đường viền trên các cạnh đã cho. Nếu bạn thay đổi các cạnh trong thời gian chạy, các đường viền sẽ điều chỉnh tương ứng.
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 {
case UIRectEdge.bottom:
horizontalVisualFormat += "|-(0)-[v]-(0)-|"
verticalVisualFormat += "[v(\(width))]-(0)-|"
case UIRectEdge.top:
horizontalVisualFormat += "|-(0)-[v]-(0)-|"
verticalVisualFormat += "|-(0)-[v(\(width))]"
case UIRectEdge.left:
horizontalVisualFormat += "|-(0)-[v(\(width))]"
verticalVisualFormat += "|-(0)-[v]-(0)-|"
case UIRectEdge.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]))
}
}
}
}
}
Phiên bản Swift:
var myView = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
myView.backgroundColor = UIColor.yellowColor()
var border = CALayer()
border.backgroundColor = UIColor.lightGrayColor()
border.frame = CGRect(x: 0, y: 0, width: myView.frame.width, height: 0.5)
myView.layer.addSublayer(border)
Chỉnh sửa: Đối với các phiên bản cập nhật, hãy kiểm tra repo của tôi tại đây: https://github.com/goktugyil/EZSwiftExtensions/blob/master/Source/UIViewExtensions.swift
Nhìn vào các phần addBorder
Tôi lấy cả câu trả lời của Adam Waite và Pauls và kết hợp chúng lại. Tôi cũng đã thêm khả năng nối các cạnh đã chọn với nhau, vì vậy bạn chỉ cần gọi một chức năng như vậy:
[self.view addBordersToEdge:(UIRectEdgeLeft|UIRectEdgeRight)
withColor:[UIColor grayColor]
andWidth:1.0];
hoặc là:
[self.view addBordersToEdge:(UIRectEdgeAll)
withColor:[UIColor grayColor]
andWidth:1.0];
Những gì bạn cần triển khai là một danh mục trên UIView như được đề xuất trong các câu trả lời khác với cách thực hiện sau:
- (void)addBordersToEdge:(UIRectEdge)edge withColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
if (edge & UIRectEdgeTop) {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin];
border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth);
[self addSubview:border];
}
if (edge & UIRectEdgeLeft) {
UIView *border = [UIView new];
border.backgroundColor = color;
border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height);
[border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin];
[self addSubview:border];
}
if (edge & UIRectEdgeBottom) {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth);
[self addSubview:border];
}
if (edge & UIRectEdgeRight) {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin];
border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height);
[self addSubview:border];
}
}
// Đánh dấu: - Thêm LeftBorder để xem
(void)prefix_addLeftBorder:(UIView *) viewName
{
CALayer *leftBorder = [CALayer layer];
leftBorder.backgroundColor = [UIColor colorWithRed:221/255.0f green:221/255.0f blue:221/255.0f alpha:1.0f].CGColor;
leftBorder.frame = CGRectMake(0,0,1.0,viewName.frame.size.height);
[viewName.layer addSublayer:leftBorder];
}
// Đánh dấu: - Thêm RightBorder để xem
(void)prefix_addRightBorder:(UIView *) viewName
{
CALayer *rightBorder = [CALayer layer];
rightBorder.backgroundColor = [UIColor colorWithRed:221/255.0f green:221/255.0f blue:221/255.0f alpha:1.0f].CGColor;
rightBorder.frame = CGRectMake(viewName.frame.size.width - 1.0,0,1.0,viewName.frame.size.height);
[viewName.layer addSublayer:rightBorder];
}
// Đánh dấu: - Thêm viền dưới để xem
(void)prefix_addbottomBorder:(UIView *) viewName
{
CALayer *bottomBorder = [CALayer layer];
bottomBorder.backgroundColor = [UIColor colorWithRed:221/255.0f green:221/255.0f blue:221/255.0f alpha:1.0f].CGColor;
bottomBorder.frame = CGRectMake(0,viewName.frame.size.height - 1.0,viewName.frame.size.width,1.0);
[viewName.layer addSublayer:bottomBorder];
}
Swift 4.2 và Tự động thanh toán
Tôi đã đi qua các giải pháp được cung cấp. Nhiều người dựa trên các khung Đây là một tiện ích mở rộng đơn giản hoạt động với AutoLayout - sử dụng View thay vì Layer để đảm bảo chúng ta có thể sử dụng AutoLayout - Subview đơn với 4 ràng buộc
Sử dụng như sau:
self.addBorder(.bottom, color: .lightGray, thickness: 0.5)
extension UIView {
func addBorder(_ edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let subview = UIView()
subview.translatesAutoresizingMaskIntoConstraints = false
subview.backgroundColor = color
self.addSubview(subview)
switch edge {
case .top, .bottom:
subview.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0).isActive = true
subview.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0).isActive = true
subview.heightAnchor.constraint(equalToConstant: thickness).isActive = true
if edge == .top {
subview.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
} else {
subview.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
}
case .left, .right:
subview.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
subview.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
subview.widthAnchor.constraint(equalToConstant: thickness).isActive = true
if edge == .left {
subview.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0).isActive = true
} else {
subview.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0).isActive = true
}
default:
break
}
}
}
Tôi đã thực hiện một số thay đổi cho câu trả lời của Dan để tôi có thể thêm viền vào nhiều cạnh bằng một lệnh:
infoView.addBorder(toEdges: [.left, .bottom, .right], color: borderColor, thickness: 1)
Đây là mã đầy đủ:
extension UIView {
func addBorder(toEdges edges: UIRectEdge, color: UIColor, thickness: CGFloat) {
func addBorder(toEdge edges: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer()
border.backgroundColor = color.cgColor
switch edges {
case .top:
border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
case .bottom:
border.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness)
case .left:
border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.height)
case .right:
border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
default:
break
}
layer.addSublayer(border)
}
if edges.contains(.top) || edges.contains(.all) {
addBorder(toEdge: .top, color: color, thickness: thickness)
}
if edges.contains(.bottom) || edges.contains(.all) {
addBorder(toEdge: .bottom, color: color, thickness: thickness)
}
if edges.contains(.left) || edges.contains(.all) {
addBorder(toEdge: .left, color: color, thickness: thickness)
}
if edges.contains(.right) || edges.contains(.all) {
addBorder(toEdge: .right, color: color, thickness: thickness)
}
}
}
Dựa trên câu trả lời của NSBum , tôi đã sử dụng một cách tiếp cận tương tự và tạo lớp con UIView đơn giản này để nó hoạt động trong Trình tạo giao diện và hoạt động với các ràng buộc: liên kết github
Bằng cách sử dụng CGContextFillRect thay vì CGContextStrokePath, tôi có thể dự đoán được các dòng hoàn toàn chắc chắn và bên trong giới hạn của quan điểm.
Đây là bài viết trên blog của tôi về nó: http://natrosoft.com/?p=55
- Về cơ bản chỉ cần thả một UIView trong Trình tạo giao diện và thay đổi loại lớp của nó thành NAUIViewWithBnings.
- Sau đó, trong viewDidLoad của VC, hãy thực hiện một số thứ như:
/* 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];
Đây là một liên kết trực tiếp đến tệp .m để bạn có thể thấy việc thực hiện. Có một dự án demo là tốt. Hy vọng điều này sẽ giúp được ai đó :)
Câu trả lời của tôi cho một câu hỏi tương tự: https://stackoverflow.com/a/27141956/435766 Cá nhân tôi thích đi xuống con đường danh mục trên đó, vì tôi muốn có thể sử dụng nó trên bất kỳ lớp con nào của UIView.
extension UIView {
func addBorder(edge: UIRectEdge, color: UIColor, borderWidth: CGFloat) {
let seperator = UIView()
self.addSubview(seperator)
seperator.translatesAutoresizingMaskIntoConstraints = false
seperator.backgroundColor = color
if edge == .top || edge == .bottom
{
seperator.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
seperator.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
seperator.heightAnchor.constraint(equalToConstant: borderWidth).isActive = true
if edge == .top
{
seperator.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
}
else
{
seperator.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
}
}
else if edge == .left || edge == .right
{
seperator.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
seperator.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
seperator.widthAnchor.constraint(equalToConstant: borderWidth).isActive = true
if edge == .left
{
seperator.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
}
else
{
seperator.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
}
}
}
}
Đây là một giải pháp đơn giản. Thêm nhãn vào của bạn UIView
, xóa văn bản trên nhãn và đặt màu nền của nhãn là màu đường viền của bạn. Đặt nguồn gốc (x,y)
nhãn của bạn là gốc (x,y)
của chế độ xem của bạn. và đặt chiều rộng của nhãn là chiều rộng của bạn UIView
, đặt chiều cao là 1 hoặc 2 (đối với chiều cao đường viền của bạn ở trên cùng của bạn UIView
). Và điều đó nên làm các mẹo.
Phiên bản Swift 3
extension UIView {
enum ViewSide {
case Top, Bottom, Left, Right
}
func addBorder(toSide side: ViewSide, withColor color: UIColor, andThickness thickness: CGFloat) {
let border = CALayer()
border.backgroundColor = color.cgColor
switch side {
case .Top:
border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: thickness)
case .Bottom:
border.frame = CGRect(x: 0, y: frame.size.height - thickness, width: frame.size.width, height: thickness)
case .Left:
border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.size.height)
case .Right:
border.frame = CGRect(x: frame.size.width - thickness, y: 0, width: thickness, height: frame.size.height)
}
layer.addSublayer(border)
}
}
Để đặt đường viền tương ứng, bạn nên ghi đè phương thức viewDidLayoutSubviews () :
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
yourView.addBorder(toSide: UIView.ViewSide.Top, withColor: UIColor.lightGray, andThickness: 1)
Chỉ cần đăng ở đây để giúp ai đó tìm kiếm thêm biên giới. Tôi đã thực hiện một vài thay đổi trong câu trả lời được chấp nhận ở đây chỉ còn lại nhãn . Thay đổi chiều rộng trong trường hợp UIRectEdge.Top
từ CGRectGetHeight(self.frame)
để CGRectGetWidth(self.frame)
và trong trường hợp UIRectEdge.Bottom
từ UIScreen.mainScreen().bounds.width
để CGRectGetWidth(self.frame)
để có được biên giới một cách chính xác. Sử dụng Swift 2.
Cuối cùng, phần mở rộng là:
extension CALayer {
func addBorder(edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer();
switch edge {
case UIRectEdge.Top:
border.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), thickness);
break
case UIRectEdge.Bottom:
border.frame = CGRectMake(0, CGRectGetHeight(self.frame) - thickness, CGRectGetWidth(self.frame), thickness)
break
case UIRectEdge.Left:
border.frame = CGRectMake(0, 0, thickness, CGRectGetHeight(self.frame))
break
case UIRectEdge.Right:
border.frame = CGRectMake(CGRectGetWidth(self.frame) - thickness, 0, thickness, CGRectGetHeight(self.frame))
break
default:
break
}
border.backgroundColor = color.CGColor;
self.addSublayer(border)
}
}
Trong trường hợp ai đó sẽ cần phiên bản Xamarin:
public static class UIUtils
{
public static void AddBorder(this CALayer cALayer, UIRectEdge edge, UIColor color, float thickness)
{
var border = new CALayer();
switch (edge)
{
case UIRectEdge.Top:
border.Frame = new CGRect(0, 0, cALayer.Frame.Width, height: thickness);
break;
case UIRectEdge.Bottom:
border.Frame = new CGRect(0, cALayer.Frame.Height - thickness, width: cALayer.Frame.Width, height: thickness);
break;
case UIRectEdge.Left:
border.Frame = new CGRect(0, 0, width: thickness, height: cALayer.Frame.Height);
break;
case UIRectEdge.Right:
border.Frame = new CGRect(cALayer.Frame.Width - thickness, y: 0, width: thickness, height: cALayer.Frame.Height);
break;
default: break;
}
border.BackgroundColor = color.CGColor;
cALayer.AddSublayer(border);
}
}
Đây là phiên bản Swift 4 của câu trả lời của Pauls
func addTopBorder(color: UIColor, thickness: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin]
border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: thickness)
addSubview(border)
}
func addBottomBorder(color: UIColor, thickness: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
border.frame = CGRect(x: 0, y: frame.size.height - thickness, width: frame.size.width, height: thickness)
addSubview(border)
}
func addLeftBorder(color: UIColor, thickness: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleHeight, .flexibleRightMargin]
border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.size.height)
addSubview(border)
}
func addRightBorder(color: UIColor, thickness: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleHeight, .flexibleLeftMargin]
border.frame = CGRect(x: frame.size.width - thickness, y: 0, width: thickness, height: frame.size.height)
addSubview(border)
}
Lấy cảm hứng từ @Addison Tôi đã viết lại tiện ích mở rộng mà không sử dụng bất kỳ khuôn khổ bên thứ ba nào, khi anh ấy sử dụng SnapKit và CocoaLumberjack.
Như trong cách tiếp cận @Addisons, tôi cũng loại bỏ các đường viền được thêm trước đó, vì vậy việc triển khai này sẽ hoạt động tốt với các khung nhìn có thể sử dụng lại như các ô của bảng và các ô thu thập.
fileprivate class BorderView: 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 edges
for view in subviews {
if view is BorderView {
view.removeFromSuperview()
}
}
// Add new edges
if 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 = false
switch 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) ])
}
}
}
private enum RectangularEdges {
case left
case right
case top
case bottom
}
}
Nếu tôi xây dựng từ bên trong bảng phân cảnh, tôi thích thêm phần UIView
phía sau hữu ích của mình UIView
... Nếu tôi muốn tạo một đường viền trên đỉnh của mình UIView
, tôi chỉ cần tăng chiều cao của nền UIView
bằng chiều rộng đường viền của mình .. Cũng có thể được thực hiện cho bất kỳ mặt nào khác :)
Cá nhân tôi thích phân loại phụ của khung nhìn + drawRect, nhưng đây chỉ là một cách khác để thực hiện (và nó hoạt động theo cùng một dòng với câu trả lời được chấp nhận bởi @ If Pollavith):
Lớp viền mới của bạn có thể được thiết lập để có bất kỳ kích thước nào bạn muốn. Vì vậy, giống như câu trả lời của @ If Pollavith, bạn tạo một lớp có chiều cao như bạn muốn và rộng như tầm nhìn bạn muốn có viền. Sử dụng định nghĩa khung của lớp để đặt nó ở nơi bạn muốn và sau đó thêm nó dưới dạng lớp phụ vào chế độ xem của bạn.
Để tham khảo, yêu cầu của riêng tôi là đặt một đường viền ở phía bên trái của chế độ xem (vui lòng không cắt và dán mã này và không 'tôi chỉ' vì nó không đặt đường viền ở đầu chế độ xem - sửa đổi mã dưới đây là đủ đơn giản):
CALayer *leftBorder = [CALayer layer];
leftBorder.borderColor = [UIColor colorWithRed:0.0 green:91.0/255.0 blue:141.0/255.0 alpha:1.0].CGColor;
leftBorder.borderWidth = 1;
leftBorder.frame = CGRectMake(0, 0, 1.0, CGRectGetHeight(self.myTargetView.frame));
[self.myTargetView.layer addSublayer:leftBorder];
Tôi đoán rằng lợi ích vừa phải duy nhất cho việc này và tạo ra một UIView hoặc UILabel nhỏ là CALayer được cho là 'nhẹ hơn', và có rất nhiều quan điểm thú vị (như ý kiến) về việc sử dụng drawRect quá mức so với sử dụng CALayers (như ở đây : iOS: Sử dụng 'drawRect:' của UIView so với lớp của nó 'drawLayer: inContext:' ).
Tôi thích màu xanh lam.
Ngoài n8tr, có thể thêm rằng có sẵn để đặt chúng từ bảng phân cảnh:
- thêm hai thuộc tính like borderColor
và borderWidth
trong tệp .h;
- sau đó bạn có thể thêm keyPaths
ngay trong bảng phân cảnh, xem liên kết đến ảnh chụp màn hình
Chuyển đổi câu trả lời DanShev sang Swift 3
extension CALayer {
func addBorder(edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer()
switch edge {
case .top:
border.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: thickness)
break
case .bottom:
border.frame = CGRect(x: 0, y: self.frame.height - thickness, width: self.frame.width, height: thickness)
break
case .left:
border.frame = CGRect(x: 0, y: 0, width: thickness, height: self.frame.height)
break
case .right:
border.frame = CGRect(x: self.frame.width - thickness, y: 0, width: thickness, height: self.frame.height)
break
default:
break
}
border.backgroundColor = color.cgColor;
self.addSublayer(border)
}
}
Đối với Xamarin trong C #, tôi chỉ tạo đường viền nội tuyến khi thêm lớp phụ
View.Layer.AddSublayer(new CALayer()
{
BackgroundColor = UIColor.Black.CGColor,
Frame = new CGRect(0, 0, View.Frame.Width, 0.5f)
});
Bạn có thể sắp xếp cái này (theo gợi ý của người khác) cho các đường viền dưới, trái và phải.
Bạn cũng có thể kiểm tra bộ sưu tập các danh mục UIKit và Foundation này: https://github.com/leszek-s/LSC Chuyên mục
Nó cho phép thêm đường viền ở một bên của UIView với một dòng mã:
[self.someView lsAddBorderOnEdge:UIRectEdgeTop color:[UIColor blueColor] width:2];
và nó xử lý đúng cách xoay vòng trong khi hầu hết các câu trả lời được đăng ở đây không xử lý tốt.
Lưu ý: hầu hết các giải pháp ở đây không thích ứng và sẽ không thay đổi kích thước. Các giải pháp sẽ thay đổi kích thước sẽ có tác động lớn đến thời gian khởi động của bạn vì chúng sử dụng rất nhiều CPU.
Bạn có thể sử dụng giải pháp này bên dưới. Nó hoạt động trên UIBezierPaths nhẹ hơn các lớp, khiến thời gian khởi động nhanh. Nó rất dễ sử dụng, xem hướng dẫn bên dưới.
class ResizeBorderView: UIView {
var color = UIColor.white
var lineWidth: CGFloat = 1
var edges = [UIRectEdge](){
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
if edges.contains(.top) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: 0, y: 0 + lineWidth / 2))
path.addLine(to: CGPoint(x: self.bounds.width, y: 0 + lineWidth / 2))
path.stroke()
}
if edges.contains(.bottom) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: 0, y: self.bounds.height - lineWidth / 2))
path.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.height - lineWidth / 2))
path.stroke()
}
if edges.contains(.left) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: 0 + lineWidth / 2, y: 0))
path.addLine(to: CGPoint(x: 0 + lineWidth / 2, y: self.bounds.height))
path.stroke()
}
if edges.contains(.right) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: self.bounds.width - lineWidth / 2, y: 0))
path.addLine(to: CGPoint(x: self.bounds.width - lineWidth / 2, y: self.bounds.height))
path.stroke()
}
}
}
Để đặt Đường viền trên và Đường viền dưới cho UIView trong Swift.
let topBorder = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 1))
topBorder.backgroundColor = UIColor.black
myView.addSubview(topBorder)
let bottomBorder = UIView(frame: CGRect(x: 0, y: myView.frame.size.height - 1, width: 10, height: 1))
bottomBorder.backgroundColor = UIColor.black
myView.addSubview(bottomBorder)