Swift'te bir düğmenin yuvarlatılmış kenarlığı nasıl alabilirim?


232

Xcode 6'nın en son sürümünde swift kullanarak bir uygulama oluşturuyorum ve düğmemi nasıl değiştirebileceğimi bilmek istiyorum, böylece gerekirse kendimi ayarlayabileceğim yuvarlak bir kenarlık olabilir. Bu yapıldıktan sonra, arka plan eklemeden kenarlığın rengini nasıl değiştirebilirim? Başka bir deyişle, arka planı olmayan, sadece belirli bir rengin sadece 1 pt'lik bir kenarlığı olan hafif yuvarlak bir düğme istiyorum.

Yanıtlar:


528

Kullanın button.layer.cornerRadius, button.layer.borderColorve button.layer.borderWidth. Bunu borderColorgerektiren bir not CGColor, böylece şunu söyleyebilirsiniz (Swift 3/4):

button.backgroundColor = .clear
button.layer.cornerRadius = 5
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.black.cgColor

2
Bunu denedim, ancak küçük bir sorunum var ilk metin kenarlığın kendisinden başlıyor, bu yüzden iyi görünümlü değil bunu çözmek için herhangi bir yol yoktur
vinbhai4u

2
@ vinbhai4u Kullanmayı deneyin titleEdgeInsets.
Gerçek dönüş

kutuyu düğme metninden daha büyük hale nasıl getirebiliriz?
Yakında

düğmeye başvurmak için bir çıkış oluşturun
Jobs

i böyle kullanmak istiyorum ama çalışmıyor :( UIButton.appearance (). layer.cornerRadius = 4
MR

65

Bu işi film şeridinde yapmak için (Interface Builder Inspector)

Yardımı IBDesignableile Arayüz Oluşturucu Denetçisine daha fazla seçenek ekleyebilir UIButtonve bunları storyboard'da düzenleyebiliriz . İlk olarak, projenize aşağıdaki kodu ekleyin.

@IBDesignable extension UIButton {

    @IBInspectable var borderWidth: CGFloat {
        set {
            layer.borderWidth = newValue
        }
        get {
            return layer.borderWidth
        }
    }

    @IBInspectable var cornerRadius: CGFloat {
        set {
            layer.cornerRadius = newValue
        }
        get {
            return layer.cornerRadius
        }
    }

    @IBInspectable var borderColor: UIColor? {
        set {
            guard let uiColor = newValue else { return }
            layer.borderColor = uiColor.cgColor
        }
        get {
            guard let color = layer.borderColor else { return nil }
            return UIColor(cgColor: color)
        }
    }
}

Ardından, film şeridindeki düğmelerin özelliklerini ayarlayın.

resim açıklamasını buraya girin


4
Bu, Hamza Ghazouani'nin cevabının aşağı yukarı bir kopyasıdır.
gerçek

Ben interfacebuilder inşa başarısız boarderColor için yukarıdaki çözümü kullandığınızda, ben aşağıdaki kodu kullanın ama ben yerine set ve olsun didset kullandıysanız ben başarı. @IBInspectable var borderColor: UIColor = .red {// didSet {// layer.borderColor = borderColor.cgColor //} set {guard let uiColor = newValue else {return} layer.borderColor = uiColor.cgColor} get {guard let color = layer.borderColor else {return nil} dönüş UIColor (cgColor: renk)}}
Amr Angry

1
Vay be, sihir gibi! Teşekkür ederim! Google çalışanları - bu kod snippet'ini, yerleştirdiğiniz dosyadaki son küme parantezinizin tamamen dışına koyduğunuzdan emin olun - kod snippet'i herhangi bir sınıf veya işlevin içinde olmamalıdır
velkoon

24

tintColorMetin ve kenarlık renklerini kullanan ve vurgulandığında arka planını değiştirdiği basit bir UIButton sublcass oluşturdum tintColor.

class BorderedButton: UIButton {

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    layer.borderWidth = 1.0
    layer.borderColor = tintColor.CGColor
    layer.cornerRadius = 5.0
    clipsToBounds = true
    contentEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
    setTitleColor(tintColor, forState: .Normal)
    setTitleColor(UIColor.whiteColor(), forState: .Highlighted)
    setBackgroundImage(UIImage(color: tintColor), forState: .Highlighted)
}
}

Bu, bir renkten bir görüntü oluşturan bir UIImage uzantısını kullanır, bu kodu burada buldum: https://stackoverflow.com/a/33675160

Arabirim oluşturucuda Özel olarak ayarlandığında en iyi sonucu verir, çünkü varsayılan Sistem türü düğme vurgulandığında renkleri biraz değiştirir.


13

Bu sınıf, cevaplardaki tüm yorum ve önerilere dayanmaktadır ve ayrıca doğrudan xcode'dan da tasarlanabilir. Projenize kopyalayın ve herhangi bir UIBdüğmesi ekleyin ve özel sınıfı kullanmak için değiştirin, şimdi normal ve / veya vurgulanan durumlar için xcode'dan kenarlık veya arka plan rengini seçin.

//
//  RoundedButton.swift
//

import UIKit

@IBDesignable
class RoundedButton:UIButton {

    @IBInspectable var borderWidth: CGFloat = 0 {
        didSet {
            layer.borderWidth = borderWidth
        }
    }
    //Normal state bg and border
    @IBInspectable var normalBorderColor: UIColor? {
        didSet {
            layer.borderColor = normalBorderColor?.CGColor
        }
    }

    @IBInspectable var normalBackgroundColor: UIColor? {
        didSet {
            setBgColorForState(normalBackgroundColor, forState: .Normal)
        }
    }


    //Highlighted state bg and border
    @IBInspectable var highlightedBorderColor: UIColor?

    @IBInspectable var highlightedBackgroundColor: UIColor? {
        didSet {
            setBgColorForState(highlightedBackgroundColor, forState: .Highlighted)
        }
    }


    private func setBgColorForState(color: UIColor?, forState: UIControlState){
        if color != nil {
            setBackgroundImage(UIImage.imageWithColor(color!), forState: forState)

        } else {
            setBackgroundImage(nil, forState: forState)
        }
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        layer.cornerRadius = layer.frame.height / 2
        clipsToBounds = true

        if borderWidth > 0 {
            if state == .Normal && !CGColorEqualToColor(layer.borderColor, normalBorderColor?.CGColor) {
                layer.borderColor = normalBorderColor?.CGColor
            } else if state == .Highlighted && highlightedBorderColor != nil{
                layer.borderColor = highlightedBorderColor!.CGColor
            }
        }
    }

}

//Extension Required by RoundedButton to create UIImage from UIColor
extension UIImage {
    class func imageWithColor(color: UIColor) -> UIImage {
        let rect: CGRect = CGRectMake(0, 0, 1, 1)
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, 1), false, 1.0)
        color.setFill()
        UIRectFill(rect)
        let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

1
İçe Foundationaktarırken neden içe aktarma UIKitgerçekten yeterli?
Gerçek dönüş

@returntrue Evet haklısın, Vakıf gerekli değil, eğer yanlış değilsem orijinal xcode temel şablonundan geldim. Kodu güncelledim.
le0diaz

Tek şey, düğmeyi her zaman dairesel hale getirecek olmasıdır. Belki bunu düzeltmek için bir köşe yarıçapı özelliği ekleyebilirsiniz.
Andreas777

10

@Returntrue yanıtına dayanarak, bunu Interface Builder'da uygulamayı başardım.

Arayüz Oluşturucu'yu kullanarak yuvarlak köşeler düğmesi almak için , düğmenin " " bölümüne ve (veya gerektiği gibi başka bir değer) Path = "layer.cornerRadius"içeren bir Anahtar ekleyin .Type = "Number"Value = "10"User Defined RunTime AttributeIdentity Inspector


1
Bu gerçekten işe yarıyor, ancak Swift'e özgü değil. Soru, film şeridi veya benzeri değil, Swift kullanarak istenen efekti nasıl elde edeceğini açıkça soruyor.
gerçek dönüş

2
Cevabım OP'ye değil, sorunumla karşılaşan diğer okuyuculara yöneltildi. ve sadece bu gönderiyi bularak sorunu çözebildik. Benim düşünceme ve tecrübeme göre, cevaplar OP ile ilgili olduğu sürece okudukları soruya tam olarak sahip değildir ve okuyucular için yararlı olan ek bilgiler vermez. Bu tür cevapları aşağıya doğru oylayarak yararlı cevapları caydırırsınız.
Zvi

1
Bu genellikle doğru olsa da - özellikle geniş sorular için - bu soru karakterinde açıktır. Film şeridi aracılığıyla açık bir çözüm isteyen çok sayıda soru var ve mümkünse okuyucular film şeridini kullanan bir çözüme sahip olmak istediler, ardından google arama terimlerine "film şeridi" eklemek bu soruları göstermek için yeterli. Cevabınızın kötü olduğunu değil, yanlış yerde olduğunu söylemiyorum.
Gerçek dönüş

Bu gönderiyi sorunumu ele almaya en yakın bulduğum için buraya gönderdim. Yolunuza gitmek, yeni bir yazı yazmam ve yazıma cevap vermem gerektiği anlamına geliyor, ki bu bana göre biraz abartılı görünüyor.
Zvi

1
Sorununuzu bundan daha iyi ele almış gibi görünen soruları buldum: stackoverflow.com/questions/12301256 ; stackoverflow.com/questions/20477990
geri dönüş

6

UIButton'u ihtiyaçlarınıza göre özelleştirmek için bu UIButton alt sınıfını kullanabilirsiniz.

referans için bu github deposunu ziyaret edin

class RoundedRectButton: UIButton {

    var selectedState: Bool = false

    override func awakeFromNib() {
        super.awakeFromNib()
        layer.borderWidth = 2 / UIScreen.main.nativeScale
        layer.borderColor = UIColor.white.cgColor
        contentEdgeInsets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
    }


    override func layoutSubviews(){
        super.layoutSubviews()
        layer.cornerRadius = frame.height / 2
        backgroundColor = selectedState ? UIColor.white : UIColor.clear
        self.titleLabel?.textColor = selectedState ? UIColor.green : UIColor.white
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        selectedState = !selectedState
        self.layoutSubviews()
    }
}

kim bu aşağı indirdi, u bile bu şekilde çalışmaya çalıştım ??? sadece zaman aşağı boşa harcamayın
Nikesh Jha

Neden inişli çıkışlı? Bu çalışıyor gibi görünüyor ve çok temiz.
ColdGrub1384

@ ColdGrub1384 tam olarak :)
Nikesh Jha

3

Bence en kolay ve en temiz yol, miras ve kod tekrarını önlemek için protokol kullanmaktır. Bu özellikleri doğrudan film şeridinden değiştirebilirsiniz

protocol Traceable {
    var cornerRadius: CGFloat { get set }
    var borderColor: UIColor? { get set }
    var borderWidth: CGFloat { get set }
}

extension UIView: Traceable {

    @IBInspectable var cornerRadius: CGFloat {
        get { return layer.cornerRadius }
        set {
            layer.masksToBounds = true
            layer.cornerRadius = newValue
        }
    }

    @IBInspectable var borderColor: UIColor? {
        get {
            guard let cgColor = layer.borderColor else { return nil }
            return  UIColor(cgColor: cgColor)
        }
        set { layer.borderColor = newValue?.cgColor }
    }

    @IBInspectable var borderWidth: CGFloat {
        get { return layer.borderWidth }
        set { layer.borderWidth = newValue }
    }
}

Güncelleme

Bu linkte İzlenebilir protokolün yardımcı programını içeren bir örnek bulabilirsiniz

resim açıklamasını buraya girin


2
Burada protokole gerçekten ihtiyacınız yok. Onsuz tamamen iyi çalışır.
gerçek dönüş

2
Merhaba @returntrue, cevabımı neden indirdiğinizi bilmiyorum ... Sanırım anlamadınız, sizi bu oturumu izlemeye davet ediyorum: developer.apple.com/videos/play/wwdc2015/408 Neden protokolü kullanıyorsunuz? protokol daha fazla esneklik sağlar, vb varsayılan uygulama olabilir, Cevabım film şeridinde bu özellikleri düzenlemek için izin verir ve herhangi bir sınıf kodu tekrarlamak veya herhangi bir sınıf alt sınıf gerekmez Cevabınız doğru ama burada başka bir yol paylaştı Diğer tüm cevapları küçümsersiniz, Stackoverflow'un itibar kazanmadan önce bilgilerimizi paylaşmak için olduğunu hatırlamanız gerekir
Hamza

2
Doğru, kodunuz listelediğiniz tüm bu şeylere izin verir. AMA, UIView tüm UI öğelerinin üst sınıfı olduğundan UIView uzantınız işi yapmak için yeterlidir. İzlenebilir protokol herhangi bir şekilde gerekli değildir ve herhangi bir iyileştirme sağlamaz (sadece UIView anlamına gelir - sadece UIViews ve alt sınıfları izlenebilir).
gerçek dönüş

1
merhaba @returntrue, bu kullanım durumunda haklısın, olabilir, protokole ihtiyacımız yok, ancak onunla daha fazla esnekliğe sahibiz ve örneğin, uygulamak için varsayılan değerler ekleyebiliriz ve sadece UIImageView ve UIButton için kullanılabilir, ben cevabımı bu örnekle güncelleyeceğim :)
Hamza

1
Köşe yarıçapı veya kenarlık rengi gibi özellikler için varsayılan değerlerin uygulanması gerçekten mantıklı değildir. Bu değerler arayüzünde her görünüm örneğine uygulanması gerektiğini ayrı ayrı anlamlı bir şekilde.
Gerçek dönüş

3
   @IBOutlet weak var yourButton: UIButton! {
        didSet{
            yourButton.backgroundColor = .clear
            yourButton.layer.cornerRadius = 10
            yourButton.layer.borderWidth = 2
            yourButton.layer.borderColor = UIColor.white.cgColor
        }
    }

1

bir kenara ipucu, düğmenizin hikaye panosunda herhangi bir özel sınıfın alt sınıfı olmadığından emin olun, bu durumda kodunuzun en iyi yeri özel sınıfta olmalıdır, çünkü düğmeniz varsayılanın alt sınıfı ise kodun yalnızca özel sınıfın dışında çalışmasına neden olur UIButton sınıfı ve çıkışı, umarım bu herkesin köşe radyolarının neden düğmeme uygulanmadığını merak etmesine yardımcı olabilir.


0
@IBOutlet weak var button: UIButton!

...

Yarıçap için yeterli bu parametre düşünüyorum:

button.layer.cornerRadius = 5

Bu yeni bir şey eklemiyor, öyle görünüyor.
gerçek

0

TRY BU Düğme Kenarları Yuvarlatılmış Köşeli

anyButton.backgroundColor = .clear

anyButton.layer.cornerRadius = anyButton.frame.height / 2

anyButton.layer.borderWidth = 1

anyButton.layer.borderColor = UIColor.black.cgColor

evet, ama dinamik bir köşe kullanma fikrini tanıtıyor, sadece kopyalanıp yapıştırıldığını sanmıyorum.
benc

0
import UIKit

@IBDesignable
class RoundedButton: UIButton {
    
    @IBInspectable var cornerRadius: CGFloat = 8
    @IBInspectable var borderColor: UIColor? = .lightGray
    
    override func draw(_ rect: CGRect) {
        layer.cornerRadius = cornerRadius
        layer.masksToBounds = true
        layer.borderWidth = 1
        layer.borderColor = borderColor?.cgColor
        
    }
    
    
}

-1

Özel düğme parametrelerini StoryBoard "Attribute Inspector" aracılığıyla yapılandırabilmeniz için alt sınıfları oluşturabilir UIButtonve @IBInspectabledeğişkenler ekleyebilirsiniz . Aşağıda bu kodu yazıyorum.

@IBDesignable
class BHButton: UIButton {

    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

    @IBInspectable lazy var isRoundRectButton : Bool = false

    @IBInspectable public var cornerRadius : CGFloat = 0.0 {
        didSet{
            setUpView()
        }
    }

    @IBInspectable public var borderColor : UIColor = UIColor.clear {
        didSet {
            self.layer.borderColor = borderColor.cgColor
        }
    }

    @IBInspectable public var borderWidth : CGFloat = 0.0 {
        didSet {
            self.layer.borderWidth = borderWidth
        }
    }

    //  MARK:   Awake From Nib

    override func awakeFromNib() {
        super.awakeFromNib()
        setUpView()
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setUpView()
    }

    func setUpView() {
        if isRoundRectButton {
            self.layer.cornerRadius = self.bounds.height/2;
            self.clipsToBounds = true
        }
        else{
            self.layer.cornerRadius = self.cornerRadius;
            self.clipsToBounds = true
        }
    }

}

-1

Bence bu basit bir form

        Button1.layer.cornerRadius = 10(Half of the length and width)
        Button1.layer.borderWidth = 2
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.