Swift에서 버튼에 둥근 테두리를 만들려면 어떻게해야합니까?


232

최신 버전의 Xcode 6에서 swift를 사용하여 앱을 작성 중이며 둥근 버튼을 사용하여 필요할 때 직접 조정할 수 있도록 버튼을 수정하는 방법을 알고 싶습니다. 완료되면 배경을 추가하지 않고 테두리 자체의 색상을 어떻게 변경할 수 있습니까? 즉, 배경이없는 약간 둥근 버튼, 특정 색상의 1pt 테두리 만 원합니다.

답변:


528

사용 button.layer.cornerRadius, button.layer.borderColorbutton.layer.borderWidth. 참고 borderColor을 필요로 CGColor당신이 말할 수 있도록, (스위프트 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 반환

상자를 버튼 텍스트보다 크게 만들려면 어떻게해야합니까?
Sooner

버튼을 참조 할 수있는 콘센트 만들기
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
이것은 Hamza Ghazouani의 답변의 사본입니다.
true를 반환

boarderColor에 대해 위의 솔루션을 사용할 때 interfacebuilder에서 빌드가 실패했습니다. 아래 코드를 사용하지만 설정하고 가져 오는 대신 didset을 사용하면 성공합니다. @IBInspectable var borderColor : UIColor = .red {// didSet {// layer.borderColor = borderColor.cgColor //} set {guard let uiColor = newValue else {return} layer.borderColor = uiColor.cgColor} get {가드 색상 지정 = layer.borderColor else {return nil} return UIColor (cgColor : color)}}
Amr Angry

1
와우, 마술처럼! 감사합니다! Google 직원 - 어떤 클래스 또는 함수 내에서해서는 안됩니다 코드 - 완전히 외부 당신이에 배치하고있는 파일에 매우 마지막 중괄호의 스 니펫이 코드를 넣어 확인
velkoon

24

tintColor텍스트 및 테두리 색상에 대해 를 사용하고 강조 표시되면 배경이로 변경 되는 간단한 UIButton sublcass를 만들었습니다 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

10

@returntrue 답변을 바탕으로 Interface Builder에서 구현했습니다.

인터페이스 빌더가 키를 추가 사용하여 모서리가 둥근 버튼을 얻으려면 Path = "layer.cornerRadius"함께 Type = "Number"하고 Value = "10"은 "에서 (또는 필요에 따라 다른 값) User Defined RunTime Attribute"의 Identity Inspector버튼의.


1
이것은 실제로 작동하지만 Swift와는 다릅니다. 이 질문은 스토리 보드 등을 사용하지 않고 Swift를 사용하여 원하는 효과를 얻는 방법을 명시 적으로 묻습니다.
true를 반환

2
내 대답은 OP가 아니라 내 문제에 직면 한 다른 독자들에게 지시되었습니다. 이 게시물을 찾아서 만 문제를 해결할 수있었습니다. 제 의견과 경험에 따르면, OP와 관련이 있고 독자에게 유용한 추가 정보를 제공하는 한 OP가 요청한 내용과 정확히 일치하는 것은 아닙니다. 그러한 답변을 투표하지 않으면 유용한 답변을 권장하지 않습니다.
Zvi

1
이것은 광범위한 질문에 대해 일반적으로 사실이지만이 질문의 성격은 명확합니다. 스토리 보드를 통해 명시적인 솔루션을 요구하는 여러 가지 질문이 있으며 가능한 독자는 스토리 보드를 활용하는 솔루션을 원한 다음 Google 검색어에 "스토리 보드"를 추가하면 이러한 질문을 표시 할 수 있습니다. 나는 당신의 대답이 나쁘다는 것이 아니라 잘못된 장소에 있다고 말합니다.
true를 반환

이 게시물이 내 문제를 해결하는 데 가장 가까운 것으로 확인되었으므로 여기에 게시했습니다. 당신의 길을가는 것은 내가 새로운 게시물을 작성하고 내 게시물에 대답해야한다는 것을 의미합니다.
Zvi

1
이 질문보다 문제를 더 잘 해결하는 것으로 보이는 질문을 찾았습니다. stackoverflow.com/questions/12301256 ; stackoverflow.com/questions/20477990
true가 돌려

6

이 UIButton 하위 클래스를 사용하여 필요에 따라 UIButton을 사용자 정의 할 수 있습니다.

이 github repo를 방문하여 참조하십시오

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

누구든지 유 심지어 ??? 당신의 시간 downvoting 낭비 그나마 이런 식으로 작업하려고 않았다,이을 downvoted
소재한 산 제이

왜 공감해야합니까? 이것은 작동하는 것으로 보이며 매우 깨끗합니다.
ColdGrub1384

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

최신 정보

링크 에서 Traceable protocol 유틸리티를 사용하여 예를 찾을 수 있습니다.

여기에 이미지 설명을 입력하십시오


2
여기에는 실제로 프로토콜이 필요하지 않습니다. 그것없이 완벽하게 작동합니다.
반환

2
안녕하세요 @returntrue, 왜 당신이 내 대답을 공감해야하는지 모르겠습니다 ... 이해하지 못했다고 생각합니다. developer.apple.com/videos/play/wwdc2015/408 프로토콜을 사용하는 이유는 무엇입니까? 프로토콜은 유연성을 높이고 기본 구현을 할 수 있습니다. 내 답변은 스토리 보드 에서이 속성을 편집 할 수 있으며 코드를 반복하거나 클래스를 서브 클래스 할 필요가 없습니다. 답은 정확하지만 여기에서 다른 방법을 공유했습니다. 그것은 당신이 다른 모든 답변을 downvote, 당신은 명성을 얻기 전에 우리의 지식을 공유하기위한 Stackoverflow
Hamza

2
맞습니다. 코드는 나열된 모든 것을 허용합니다. 그러나 UIView는 모든 UI 요소의 수퍼 클래스이므로 UIView 확장은 작업을 수행하기에 충분합니다. 프로토콜 Traceable은 어떤 방식으로도 필요하지 않으며 개선되지 않습니다 (단순히 UIView로 변환되므로 UIView 및 해당 서브 클래스 만 추적 가능함).
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

둥근 모서리가있는 단추 테두리 시도

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 "Attribute Inspector"를 통해 사용자 정의 단추 매개 변수를 구성 할 수 있도록 서브 클래스를 작성 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.