web-dev-qa-db-fra.com

UIView ne définit que les bordures latérales

Existe-t-il un moyen de régler les côtés de la bordure d’un UIView sur une couleur et de laisser le haut et le bas l’autre?

16
Mason

Nope — Les frontières de CALayer ne supportent pas ce comportement. Le moyen le plus simple de réaliser ce que vous voulez consiste à ajouter une sous-vue opaque à l’échelle des points n - avec la couleur de bordure souhaitée comme couleur d’arrière-plan de chaque côté de la vue.

Exemple:

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];

Notez que cela ne correspond pas tout à fait au comportement des bordures de CALayer: les vues des bordures gauche et droite seront toujours à l’intérieur des limites de leur vue d’ensemble.

26
Noah Witherspoon

La réponse avec les vues qui fonctionnent comme des frontières sont très gentils, mais rappelez-vous que chaque vue est un objet d'interface utilisateur qui coûte beaucoup de mémoire.

J'utiliserais le calque d'uivew pour peindre un trait avec de la couleur sur une vue déjà existante.

-(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;}

et l'ajouter à notre vue.

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

[_myView.layer addSublayer:borderLine];

Alors ... Nous prenons un point et nous dessinons une ligne de haut en bas de notre vue. Le résultat est qu'il existe une ligne qui ressemble à une bordure d'une largeur de pixel.

7
daniel kilinskas

Mis à jour pour Swift 3.0

J'ai écrit une extension Swift (pour un UIButton) qui simule la définition d'une bordure de n'importe quel côté d'un UIView avec une couleur et une largeur données. Cette approche est similaire à celle de @Noah Witherspoon, mais repose sur des contraintes autonomes et autolayout.

 // 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
    }
  }
}    
7
SuitedSloth

Cela ressemble à l'une des deux réponses:

Si votre vue a une taille statique, placez-y une vue UIView plus large et 2 pixels plus courte que la vue de face.

Si sa taille n'est pas statique, vous pouvez également procéder de la même manière, en redimensionnant la vue de sauvegarde chaque fois que votre vue de premier plan est redimensionnée, ou en implémentant un objet personnalisé implémentant UIView et en implémentant (outrepassant) votre propre routine drawRect.

2
trumpetlicks
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
}
0
Debaprio B

NAUIViewWithBorders a fait le tour pour moi. Voir aussi le post de SO du créateur ici . Cela vaut la peine de vérifier si vous avez besoin de cette fonctionnalité pour plusieurs vues.

0
weienw