UIView устанавливает только боковые границы

Есть ли способ установить границы границы UIView на один цвет и оставить верхнюю и нижнюю части?

Ответ 1

Границы Nope-CALayer не поддерживают это поведение. Самый простой способ выполнить то, что вы хотите, - добавить непрозрачный подъярус n-point-wide с желаемым цветом границы в качестве цвета фона с каждой стороны вашего вида.

Пример:

CGSize mainViewSize = theView.bounds.size;
CGFloat borderWidth = 2;
UIColor *borderColor = [UIColor redColor];
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, borderWidth, mainViewSize.height)];
UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(mainViewSize.width - borderWidth, 0, borderWidth, mainViewSize.height)];
leftView.opaque = YES;
rightView.opaque = YES;
leftView.backgroundColor = borderColor;
rightView.backgroundColor = borderColor;

// for bonus points, set the views' autoresizing mask so they'll stay with the edges:
leftView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin;
rightView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin;

[theView addSubview:leftView];
[theView addSubview:rightView];

[leftView release];
[rightView release];

Обратите внимание, что это не вполне соответствует поведению границ CALayer - левый и правый границы будут всегда находиться внутри границ их супервизора.

Ответ 2

Ответ с представлениями, которые работают как границы, очень приятный, но помните, что каждое представление представляет собой объект пользовательского интерфейса, который требует больших объемов памяти.

Я использую слой uivew для рисования штриха с цветом на уже существующем UIview.

-(CAShapeLayer*)drawLineFromPoint:(CGPoint)fromPoint toPoint:(CGPoint) toPoint withColor:(UIColor *)color andLineWidth:(CGFloat)lineWidth{

CAShapeLayer *lineShape = nil;
CGMutablePathRef linePath = nil;

linePath = CGPathCreateMutable();
lineShape = [CAShapeLayer layer];

lineShape.lineWidth = lineWidth;
lineShape.strokeColor = color.CGColor;

NSUInteger x = fromPoint.x;
NSUInteger y = fromPoint.y;

NSUInteger toX = toPoint.x;
NSUInteger toY = toPoint.y;

CGPathMoveToPoint(linePath, nil, x, y);
CGPathAddLineToPoint(linePath, nil, toX, toY);

lineShape.path = linePath;
CGPathRelease(linePath);
return lineShape;}

и добавьте его к нашему представлению.

CAShapeLayer* borderLine=[self drawLineFromPoint:CGPointMake(0, 0) toPoint:CGPointMake(0,_myView.frame.size.height) withColor:[UIColor lightGrayColor] andLineWidth:1.0f];

[_myView.layer addSublayer:borderLine];

Итак... Мы берем точку и фактически рисуем линию сверху донизу нашего представления. В результате получается строка, которая выглядит как граница ширины одного пикселя.

Ответ 3

Обновлен для Swift 3.0

Я написал расширение Swift (для UIButton), которое имитирует установку границы на любой стороне UIView до заданного цвета и ширины. Он похож на подход @Noah Witherspoon, но основан на автономности и ограничении автоопределения.

 // Swift 3.0
extension UIView {

  enum Border {
    case left
    case right
    case top
    case bottom
  }

  func setBorder(border: UIView.Border, weight: CGFloat, color: UIColor ) {

    let lineView = UIView()
    addSubview(lineView)
    lineView.backgroundColor = color
    lineView.translatesAutoresizingMaskIntoConstraints = false

    switch border {

    case .left:
      lineView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
      lineView.topAnchor.constraint(equalTo: topAnchor).isActive = true
      lineView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
      lineView.widthAnchor.constraint(equalToConstant: weight).isActive = true

    case .right:
      lineView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
      lineView.topAnchor.constraint(equalTo: topAnchor).isActive = true
      lineView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
      lineView.widthAnchor.constraint(equalToConstant: weight).isActive = true

    case .top:
      lineView.topAnchor.constraint(equalTo: topAnchor).isActive = true
      lineView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
      lineView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
      lineView.heightAnchor.constraint(equalToConstant: weight).isActive = true

    case .bottom:
      lineView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
      lineView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
      lineView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
      lineView.heightAnchor.constraint(equalToConstant: weight).isActive = true
    }
  }
}    

Ответ 4

Это звучит как один из двух ответов:

Если ваше представление представляет собой статический размер, просто поставьте за него UIView, который на 2 пикселя шире и на 2 пикселя меньше, чем ваш вид спереди.

Если это нестатический размер, вы можете сделать то же самое, изменив размер заднего вида при изменении размера переднего плана или реализовать пользовательский объект, который реализует UIView, и реализовать (переопределить) вашу собственную процедуру drawRect.

Ответ 5

NAUIViewWithBorders помогло. См. Также создатель SO post здесь. Стоит проверить, нужна ли вам эта функция для более чем нескольких просмотров.

Ответ 6

public extension UIView {
// Border type and arbitrary tag values to identify UIView borders as subviews
public enum BorderType: Int {
    case left = 20000
    case right = 20001
    case top = 20002
    case bottom = 20003
}

public func addBorder(borderType: BorderType, width: CGFloat, color: UIColor) {
    // figure out frame and resizing based on border type
    var autoresizingMask: UIViewAutoresizing
    var layerFrame: CGRect
    switch borderType {
    case .left:
        layerFrame = CGRect(x: 0, y: 0, width: width, height: self.bounds.height)
        autoresizingMask = [ .flexibleHeight, .flexibleRightMargin ]
    case .right:
        layerFrame = CGRect(x: self.bounds.width - width, y: 0, width: width, height: self.bounds.height)
        autoresizingMask = [ .flexibleHeight, .flexibleLeftMargin ]
    case .top:
        layerFrame = CGRect(x: 0, y: 0, width: self.bounds.width, height: width)
        autoresizingMask = [ .flexibleWidth, .flexibleBottomMargin ]
    case .bottom:
        layerFrame = CGRect(x: 0, y: self.bounds.height - width, width: self.bounds.width, height: width)
        autoresizingMask = [ .flexibleWidth, .flexibleTopMargin ]
    }

    // look for the existing border in subviews
    var newView: UIView?
    for eachSubview in self.subviews {
        if eachSubview.tag == borderType.rawValue {
            newView = eachSubview
            break
        }
    }

    // set properties on existing view, or create a new one
    if newView == nil {
        newView = UIView(frame: layerFrame)
        newView?.tag = borderType.rawValue
        self.addSubview(newView!)
    } else {
        newView?.frame = layerFrame
    }
    newView?.backgroundColor = color
    newView?.autoresizingMask = autoresizingMask
}