2014-11-16 18 views
142

Sto costruendo un'app usando swift nell'ultima versione di Xcode 6 e vorrei sapere come posso modificare il mio pulsante in modo che possa avere un bordo arrotondato che potrei aggiustare io stesso se necessario. Una volta fatto, come posso cambiare il colore del bordo stesso senza aggiungere uno sfondo ad esso? In altre parole, voglio un pulsante leggermente arrotondato senza sfondo, solo un bordo di 1 pixel di un determinato colore.Come posso fare in modo che un pulsante abbia un bordo arrotondato in Swift?

risposta

342

Utilizzare button.layer.cornerRadius, button.layer.borderColor e button.layer.borderWidth. Nota che borderColor richiede un CGColor, quindi si potrebbe dire (Swift 3/4):

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

Ho provato questo, ma ho un piccolo problema il primo testo inizia dal confine stesso, quindi non lo è che bello c'è un modo per risolvere questo – vinbhai4u

+1

@ vinbhai4u Prova a usare "titleEdgeInsets'. –

+1

che funziona come un fascino grazie :) – vinbhai4u

15

ho creato un semplice sublcass UIButton che utilizza il tintColor per i suoi colori di testo e di confine e quando evidenziato cambia il suo background per il 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) 
} 
} 

Questo fa uso di un'estensione UIImage che crea un'immagine da un colore, ho scoperto che il codice qui: https://stackoverflow.com/a/33675160

Funziona meglio quando è impostato su tipo personalizzato nel costruttore di interfaccia come tipo un po 'il sistema di default modifica i colori quando il pulsante è evidenziato.

10

Questa classe è basata su tutti i commenti e suggerimenti in risposta e può anche essere progettata direttamente da xcode. Copia nel tuo progetto e inserisci un UIButton e modifica l'uso della classe personalizzata, ora seleziona il bordo o il colore di sfondo da xcode per gli stati normali e/o evidenziati.

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

Perché importare 'Foundation' quando si importa' UIKit' davvero sufficiente? –

+0

@returntrue Sì hai ragione, Foundation non è necessario, provengo dal modello base xcode originale se non sbaglio. Ho aggiornato il codice. – le0diaz

+0

L'unica cosa è che questo farà circolare il pulsante tutto il tempo. Forse puoi aggiungere una proprietà raggio angolare per risolvere anche questo. – Andreas777

7

In base alla risposta @returntrue, sono riuscito a implementarlo in Interface Builder.

Per ottenere pulsante angoli arrotondati con Interface Builder Aggiungere una chiave Path = "layer.cornerRadius" con Type = "Number" e Value = "10" (o altro valore come richiesto) nel "User Defined RunTime Attribute" della Identity Inspector del pulsante.

+1

Funziona davvero, ma non è specifico di Swift. La domanda chiede esplicitamente come ottenere l'effetto desiderato usando Swift, non usando lo storyboard o simili. –

+1

La mia risposta è stata indirizzata non all'OP ma agli altri lettori che hanno affrontato il mio problema. e solo trovando questo post sono stati in grado di risolvere il problema. Secondo la mia opinione ed esperienza, le risposte non devono essere esattamente a quello che l'OP chiedeva, purché siano correlate ad esso e forniscano informazioni supplementari utili ai lettori. Abbassando le risposte, scoraggiate risposte utili. – Zvi

+1

Anche se questo è generalmente vero, specialmente per le domande generali, questa domanda è chiara nel suo carattere. Esiste una moltitudine di domande che richiedono una soluzione esplicita tramite lo storyboard e, se possibile, i lettori volevano avere una soluzione che utilizza lo storyboard, quindi aggiungere "storyboard" ai termini di ricerca di google è sufficiente per mostrare queste domande. Non sto dicendo che la tua risposta sia negativa, ma piuttosto nel posto sbagliato. –

-1

Penso che il modo più semplice e più pulito, è quello di utilizzare il protocollo per evitare l'ereditarietà e la ripetizione del codice. è possibile modificare questa proprietà direttamente da storyboard

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

Aggiornamento

In questo link potete trovare un esempio con l'utilità di protocollo tracciabile

enter image description here

+2

Non hai davvero bisogno del protocollo qui.Funziona perfettamente senza di esso. –

+1

Ciao @returntrue, non so perché rispondi alla mia risposta ... Penso che tu non l'abbia capito, ti invito a guardare questa sessione: https://developer.apple.com/videos/play/wwdc2015/408/ Perché utilizzare il protocollo? il protocollo consente una maggiore flessibilità, posso avere un'implementazione predefinita, ecc. La mia risposta permette di modificare queste proprietà nello storyboard, e non ho bisogno di ripetere il codice o sottoclasse alcuna classe La tua risposta è corretta ma qui ho condiviso un altro modo per farlo Hai tutte le altre risposte in difetto, dovresti ricordare che Stackoverflow è per condividere le nostre conoscenze prima di guadagnare la reputazione –

+2

Corretto, il tuo codice consente tutte queste cose che hai elencato. MA, poiché UIView è la superclasse di tutti gli elementi dell'interfaccia utente, l'estensione di UIView è sufficiente per eseguire il lavoro. Il protocollo Tracciabile non è richiesto in alcun modo e non produce alcun miglioramento (poiché si traduce semplicemente in UIView - solo UIViews e le sue sottoclassi sono tracciabili). –

8

Per fare questo lavoro nello storyboard (Interface Builder Inspector)

Con l'aiuto di IBDesignable, è possibile aggiungere ulteriori opzioni a Interface Builder Inspector per UIButton e modificarle sullo storyboard. Innanzitutto, aggiungi il seguente codice al tuo progetto.

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

Quindi impostare semplicemente gli attributi per i pulsanti sullo storyboard.

enter image description here

+0

Questa è più o meno una copia della risposta di seguito di Hamza Ghazouani. –

+0

quando uso la soluzione di cui sopra per il boarderColor che genera fallito in interfacebuilder, io uso il codice seguente ma ho successo se ho usato didset piuttosto che set e get. @IBInspectable var borderColor: UIColor = .red {// didSet {// layer.borderColor = borderColor.cgColor //} set { guardia lasciare UIColor = newValue else {} ritorno layer.borderColor = uiColor.cgColor } get { guardia lasciare color = layer.borderColor else {} ritorno pari a zero ritorno UIColor (cgColor: colore) }} –

2

È possibile utilizzare questa sottoclasse di UIButton per personalizzare UIButton secondo i vostri bisogni.

visit this github repo for reference

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

chi downvoted questo, ha u nemmeno di lavorare in questo modo ??? basta non perdere il tuo downvoting di tempo –

+0

Perché un downvote? questo sembra funzionare ed è molto pulito. – ColdGrub1384

+0

@ ColdGrub1384 esattamente :) –

0
@IBOutlet weak var button: UIButton! 

...

penso che per il raggio quel tanto che basta questo parametro:

button.layer.cornerRadius = 5 
+0

Questo non aggiunge nulla di nuovo, a quanto pare. –

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