Swiftでボタンの境界を丸くするにはどうすればよいですか?


232

Xcode 6の最新バージョンでSwiftを使用してアプリを構築しています。ボタンを変更して、必要に応じて自分で調整できる丸い境界線を付ける方法を知りたいです。それが完了したら、背景を追加せずに境界線自体の色を変更するにはどうすればよいですか?言い換えると、背景がなく、特定の色の1ptの境界線だけの、少し丸いボタンが必要です。

回答:


528

使用button.layer.cornerRadiusbutton.layer.borderColorおよびbutton.layer.borderWidth。にはがborderColor必要なCGColorので、(Swift 3/4)と言うことができます:

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

2
私はこれを試しましたが、最初のテキストが境界線自体から始まっているという小さな問題があるので、これを解決する方法はそれほど見栄えがよくありません
vinbhai4u

2
@ vinbhai4uを使用してみてくださいtitleEdgeInsets
trueを返す

ボックスをボタンのテキストよりも大きくするにはどうすればよいですか?
早めに2015

ボタンを参照するためのアウトレットを作成します
Jobs

私はそれをこのように使いたいのですが動作しません:( UIButton.appearance()。layer.cornerRadius = 4
MR

65

ストーリーボードでこの作業を行うには(Interface Builder Inspector)

の助けを借りて、IBDesignableInterface Builder Inspectorにオプションを追加UIButtonして、ストーリーボードで微調整できます。まず、次のコードをプロジェクトに追加します。

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

次に、ストーリーボードのボタンの属性を設定します。

ここに画像の説明を入力してください


4
これは多かれ少なかれ、以下のハムザ・ガゾアニの答えのコピーです。
trueを返す

構築したboarderColorに上記のソリューションを使用すると、interfacebuilderでビルドに失敗しましたが、以下のコードを使用しましたが、set and getではなくdidsetを使用した場合は成功しました。@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} return UIColor(cgColor:color)}}
Amr Angry

1
うわー、魔法のように!ありがとうございました!Google社員-このコードスニペットは、配置するファイルの最後の中括弧の外側に完全に配置してください。コードスニペットは、クラスや関数の内部にあってはなりません
velkoon

24

tintColorテキストと境界線の色にを使用し、ハイライトすると背景がに変わるシンプルなUIButtonサブカルパスを作成しました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)
}
}

これは、色から画像を作成するUIImage拡張機能を利用しています。そのコードは、https://stackoverflow.com/a/33675160です

ボタンが強調表示されたときにデフォルトのシステムタイプが色をわずかに変更するため、インターフェイスビルダーで「カスタム」と入力するように設定した場合に最適です。


13

このクラスは、回答のすべてのコメントと提案に基づいており、xcodeから直接設計することもできます。プロジェクトにコピーしてUIButtonを挿入し、カスタムクラスを使用するように変更します。通常の状態または強調表示された状態のxcodeから境界線または背景色を選択するだけです。

//
//  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
FoundationインポートでUIKit本当に十分なのになぜインポートするのですか?
trueを返す

@returntrueはい、そうです、Foundationは必要ありません。私が間違っていなければ、私は元のxcode基本テンプレートから来ました。コードを更新しました。
le0diaz

唯一のことは、これによりボタンが常に円形になることです。コーナー半径プロパティを追加してこれを修正することもできます。
Andreas777 2017

10

@returntrueの回答に基づいて、私はそれをInterface Builderで実装することができました。

Interface Builderを使用して角の丸いボタンを取得するには、ボタンの" "におよび(または必要に応じて他の値)のキーPath = "layer.cornerRadius"を追加します。Type = "Number"Value = "10"User Defined RunTime AttributeIdentity Inspector


1
これは実際に機能しますが、Swift固有ではありません。質問は、ストーリーボードなどを使用するのではなく、Swiftを使用して目的の効果を達成する方法を明確に尋ねます。
trueを返す

2
私の答えはOPではなく、私の問題に直面した他の読者に向けられました。そして、この投稿を見つけることによってのみ、問題を解決することができました。私の意見と経験では、OPがそれに関係し、読者に役立つ追加情報を提供する限り、回答はOPが要求したものと正確に一致する必要はありません。そのような回答に反対票を投じることで、有用な回答を思いとどまらせます。
Zvi 2016

1
これは一般的に当てはまりますが、特に幅広い質問の場合は、この質問自体の性質が明確です。ストーリーボードを介して明示的な解決策を求める質問が多数存在し、可能であれば読者はストーリーボードを利用するソリューションを望んでおり、これらの質問を表示するにはGoogleの検索用語に「ストーリーボード」を追加するだけで十分です。私はあなたの答えが悪いと言っているのではなく、間違った場所にあります。
trueを返す

この投稿が自分の問題の解決に最も近いことがわかったので、ここに投稿しました。あなたの道を行くということは、私は新しい投稿を書いて私の投稿に答えるべきだったということを意味します。
Zvi 2016

1
私はあなたの問題をこれよりもうまく解決しているように見えるこれらの質問を見つけました:stackoverflow.com/questions/12301256 ; stackoverflow.com/questions/20477990
trueを返す

6

UIButtonのこのサブクラスを使用して、必要に応じてUIButtonをカスタマイズできます。

参照するには、このgithubリポジトリにアクセスしてください

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

誰もがこれに反対票を投じたとしても、あなたはこの方法で作業しようとしましたか???あなたの時間を無駄にしないでください
Nikesh Jha

なぜ反対票か。これは動作するようで、非常にきれいです。
ColdGrub1384 2017年

@ ColdGrub1384正確に:)
Nikesh Jha

3

私は、最も簡単でクリーンな方法は、継承とコードの繰り返しを避けるためにプロトコルを使用することだと思います。このプロパティはストーリーボードから直接変更できます

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

更新

このリンクでは、追跡可能なプロトコルのユーティリティを使用した例を見つけることができます

ここに画像の説明を入力してください


2
ここでは実際にはプロトコルは必要ありません。それなしで完全に正常に動作します。
trueを返す

2
こんにちは@returntrue、なぜあなたが私の回答に反対票を投じたのかわかりません...理解できなかったと思います。このセッションを視聴することを勧めます:developer.apple.com/videos/play/wwdc2015/408なぜプロトコルを使用するのですか?プロトコルにより柔軟性が高まり、デフォルトの実装が可能になるなど、私の答えはストーリーボードでこのプロパティを編集でき、コードを繰り返したり、クラスをサブクラス化したりする必要はありません。あなたの答えは正しいですが、ここでは別の方法を共有しましたit他のすべての回答に反対票を投じます。Stackoverflowは評判を得る前に知識を共有するためのものであることを覚えておく必要があります
Hamza

2
正しい、あなたのコードはあなたがリストしたこれらすべてのものを許可します。ただし、UIViewはすべてのUI要素のスーパークラスであるため、UIView拡張で十分です。プロトコルTraceableは決して必要ではなく、改善もありません(単にUIViewに変換されるため、UIViewsとそのサブクラスのみが追跡可能です)。
trueを返す

1
こんにちは@returntrue、あなたはこのユースケースで正しいです、たぶん、プロトコルは必要ありませんが、これにより柔軟性が増します。たとえば、適用するデフォルト値を追加して、UIImageViewとUIButtonでのみ使用できます。この例で私の答えを更新します:)
Hamza

1
角の半径や境界線の色などのプロパティにデフォルト値を適用することは実際には意味がありません。これらの値は、意味のある方法で、UIの各ビューインスタンスに個別に適用する必要があります。
trueを返す

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

脇のヒントとして、ボタンがストーリーボードのカスタムクラスのサブクラスではないことを確認してください。このような場合、コードの最適な場所はカスタムクラスにする必要があります。ボタンがデフォルトのサブクラスの場合、コードはカスタムクラスからのみ機能します。 UIButtonクラスとそのアウトレット。これにより、コーナーラジオがコードから私のボタンに適用されない理由を誰かが疑問に思う人に役立つことを願っています。



0

THIS TRY 角の丸いボタンのボーダーを

anyButton.backgroundColor = .clear

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

anyButton.layer.borderWidth = 1

anyButton.layer.borderColor = UIColor.black.cgColor

そうですが、動的なcornerRadiusを使用するという考え方が導入されています。単にコピーして貼り付けただけではないと思います。
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

StoryBoardの「属性インスペクター」を介してカスタムボタンパラメーターを構成できるように、サブクラス化UIButtonして@IBInspectable変数を追加できます。以下にそのコードを書き留めます。

@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

シンプルな形だと思います

        Button1.layer.cornerRadius = 10(Half of the length and width)
        Button1.layer.borderWidth = 2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.