Нижняя граница UIView?
до UIScrollView *toScrollView
(что является шириной экрана), я хочу добавить серую нижнюю границу (точно так же, как в поле to представления compose собственного приложения сообщений iPhone).
чтобы достичь этого, я следовал Cocoa Touch: как изменить цвет и толщину границы UIView? и просто покрыл верхнюю границу с пользовательским UINavigationBar
и сделал toScrollView
' S X-координата -1 и ширина 322, так что левая и правая границы находятся за пределами экрана.
это выглядит нормально, но это своего рода Хак, и мне было интересно, есть ли лучший способ сделать это.
- (void)viewDidLoad {
[super viewDidLoad];
// Add UINavigationBar *navigationBar at top.
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self action:@selector(cancelAction)];
UINavigationBar *navigationBar = [[UINavigationBar alloc]
initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)];
navigationBar.items = [NSArray arrayWithObject:self.navigationItem];
// Add UIScrollView *toScrollView below navigationBar.
UIScrollView *toScrollView = [[UIScrollView alloc]
initWithFrame:CGRectMake(-1.0f, 43.0f, 322.0f, 45.0f)];
toScrollView.backgroundColor = [UIColor whiteColor];
toScrollView.layer.borderColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor;
toScrollView.layer.borderWidth = 1.0f;
[self.view addSubview:toScrollView];
[self.view addSubview:navigationBar]; // covers top of toScrollView
}
18 ответов:
вместо
UIView
, как предлагает @ImreKelényi, вы можете использоватьCALayer
:// Add a bottomBorder. CALayer *bottomBorder = [CALayer layer]; bottomBorder.frame = CGRectMake(0.0f, 43.0f, toScrollView.frame.size.width, 1.0f); bottomBorder.backgroundColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor; [toScrollView.layer addSublayer:bottomBorder];
вот более обобщенное расширение Swift для создания границы для любого
UIView
подкласс:import UIKit extension UIView { func addTopBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor border.frame = CGRectMake(0, 0, self.frame.size.width, width) self.layer.addSublayer(border) } func addRightBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor border.frame = CGRectMake(self.frame.size.width - width, 0, width, self.frame.size.height) self.layer.addSublayer(border) } func addBottomBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor border.frame = CGRectMake(0, self.frame.size.height - width, self.frame.size.width, width) self.layer.addSublayer(border) } func addLeftBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor border.frame = CGRectMake(0, 0, width, self.frame.size.height) self.layer.addSublayer(border) } }
Swift 3
extension UIView { func addTopBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width) self.layer.addSublayer(border) } func addRightBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height) self.layer.addSublayer(border) } func addBottomBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width) self.layer.addSublayer(border) } func addLeftBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height) self.layer.addSublayer(border) } }
реализовано в категории, как показано ниже:
UIButton+Граница.h:
@interface UIButton (Border) - (void)addBottomBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addLeftBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addRightBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addTopBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; @end
UIButton+Граница.м:
@implementation UIButton (Border) - (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth); [self.layer addSublayer:border]; } - (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth); [self.layer addSublayer:border]; } - (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height); [self.layer addSublayer:border]; } - (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height); [self.layer addSublayer:border]; } @end
вы можете добавить отдельной
UIView
с высотой 1 пункта и серым цветом предпосылки кself.view
и расположите его прямо подtoScrollView
.EDIT: если у вас нет веской причины (хотите использовать некоторые услуги UIView, которые не предлагаются CALayer), вы должны использовать CALayer как @MattDiPasquale предлагает. UIView имеет большие накладные расходы, которые могут не быть проблемой в большинстве случаев, но все же, другое решение является более элегантным.
Если вам нужно действительно адаптивное решение (для всех размеров экрана), то это он:
/** * Extends UIView with shortcut methods * * @author Alexander Volkov * @version 1.0 */ extension UIView { /** Adds bottom border to the view with given side margins - parameter color: the border color - parameter margins: the left and right margin */ func addBottomBorder(color: UIColor = UIColor.lightBorderColor(), margins: CGFloat = 0) { let border = UIView() border.backgroundColor = color border.translatesAutoresizingMaskIntoConstraints = false self.addSubview(border) border.addConstraint(NSLayoutConstraint(item: border, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.Height, multiplier: 1, constant: 1)) self.addConstraint(NSLayoutConstraint(item: border, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)) self.addConstraint(NSLayoutConstraint(item: border, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: margins)) self.addConstraint(NSLayoutConstraint(item: border, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: margins)) } }
также улучшен код с функцией удаления границ. На основе confile ответ.
import UIKit enum viewBorder: String { case Left = "borderLeft" case Right = "borderRight" case Top = "borderTop" case Bottom = "borderBottom" } extension UIView { func addBorder(vBorder: viewBorder, color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor border.name = vBorder.rawValue switch vBorder { case .Left: border.frame = CGRectMake(0, 0, width, self.frame.size.height) case .Right: border.frame = CGRectMake(self.frame.size.width - width, 0, width, self.frame.size.height) case .Top: border.frame = CGRectMake(0, 0, self.frame.size.width, width) case .Bottom: border.frame = CGRectMake(0, self.frame.size.height - width, self.frame.size.width, width) } self.layer.addSublayer(border) } func removeBorder(border: viewBorder) { var layerForRemove: CALayer? for layer in self.layer.sublayers! { if layer.name == border.rawValue { layerForRemove = layer } } if let layer = layerForRemove { layer.removeFromSuperlayer() } } }
Обновление: Swift 3
import UIKit enum ViewBorder: String { case left, right, top, bottom } extension UIView { func add(border: ViewBorder, color: UIColor, width: CGFloat) { let borderLayer = CALayer() borderLayer.backgroundColor = color.cgColor borderLayer.name = border.rawValue switch border { case .left: borderLayer.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height) case .right: borderLayer.frame = CGRect(x: self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height) case .top: borderLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width) case .bottom: borderLayer.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width) } self.layer.addSublayer(borderLayer) } func remove(border: ViewBorder) { guard let sublayers = self.layer.sublayers else { return } var layerForRemove: CALayer? for layer in sublayers { if layer.name == border.rawValue { layerForRemove = layer } } if let layer = layerForRemove { layer.removeFromSuperlayer() } } }
или самый удобный для производительности способ-перегрузить drawRect, просто так:
@interface TPActionSheetButton : UIButton @property (assign) BOOL drawsTopLine; @property (assign) BOOL drawsBottomLine; @property (assign) BOOL drawsRightLine; @property (assign) BOOL drawsLeftLine; @property (strong, nonatomic) UIColor * lineColor; @end @implementation TPActionSheetButton - (void) drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(ctx, 0.5f * [[UIScreen mainScreen] scale]); CGFloat red, green, blue, alpha; [self.lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; CGContextSetRGBStrokeColor(ctx, red, green, blue, alpha); if(self.drawsTopLine) { CGContextBeginPath(ctx); CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMinY(rect)); CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMinY(rect)); CGContextStrokePath(ctx); } if(self.drawsBottomLine) { CGContextBeginPath(ctx); CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMaxY(rect)); CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMaxY(rect)); CGContextStrokePath(ctx); } if(self.drawsLeftLine) { CGContextBeginPath(ctx); CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMinY(rect)); CGContextAddLineToPoint(ctx, CGRectGetMinX(rect), CGRectGetMaxY(rect)); CGContextStrokePath(ctx); } if(self.drawsRightLine) { CGContextBeginPath(ctx); CGContextMoveToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMinY(rect)); CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMaxY(rect)); CGContextStrokePath(ctx); } [super drawRect:rect]; } @end
проблема с этими методами расширения заключается в том, что когда UIView/UIButton позже регулирует его размер, у вас нет возможности изменить размер CALayer в соответствии с новым размером. Что оставит вас с неуместной границей. Я обнаружил, что лучше подкласс моего UIButton, вы можете, конечно, подкласс других UIViews. Вот код:
enum BorderedButtonSide { case Top, Right, Bottom, Left } class BorderedButton : UIButton { private var borderTop: CALayer? private var borderTopWidth: CGFloat? private var borderRight: CALayer? private var borderRightWidth: CGFloat? private var borderBottom: CALayer? private var borderBottomWidth: CGFloat? private var borderLeft: CALayer? private var borderLeftWidth: CGFloat? func setBorder(side: BorderedButtonSide, _ color: UIColor, _ width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor switch side { case .Top: border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: width) borderTop?.removeFromSuperlayer() borderTop = border borderTopWidth = width case .Right: border.frame = CGRect(x: frame.size.width - width, y: 0, width: width, height: frame.size.height) borderRight?.removeFromSuperlayer() borderRight = border borderRightWidth = width case .Bottom: border.frame = CGRect(x: 0, y: frame.size.height - width, width: frame.size.width, height: width) borderBottom?.removeFromSuperlayer() borderBottom = border borderBottomWidth = width case .Left: border.frame = CGRect(x: 0, y: 0, width: width, height: frame.size.height) borderLeft?.removeFromSuperlayer() borderLeft = border borderLeftWidth = width } layer.addSublayer(border) } override func layoutSubviews() { super.layoutSubviews() borderTop?.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: borderTopWidth!) borderRight?.frame = CGRect(x: frame.size.width - borderRightWidth!, y: 0, width: borderRightWidth!, height: frame.size.height) borderBottom?.frame = CGRect(x: 0, y: frame.size.height - borderBottomWidth!, width: frame.size.width, height: borderBottomWidth!) borderLeft?.frame = CGRect(x: 0, y: 0, width: borderLeftWidth!, height: frame.size.height) } }
Swift 3 версия ответа Confile:
import UIKit extension UIView { func addTopBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width) self.layer.addSublayer(border) } func addRightBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height) self.layer.addSublayer(border) } func addBottomBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width) self.layer.addSublayer(border) } func addLeftBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height) self.layer.addSublayer(border) } }
использование при использовании автоматической компоновки:
class CustomView: UIView { override func awakeFromNib() { super.awakeFromNib() } override func layoutSubviews() { addBottomBorderWithColor(color: UIColor.white, width: 1) } }
Я написал общий метод, который добавит границу с любой стороны, которую вы хотите в любом
UIView
. Вы можете определить толщину, цвет, поля иzOrder
для каждой стороны./* view: the view to draw border around thickness: thickness of the border on the given side color: color of the border on the given side margin: space between the border's outer edge and the view's frame edge on the given side. zOrder: defines the order to add the borders to the view. The borders will be added by zOrder from lowest to highest, thus making the highest priority border visible when two borders overlap at the corners. */ +(void) drawBorderAroundUIView:(UIView *) view thicknessLeft:(CGFloat) thicknessLeft colorLeft:(UIColor *)colorLeft marginLeft:(CGFloat) marginLeft zOrderLeft:(int) zOrderLeft thicknessRight:(CGFloat) thicknessRight colorRight:(UIColor *)colorRight marginRight:(CGFloat) marginRight zOrderRight:(int) zOrderRight thicknessTop:(CGFloat) thicknessTop colorTop:(UIColor *)colorTop marginTop:(CGFloat) marginTop zOrderTop:(int) zOrderTop thicknessBottom:(CGFloat) thicknessBottom colorBottom:(UIColor *)colorBottom marginBottom:(CGFloat) marginBottom zOrderBottom:(int) zOrderBottom{ //make margins be the outside edge and make positive margin represent a smaller rectangle marginBottom = -1 * marginBottom - thicknessBottom; marginTop = -1 * marginTop - thicknessTop; marginLeft = -1 * marginLeft - thicknessLeft; marginRight = -1 * marginRight - thicknessRight; //get reference points for corners CGPoint upperLeftCorner = CGPointZero; CGPoint lowerLeftCorner = CGPointMake(upperLeftCorner.x, upperLeftCorner.y + view.frame.size.height); CGPoint upperRightCorner = CGPointMake(upperLeftCorner.x + view.frame.size.width, upperLeftCorner.y); //left CALayer *leftBorder = [CALayer layer]; leftBorder.frame = CGRectMake(upperLeftCorner.x - thicknessLeft - marginLeft, upperLeftCorner.y - thicknessTop - marginTop, thicknessLeft, view.frame.size.height + marginTop + marginBottom + thicknessBottom + thicknessTop); leftBorder.backgroundColor = colorLeft.CGColor; //right CALayer *rightBorder = [CALayer layer]; rightBorder.frame = CGRectMake(upperRightCorner.x + marginRight, upperRightCorner.y - thicknessTop - marginTop, thicknessRight, view.frame.size.height + marginTop + marginBottom + thicknessBottom + thicknessTop); rightBorder.backgroundColor = colorRight.CGColor; //top CALayer *topBorder = [CALayer layer]; topBorder.frame = CGRectMake(upperLeftCorner.x - thicknessLeft - marginLeft, upperLeftCorner.y - thicknessTop - marginTop, view.frame.size.width + marginLeft + marginRight + thicknessLeft + thicknessRight, thicknessTop); topBorder.backgroundColor = colorTop.CGColor; //bottom CALayer *bottomBorder = [CALayer layer]; bottomBorder.frame = CGRectMake(upperLeftCorner.x - thicknessLeft - marginLeft, lowerLeftCorner.y + marginBottom, view.frame.size.width + marginLeft + marginRight + thicknessLeft + thicknessRight, thicknessBottom); bottomBorder.backgroundColor = colorBottom.CGColor; //define dictionary keys to be used for adding borders in order of zOrder NSString *borderDK = @"border"; NSString *zOrderDK = @"zOrder"; //storing borders in dictionaries in preparation to add them in order of zOrder NSDictionary *leftBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:leftBorder, borderDK, [NSNumber numberWithInt:zOrderLeft], zOrderDK, nil]; NSDictionary *rightBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:rightBorder, borderDK, [NSNumber numberWithInt:zOrderRight], zOrderDK, nil]; NSDictionary *topBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:topBorder, borderDK, [NSNumber numberWithInt:zOrderTop], zOrderDK, nil]; NSDictionary *bottomBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:bottomBorder, borderDK, [NSNumber numberWithInt:zOrderBottom], zOrderDK, nil]; NSMutableArray *borders = [NSMutableArray arrayWithObjects:leftBorderDictionary, rightBorderDictionary, topBorderDictionary, bottomBorderDictionary, nil]; //add borders in order of zOrder (lowest -> highest). Thus the highest zOrder will be added last so it will be on top. while (borders.count) { //look for the next lowest zOrder border to add NSDictionary *nextBorderToLayDown = [borders objectAtIndex:0]; for (int indexOfBorder = 0; indexOfBorder < borders.count; indexOfBorder++) { NSDictionary *borderAtIndex = [borders objectAtIndex:indexOfBorder]; if ([[borderAtIndex objectForKey:zOrderDK] intValue] < [[nextBorderToLayDown objectForKey:zOrderDK] intValue]) { nextBorderToLayDown = borderAtIndex; } } //add the border to the view [view.layer addSublayer:[nextBorderToLayDown objectForKey:borderDK]]; [borders removeObject:nextBorderToLayDown]; } }
вам не нужно добавлять слой для каждой границы, просто используйте путь Безье, чтобы нарисовать их один раз.
CGRect rect = self.bounds; CGPoint destPoint[4] = {CGPointZero, (CGPoint){0, rect.size.height}, (CGPoint){rect.size.width, rect.size.height}, (CGPoint){rect.size.width, 0}}; BOOL position[4] = {_top, _left, _bottom, _right}; UIBezierPath *path = [UIBezierPath new]; [path moveToPoint:destPoint[3]]; for (int i = 0; i < 4; ++i) { if (position[i]) { [path addLineToPoint:destPoint[i]]; } else { [path moveToPoint:destPoint[i]]; } } CAShapeLayer *borderLayer = [CAShapeLayer new]; borderLayer.frame = self.bounds; borderLayer.path = path.CGPath; borderLayer.lineWidth = _borderWidth ?: 1 / [UIScreen mainScreen].scale; borderLayer.strokeColor = _borderColor.CGColor; borderLayer.fillColor = [UIColor clearColor].CGColor; [self.layer addSublayer:borderLayer];
Swift 4/3
вы можете использовать это решение ниже. Он работает на UIBezierPaths, которые легче, чем слои, вызывая быстрое время запуска. Он прост в использовании, см. инструкции ниже.
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() } } }
- установите класс вашего UIView в ResizeBorderView
- задать цвет и ширину линии с помощью yourview.цвет и ваш взгляд.ширина строки в вашем методе viewDidAppear
- установите края, например: yourview.стыки.[ = право. ,оставил] ([.все]) для всех
- наслаждайтесь быстрым запуском и изменением размеров границ
Swift 4
на основе: https://stackoverflow.com/a/32821607/9980800
UIView + Border
extension UIView { enum ViewBorder: String { case left, right, top, bottom } func add(Border border: ViewBorder, withColor color: UIColor = UIColor.lightGray, andWidth width: CGFloat = 1.0) { let borderView = UIView() borderView.backgroundColor = color borderView.translatesAutoresizingMaskIntoConstraints = false self.addSubview(borderView) NSLayoutConstraint.activate(getConstrainsFor(forView: borderView, WithBorderType: border, andWidth: width)) } private func getConstrainsFor(forView borderView: UIView, WithBorderType border: ViewBorder, andWidth width: CGFloat) -> [NSLayoutConstraint] { let height = borderView.heightAnchor.constraint(equalToConstant: width) let widthAnchor = borderView.widthAnchor.constraint(equalToConstant: width) let leading = borderView.leadingAnchor.constraint(equalTo: self.leadingAnchor) let trailing = borderView.trailingAnchor.constraint(equalTo: self.trailingAnchor) let top = borderView.topAnchor.constraint(equalTo: self.topAnchor) let bottom = borderView.bottomAnchor.constraint(equalTo: self.bottomAnchor) switch border { case .bottom: return [bottom, leading, trailing, height] case .top: return [top, leading, trailing, height] case .left: return [top, bottom, leading, widthAnchor] case .right: return [top, bottom, trailing, widthAnchor] } }
}
использование:-
class ViewController: UIViewController { @IBOutlet weak var sampleView: UIView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. sampleView.add(Border: .bottom) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
самый полный ответ. https://github.com/oney/UIView-Border
let rectangle = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 60)) rectangle.backgroundColor = UIColor.grayColor() view.addSubview(rectangle) rectangle.borderTop = Border(size: 3, color: UIColor.orangeColor(), offset: UIEdgeInsets(top: 0, left: -10, bottom: 0, right: -5)) rectangle.borderBottom = Border(size: 6, color: UIColor.redColor(), offset: UIEdgeInsets(top: 0, left: 10, bottom: 10, right: 0)) rectangle.borderLeft = Border(size: 2, color: UIColor.blueColor(), offset: UIEdgeInsets(top: 10, left: -10, bottom: 0, right: 0)) rectangle.borderRight = Border(size: 2, color: UIColor.greenColor(), offset: UIEdgeInsets(top: 10, left: 10, bottom: 0, right: 0))
Свифт
создать расширение UIView
private var bottomLineColorAssociatedKey : UIColor = .black private var topLineColorAssociatedKey : UIColor = .black private var rightLineColorAssociatedKey : UIColor = .black private var leftLineColorAssociatedKey : UIColor = .black extension UIView { @IBInspectable var bottomLineColor: UIColor { get { if let color = objc_getAssociatedObject(self, &bottomLineColorAssociatedKey) as? UIColor { return color } else { return .black } } set { objc_setAssociatedObject(self, &bottomLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN) } } @IBInspectable var bottomLineWidth: CGFloat { get { return self.bottomLineWidth } set { DispatchQueue.main.async { self.addBottomBorderWithColor(color: self.bottomLineColor, width: newValue) } } } @IBInspectable var topLineColor: UIColor { get { if let color = objc_getAssociatedObject(self, &topLineColorAssociatedKey) as? UIColor { return color } else { return .black } } set { objc_setAssociatedObject(self, &topLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN) } } @IBInspectable var topLineWidth: CGFloat { get { return self.topLineWidth } set { DispatchQueue.main.async { self.addTopBorderWithColor(color: self.topLineColor, width: newValue) } } } @IBInspectable var rightLineColor: UIColor { get { if let color = objc_getAssociatedObject(self, &rightLineColorAssociatedKey) as? UIColor { return color } else { return .black } } set { objc_setAssociatedObject(self, &rightLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN) } } @IBInspectable var rightLineWidth: CGFloat { get { return self.rightLineWidth } set { DispatchQueue.main.async { self.addRightBorderWithColor(color: self.rightLineColor, width: newValue) } } } @IBInspectable var leftLineColor: UIColor { get { if let color = objc_getAssociatedObject(self, &leftLineColorAssociatedKey) as? UIColor { return color } else { return .black } } set { objc_setAssociatedObject(self, &leftLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN) } } @IBInspectable var leftLineWidth: CGFloat { get { return self.leftLineWidth } set { DispatchQueue.main.async { self.addLeftBorderWithColor(color: self.leftLineColor, width: newValue) } } } func addTopBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.name = "topBorderLayer" removePreviouslyAddedLayer(name: border.name ?? "") border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y : 0,width: self.frame.size.width, height: width) self.layer.addSublayer(border) } func addRightBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.name = "rightBorderLayer" removePreviouslyAddedLayer(name: border.name ?? "") border.backgroundColor = color.cgColor border.frame = CGRect(x: self.frame.size.width - width, y: 0, width : width, height :self.frame.size.height) self.layer.addSublayer(border) } func addBottomBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.name = "bottomBorderLayer" removePreviouslyAddedLayer(name: border.name ?? "") border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: self.frame.size.height - width,width : self.frame.size.width,height: width) self.layer.addSublayer(border) } func addLeftBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.name = "leftBorderLayer" removePreviouslyAddedLayer(name: border.name ?? "") border.backgroundColor = color.cgColor border.frame = CGRect(x:0, y:0,width : width, height : self.frame.size.height) self.layer.addSublayer(border) } func removePreviouslyAddedLayer(name : String) { if self.layer.sublayers?.count ?? 0 > 0 { self.layer.sublayers?.forEach { if .name == name { .removeFromSuperlayer() } } } } }
С
создать класс категории UIView
UIView + Граница.h
#import <UIKit/UIKit.h> #import <Foundation/Foundation.h> @interface UIView (Border) @property (nonatomic) IBInspectable UIColor *topLineColor; @property (nonatomic) IBInspectable CGFloat topLineWidth; @property (nonatomic) IBInspectable UIColor *bottomLineColor; @property (nonatomic) IBInspectable CGFloat bottomLineWidth; @property (nonatomic) IBInspectable UIColor *rightLineColor; @property (nonatomic) IBInspectable CGFloat rightLineWidth; @property (nonatomic) IBInspectable UIColor *leftLineColor; @property (nonatomic) IBInspectable CGFloat leftLineWidth; - (void)addBottomBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addLeftBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addRightBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addTopBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; @end
UIView + Граница.м
#import "UIView+Utility.h" #import <objc/runtime.h> static char bottomLineColorKey,topLineColorKey,rightLineColorKey,leftLineColorKey; @implementation UIView(Border) @dynamic bottomLineWidth,topLineWidth,rightLineWidth,leftLineWidth; // for Bottom Line - (UIColor *)bottomLineColor { return objc_getAssociatedObject(self, &bottomLineColorKey); } - (void)setBottomLineColor:(UIColor *)bottomLineColor { objc_setAssociatedObject(self, &bottomLineColorKey, bottomLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(void)setBottomLineWidth:(CGFloat)bottomLineWidth { dispatch_async(dispatch_get_main_queue(), ^{ [self addBottomBorderWithColor:[self bottomLineColor] andWidth:bottomLineWidth]; }); } // for top Line - (UIColor *)topLineColor { return objc_getAssociatedObject(self, &topLineColorKey); } - (void)setTopLineColor:(UIColor *)topLineColor { objc_setAssociatedObject(self, &topLineColorKey, topLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)setTopLineWidth:(CGFloat)topLineWidth{ dispatch_async(dispatch_get_main_queue(), ^{ [self addTopBorderWithColor:[self topLineColor] andWidth:topLineWidth]; }); } // for right Line - (UIColor *)rightLineColor { return objc_getAssociatedObject(self, &rightLineColorKey); } -(void)setRightLineColor:(UIColor *)rightLineColor { objc_setAssociatedObject(self, &rightLineColorKey, rightLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(void)setRightLineWidth:(CGFloat)rightLineWidth{ dispatch_async(dispatch_get_main_queue(), ^{ [self addRightBorderWithColor:[self rightLineColor] andWidth:rightLineWidth]; }); } // for left Line -(UIColor *)leftLineColor { return objc_getAssociatedObject(self, &leftLineColorKey); } -(void)setLeftLineColor:(UIColor *)leftLineColor{ objc_setAssociatedObject(self, &leftLineColorKey, leftLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(void)setLeftLineWidth:(CGFloat)leftLineWidth{ dispatch_async(dispatch_get_main_queue(), ^{ [self addLeftBorderWithColor:[self leftLineColor] andWidth:leftLineWidth]; }); } - (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.name = @"topBorderLayer"; [self removePreviouslyAddedLayer:border.name]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth); [self.layer addSublayer:border]; } - (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.name = @"bottomBorderLayer"; [self removePreviouslyAddedLayer:border.name]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth); [self.layer addSublayer:border]; } - (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.name = @"leftBorderLayer"; [self removePreviouslyAddedLayer:border.name]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height); [self.layer addSublayer:border]; } - (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.name = @"rightBorderLayer"; [self removePreviouslyAddedLayer:border.name]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height); [self.layer addSublayer:border]; } - (void)removePreviouslyAddedLayer:(NSString *)name { if (self.layer.sublayers.count > 0) { for (CALayer *layer in self.layer.sublayers) { if ([layer.name isEqualToString:name]) { [layer removeFromSuperlayer]; } } } } @end
использование :- Выберите любой элемент управления из раскадровки, а затем показать инспектор атрибутов (справа) вы увидите ниже пример изображения.(Примечание : граница появляется только при запуске время.)
Теперь вы можете установить любую сторону границы цвета и ширины.
расширение Swift 4 с шириной и цветом границы. Отлично работает!
@IBDesignable final class SideBorders: UIView { @IBInspectable var topColor: UIColor = UIColor.clear @IBInspectable var topWidth: CGFloat = 0 @IBInspectable var rightColor: UIColor = UIColor.clear @IBInspectable var rightWidth: CGFloat = 0 @IBInspectable var bottomColor: UIColor = UIColor.clear @IBInspectable var bottomWidth: CGFloat = 0 @IBInspectable var leftColor: UIColor = UIColor.clear @IBInspectable var leftWidth: CGFloat = 0 override func draw(_ rect: CGRect) { let topBorder = CALayer() topBorder.backgroundColor = topColor.cgColor topBorder.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: topWidth) self.layer.addSublayer(topBorder) let rightBorder = CALayer() rightBorder.backgroundColor = rightColor.cgColor rightBorder.frame = CGRect(x: self.frame.size.width - rightWidth, y: 0, width: rightWidth, height: self.frame.size.height) self.layer.addSublayer(rightBorder) let bottomBorder = CALayer() bottomBorder.backgroundColor = bottomColor.cgColor bottomBorder.frame = CGRect(x: 0, y: self.frame.size.height - bottomWidth, width: self.frame.size.width, height: bottomWidth) self.layer.addSublayer(bottomBorder) let leftBorder = CALayer() leftBorder.backgroundColor = leftColor.cgColor leftBorder.frame = CGRect(x: 0, y: self.frame.size.height - leftWidth, width: self.frame.size.width, height: leftWidth) self.layer.addSublayer(leftBorder) }
}
Swift 4
на основе https://stackoverflow.com/a/32513578/5391914
import UIKit enum viewBorder: String { case Left = "borderLeft" case Right = "borderRight" case Top = "borderTop" case Bottom = "borderBottom" } extension UIView { func addBorder(vBorders: [viewBorder], color: UIColor, width: CGFloat) { vBorders.forEach { vBorder in let border = CALayer() border.backgroundColor = color.cgColor border.name = vBorder.rawValue switch vBorder { case .Left: border.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height) case .Right: border.frame = CGRect(x:self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height) case .Top: border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width) case .Bottom: border.frame = CGRect(x: 0, y: self.frame.size.height - width , width: self.frame.size.width, height: width) } self.layer.addSublayer(border) } } }
Swift 4 Это прекрасно работает, скопировав это расширение UIView
extension UIView { final func addBorder(edges: UIRectEdge, color: UIColor = UIColor.white, thickness: CGFloat = 1.0) -> [UIView] { var borders = [UIView]() func border() -> UIView { let border = UIView(frame: CGRect.zero) border.backgroundColor = color border.translatesAutoresizingMaskIntoConstraints = false return border } if edges.contains(.top) || edges.contains(.all) { let top = border() addSubview(top) addConstraints( NSLayoutConstraint.constraints(withVisualFormat: "V:|-(0)-[top(==thickness)]", options: [], metrics: ["thickness": thickness], views: ["top": top])) addConstraints( NSLayoutConstraint.constraints(withVisualFormat: "H:|-(0)-[top]-(0)-|", options: [], metrics: nil, views: ["top": top])) borders.append(top) } if edges.contains(.left) || edges.contains(.all) { let left = border() addSubview(left) addConstraints( NSLayoutConstraint.constraints(withVisualFormat: "H:|-(0)-[left(==thickness)]", options: [], metrics: ["thickness": thickness], views: ["left": left])) addConstraints( NSLayoutConstraint.constraints(withVisualFormat: "V:|-(0)-[left]-(0)-|", options: [], metrics: nil, views: ["left": left])) borders.append(left) } if edges.contains(.right) || edges.contains(.all) { let right = border() addSubview(right) addConstraints( NSLayoutConstraint.constraints(withVisualFormat: "H:[right(==thickness)]-(0)-|", options: [], metrics: ["thickness": thickness], views: ["right": right])) addConstraints( NSLayoutConstraint.constraints(withVisualFormat: "V:|-(0)-[right]-(0)-|", options: [], metrics: nil, views: ["right": right])) borders.append(right) } if edges.contains(.bottom) || edges.contains(.all) { let bottom = border() addSubview(bottom) addConstraints( NSLayoutConstraint.constraints(withVisualFormat: "V:[bottom(==thickness)]-(0)-|", options: [], metrics: ["thickness": thickness], views: ["bottom": bottom])) addConstraints( NSLayoutConstraint.constraints(withVisualFormat: "H:|-(0)-[bottom]-(0)-|", options: [], metrics: nil, views: ["bottom": bottom])) borders.append(bottom) } return borders } }
в файле ViewController, вы можете использовать его:
_ = view.addBorder(edges: .bottom, color: UIColor.lightGray, thickness: 0.3)
вы можете изменить ".снизу" наверх, влево, вправо или массив "[.нижний. ,top] " это подходит для вашей работы.