Bir UIView dışında bir sınır ekleyin (içerisi yerine)


83

Bir görünümde kod kullanarak bir görünümün kenarlığı eklerseniz

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

kenarlık aşağıdaki gibi görünümün içine eklenir: görüntü açıklamasını buraya girin

doğru görünüm orijinal görünümdür, görebileceğiniz gibi, kenarlıklı görünümün siyah alanı orijinal görünümden daha azdır. ama ne almak istiyorum böyle orijinal görünümünde bir sınır dışında şöyledir: görüntü açıklamasını buraya girin. siyah alan orjinaline eşit, nasıl uygulayabilirim?

Yanıtlar:


102

Ne yazık ki, sınırı dışarıya hizalamak için ayarlayabileceğiniz küçük bir özellik yok. UIViews varsayılan çizim işlemleri sınırları dahilinde çizildiği için içeriye hizalı olarak çizer.

Akla gelen en basit çözüm, kenarlığı uygularken UIView'u kenarlık genişliğinin boyutuna göre genişletmek olacaktır:

CGFloat borderWidth = 2.0f;

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

Bunu uitableviewcell görünümünde kullandım. ancak satırda self.frame = CGRectInset (self.frame, -borderWidth, -borderWidth); Tablo görünümünü kaydırmaya devam edersek görünüm genişliği ve yüksekliği artmaya devam ediyor .. Ben de onu kaldırarak bitirdim.
Neela

Bu yöntem görüntüleme yüksekliğini artırmaya devam ettiğinden bu kodu kaldırıyorum ve şu kodu kullanıyorum self.view.layer.borderColor = [[UIColor colorWithRed: 209.0f / 255.0f green: 33.0f / 255.0f blue: 8.0f / 255.0f alpha 1.0f] CGColor]; self.view.layer.borderWidth = 1.0f;
Rizwan Şah

4
Bu çözümü
Swift'de

Bu kod birden çok kez çağrılan bir yöntemin içindeyse, self.frame kendini yinelediği için boyut olarak artmaya devam edecektir. Bunu önlemek için self.frame'i depolayacak bir özellik bildirin ve bunu viewDidload'da ayarlayın. örneğin, _originalSize = self.frame; originalSize bir CGRect özelliğidir. Sonra kodu self.frame = CGRectInset (_originalSize, -borderWidth, -borderWidth) olarak değiştirin;
GeneCode

Bu, ViewDidLoad'da uygulandığında, görünüm otomatik olarak ekran boyutuna yeniden boyutlandırılır (yani görünüm orijinal boyuta yeniden boyutlandırılır ve böylece kenarlık görünür hale gelir). ViewDidAppear'da uygulanmışsa, orijinal görünümün dışında bir sınır oluşturmaz. Kenarlığın orijinal görünümün dışında oluşturulması VE görünümün yeniden boyutlandırılmaması için nasıl uygulanacağı hakkında herhangi bir fikriniz var mı?
JeffB6688

23

Tamam, zaten kabul edilmiş bir cevap var ama bence bunu yapmanın daha iyi bir yolu var, sadece görünümünüzden biraz daha büyük yeni bir katmana sahip olmanız ve bunu görünüm katmanının sınırlarına (aslında varsayılan davranış). İşte örnek kod:

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;

Tabi bu eğer bordürünüzün 1 birim genişliğinde olmasını istiyorsanız, daha fazlasını istiyorsanız borderWidthkatman ve çerçevesini buna göre uyarlamalısınız . Bu, CALayera'dan daha hafif olduğu için ikinci bir görünüm kullanmaktan daha iyidir UIViewve çerçevesini değiştirmenize gerek yoktur myView, örneğin myViewbirUIImageView

Not: Benim için sonuç simülatörde mükemmel değildi (katman tam olarak doğru konumda değildi, bu nedenle katman bazen bir tarafta daha kalındı) ama tam olarak gerçek cihazda istenen şeydi.

DÜZENLE

Aslında içinde konuşmak sorun NB I simülatörün ekran azaltılmış çünkü kesinlikle hiçbir sorun yoktur, normal boyutuna sadece,

Umarım yardımcı olur


2
myView.layer.masksToBounds = HAYIR; myView CornerRadius'a sahip olduğunda sorun yaratıyor.
umakanta

.masksToBounds = hayır // ölçekleme modu en-boy ise bu, resminizi de taşacakFill
iOS Blacksmith

22

Yukarıda kabul edilen en iyi cevapla, bu kadar hoş olmayan sonuçlar ve çirkin kenarlarla deneyimler yaptım :

bezier yolu olmayan kenarlık

Bu yüzden , çirkin kenarlar olmadan ( @Fattie'den esinlenerek ) sınır anahattı yerine bir UIBezierPath kullanan UIView Swift uzantımı sizinle paylaşacağım :

bezier yolu ile sınır

//  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()
    }

}

Misal:

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()

benim durumumda içeride olmalı :)
Peter Kreinz

iyi bir düşünce şekli ama sınırınız hala "içeride", bu yüzden bunun ana hatlarıyla düzeltilmesi gerekiyor :)
Serj Rubens

17

Bir Swift uygulaması için, bunu bir UIView uzantısı olarak ekleyebilirsiniz.

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

}

Mükemmel! Teşekkür ederim! Swift 4'te bazı şeyler değişti ve şimdi farklı görünüyor, ancak Xcode kodun nasıl değiştirileceğini açıklıyor. Ve 'removeExternalBorder' yönteminde 'guard externalBorder.name ==' olmalıdır.
DmitryKanunnikoff

13

Bunu yapmak için doğrudan bir yöntem yok Bazı geçici çözümleri düşünebilirsiniz.

  1. Yaptığınız gibi çerçeveyi değiştirin ve artırın ve kenarlık rengini ekleyin
  2. Geçerli görünümün arkasına, kenarlık olarak görünmesi için daha büyük boyutta bir görünüm ekleyin. Özel bir görünüm sınıfı olarak çalışılabilir
  3. Kesin bir sınıra ihtiyacınız yoksa (net sınır), o zaman amaç için gölgeye güvenebilirsiniz.

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

2

Kenarlığı eklemeden önce kenarlık genişliğine sahip görünüm çerçevesinin genişliğini ve yüksekliğini artırın:

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

Aslında çok basit bir çözüm var. İkisini de şu şekilde ayarlayın:

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

@Picciano çözümünü beğendim Kare yerine patlayan daire istiyorsanız, addExternalBorder işlevini şu şekilde değiştirin :

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

@Picciano ve @Maksim Kniazev'in çözümünü beğendim. Ayrıca aşağıdakilerle dairesel sınır oluşturabiliriz:

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

Storyboard'da UI görünümümün etrafına (ana - SubscriptionAd) bir sınır nasıl yerleştirdim, onu başka bir UI görünümünün (arka plan - Arka Plan Reklamı) içine yerleştirmektir. Arka Plan UIVView, istediğim kenarlık rengiyle eşleşen bir arka plan rengine sahiptir ve Ana UIView, her iki taraftan 2 kısıtlama değerine sahiptir.

Arka plan görünümünü ViewController'ime bağlayacağım ve ardından arka plan rengini değiştirerek kenarlığı açıp kapatacağım.

Her yerde Üst Görünüm 2px kısıtlamaları olan İç İçe UIView Resmi


0

Swift 5

extension UIView {
    fileprivate struct Constants {
        static let externalBorderName = "externalBorder"
    }

    func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white) -> CALayer {
        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.name = Constants.ExternalBorderName

        layer.insertSublayer(externalBorder, at: 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()
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.