it-swarm.com.de

Hinzufügen eines Rahmens außerhalb einer UIView (statt innerhalb)

Wenn Sie einen Rand einer Ansicht hinzufügen, verwenden Sie Code in einer Ansicht wie

self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = 2.0f;

der Rahmen wird wie folgt in die Ansicht eingefügt: enter image description here

die rechte Ansicht ist die ursprüngliche Ansicht. Wie Sie sehen, ist der schwarze Bereich der umrandeten Ansicht kleiner als der ursprüngliche Bereich. Aber was ich möchte, ist eine Grenze außerhalb der ursprünglichen Ansicht, wie folgt:enter image description here. der schwarze Bereich ist gleich dem Original, wie kann ich ihn implementieren?

71
remykits

Leider gibt es nicht einfach eine kleine Eigenschaft, mit der Sie die Grenze nach außen ausrichten können. Es wird nach innen ausgerichtet, da die UIViews-Standardzeichnungsvorgänge innerhalb der Grenzen gezeichnet werden.

Die einfachste Lösung, die Ihnen einfällt, wäre die Erweiterung des UIView um die Größe der Rahmenbreite, wenn Sie den Rahmen anwenden:

CGFloat borderWidth = 2.0f;

self.frame = CGRectInset(self.frame, -borderWidth, -borderWidth);
self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = borderWidth;
93

Ok, es gibt bereits eine akzeptierte Antwort, aber ich denke, es gibt einen besseren Weg, es zu tun. Sie müssen nur eine neue Ebene haben, die etwas größer ist als Ihre Ansicht, und sie nicht über die Grenzen der Ansichtsebene verdecken (was tatsächlich der Fall ist.) das Standardverhalten). Hier ist der Beispielcode:

CALayer * externalBorder = [CALayer layer];
externalBorder.frame = CGRectMake(-1, -1, myView.frame.size.width+2, myView.frame.size.height+2);
externalBorder.borderColor = [UIColor blackColor].CGColor;
externalBorder.borderWidth = 1.0;

[myView.layer addSublayer:externalBorder];
myView.layer.masksToBounds = NO;

Dies ist natürlich der Fall, wenn Sie möchten, dass Ihr Rand eine Einheit groß ist. Wenn Sie mehr wollen, passen Sie borderWidth und den Rahmen der Ebene entsprechend an .. _. Dies ist besser als die Verwendung einer zweiten etwas größeren Ansicht, da CALayer leichter ist als UIView, und Sie müssen den Rahmen von myView nicht ändern. Dies ist beispielsweise dann sinnvoll, wenn myView einUIImageView ist. 

NB: Für mich war das Ergebnis auf dem Simulator nicht perfekt (die Schicht befand sich nicht genau an der richtigen Position, so dass die Schicht auf einer Seite manchmal dicker war), war aber genau das, was auf einem realen Gerät verlangt wird.

EDIT 

Eigentlich war das Problem, von dem ich in der N.B spreche, nur, weil ich den Bildschirm des Simulators verkleinert hatte, bei normaler Größe gibt es absolut kein Problem

Ich hoffe es hilft

17

Nun, es gibt keine direkte Methode, um dies zu tun. Sie können einige Problemumgehungen in Betracht ziehen.

  1. Ändern und vergrößern Sie den Rahmen und fügen Sie Rahmenfarbe wie gewünscht hinzu
  2. Fügen Sie hinter der aktuellen Ansicht eine Ansicht mit der größeren Größe hinzu, so dass sie als Rahmen erscheint. Kann als benutzerdefinierte Ansichtsklasse verwendet werden
  3. Wenn Sie keinen eindeutigen Rand (Clearcut-Rand) benötigen, können Sie sich zu diesem Zweck auf Schatten verlassen

    [view1 setBackgroundColor:[UIColor blackColor]];
    UIColor *color = [UIColor yellowColor];
    view1.layer.shadowColor = [color CGColor];
    view1.layer.shadowRadius = 10.0f;
    view1.layer.shadowOpacity = 1;
    view1.layer.shadowOffset = CGSizeZero;
    view1.layer.masksToBounds = NO;
    
13
Lithu T.V

Mit der oben akzeptierten besten Antwort habe ich Erfahrungen mit solchen nicht Nice Ergebnissen und unschönen Kanten gemacht:

 border without bezier path

Also werde ich meine UIView Swift -Erweiterung mit Ihnen teilen, die einen UIBezierPath als Randumriss verwendet - ohne unschöne Kanten (inspiriert von @Fattie ):

 border with bezier path

//  UIView+BezierPathBorder.Swift

import UIKit

extension UIView {

    fileprivate var bezierPathIdentifier:String { return "bezierPathBorderLayer" }

    fileprivate var bezierPathBorder:CAShapeLayer? {
        return (self.layer.sublayers?.filter({ (layer) -> Bool in
            return layer.name == self.bezierPathIdentifier && (layer as? CAShapeLayer) != nil
        }) as? [CAShapeLayer])?.first
    }

    func bezierPathBorder(_ color:UIColor = .white, width:CGFloat = 1) {

        var border = self.bezierPathBorder
        let path = UIBezierPath(roundedRect: self.bounds, cornerRadius:self.layer.cornerRadius)
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask

        if (border == nil) {
            border = CAShapeLayer()
            border!.name = self.bezierPathIdentifier
            self.layer.addSublayer(border!)
        }

        border!.frame = self.bounds
        let pathUsingCorrectInsetIfAny =
            UIBezierPath(roundedRect: border!.bounds, cornerRadius:self.layer.cornerRadius)

        border!.path = pathUsingCorrectInsetIfAny.cgPath
        border!.fillColor = UIColor.clear.cgColor
        border!.strokeColor = color.cgColor
        border!.lineWidth = width * 2
    }

    func removeBezierPathBorder() {
        self.layer.mask = nil
        self.bezierPathBorder?.removeFromSuperlayer()
    }

}

Beispiel:

let view = UIView(frame: CGRect(x: 20, y: 20, width: 100, height: 100))
view.layer.cornerRadius = view.frame.width / 2
view.backgroundColor = .red

//add white 2 pixel border outline
view.bezierPathBorder(.white, width: 2)

//remove border outline (optional)
view.removeBezierPathBorder()
13
Peter Kreinz

Für eine Swift-Implementierung können Sie diese als UIView-Erweiterung hinzufügen.

extension UIView {

    struct Constants {
        static let ExternalBorderName = "externalBorder"
    }

    func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.whiteColor()) -> CALayer {
        let externalBorder = CALayer()
        externalBorder.frame = CGRectMake(-borderWidth, -borderWidth, frame.size.width + 2 * borderWidth, frame.size.height + 2 * borderWidth)
        externalBorder.borderColor = borderColor.CGColor
        externalBorder.borderWidth = borderWidth
        externalBorder.name = Constants.ExternalBorderName

        layer.insertSublayer(externalBorder, atIndex: 0)
        layer.masksToBounds = false

        return externalBorder
    }

    func removeExternalBorders() {
        layer.sublayers?.filter() { $0.name == Constants.ExternalBorderName }.forEach() {
            $0.removeFromSuperlayer()
        }
    }

    func removeExternalBorder(externalBorder: CALayer) {
        guard externalBorder.name == Constants.ExternalBorderName else { return }
        externalBorder.removeFromSuperlayer()
    }

}
9
picciano

Erhöhen Sie die Breite und Höhe des Rahmens der Ansicht mit der Randbreite, bevor Sie den Rand hinzufügen:

float borderWidth = 2.0f
CGRect frame = self.frame;
frame.width += borderWidth;
frame.height += borderWidth;
 self.layer.borderColor = [UIColor yellowColor].CGColor;
 self.layer.borderWidth = 2.0f;
2
Hossam Ghareeb

Es gibt tatsächlich eine sehr einfache Lösung. Stellen Sie sie einfach wie folgt ein:

view.layer.borderWidth = 5

view.layer.borderColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.5).cgColor

view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.25).cgColor
1
Nikolas Ioannou

Ich mochte die Lösung von @picciano & @Maksim Kniazev. Wir können auch einen ringförmigen Rand mit Folgendem erstellen:

func addExternalAnnularBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white) {
    let externalBorder = CALayer()
    externalBorder.frame = CGRect(x: -borderWidth*2, y: -borderWidth*2, width: frame.size.width + 4 * borderWidth, height: frame.size.height + 4 * borderWidth)
    externalBorder.borderColor = borderColor.cgColor
    externalBorder.borderWidth = borderWidth
    externalBorder.cornerRadius = (frame.size.width + 4 * borderWidth) / 2
    externalBorder.name = Constants.ExternalBorderName
    layer.insertSublayer(externalBorder, at: 0)
    layer.masksToBounds = false
}
0
Jimbung

Ich mochte die Lösung von @picciano Wenn Sie anstelle des Quadrats einen explodierenden Kreis erzeugen möchten, ersetzen Sie addExternalBorder mit:

func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white) {
        let externalBorder = CALayer()
        externalBorder.frame = CGRect(x: -borderWidth, y: -borderWidth, width: frame.size.width + 2 * borderWidth, height: frame.size.height + 2 * borderWidth)
        externalBorder.borderColor = borderColor.cgColor
        externalBorder.borderWidth = borderWidth
        externalBorder.cornerRadius = (frame.size.width + 2 * borderWidth) / 2
        externalBorder.name = Constants.ExternalBorderName
        layer.insertSublayer(externalBorder, at: 0)
        layer.masksToBounds = false

    }
0
Maksim Kniazev