简体   繁体   English

Swift UI 中具有圆角半径的按钮边框

[英]Button border with corner radius in Swift UI

I'm trying to set a rounded border to a button but the border of the button is not correct.我正在尝试为按钮设置圆角边框,但按钮的边框不正确。

Code:代码:

Button(action: {
        print("sign up bin tapped")          
}) {
    Text("SIGN UP")
      .frame(minWidth: 0, maxWidth: .infinity)
      .font(.system(size: 18))
      .padding()
      .foregroundColor(.white)
 }
  .border(Color.white, width: 2)
  .cornerRadius(25)

Output: Output:

在此处输入图像描述

As you can see the border at corner are cut-off.如您所见,拐角处的边界被切断。

Any suggestion what am I doing wrong?任何建议我做错了什么?

Try it like this: Instead of setting the cornerRadius to the Button use an overlay for the inside View:像这样尝试:不要将cornerRadius设置为Button,而是使用内部视图的叠加层:

Edit: If you have a background for the button you also need to apply the cornerRadius to the background.编辑:如果您有按钮的背景,您还需要将cornerRadius 应用于背景。

    Button(action: {
        print("sign up bin tapped")
    }) {
        Text("SIGN UP")
            .frame(minWidth: 0, maxWidth: .infinity)
            .font(.system(size: 18))
            .padding()
            .foregroundColor(.white)
            .overlay(
                RoundedRectangle(cornerRadius: 25)
                    .stroke(Color.white, lineWidth: 2)
        )
    }
    .background(Color.yellow) // If you have this
    .cornerRadius(25)         // You also need the cornerRadius here
    

Works for me.为我工作。 Let me know if it helps!让我知道它是否有帮助!

Updated for Swift 5 & iOS 13.4+ with Press States!更新了 Swift 5 和 iOS 13.4+ 与新闻状态!

None of the examples worked for buttons with both dark and white background colors as well as none of them had press state updates, so I built this LargeButton view that you can see below.这些示例都不适用于同时具有深色和白色背景 colors 的按钮,而且它们都没有按 state 更新,所以我构建了这个您可以在下面看到的LargeButton视图。 Hope this helps, should be pretty simple to use!希望这会有所帮助,应该很容易使用!

Example Photos示例照片

在此处输入图像描述

Example Use示例使用

// White button with green border.
LargeButton(title: "Invite a Friend", 
            backgroundColor: Color.white, 
            foregroundColor: Color.green) {
                        print("Hello World")
                    }

// Yellow button without a border
LargeButton(title: "Invite a Friend", 
            backgroundColor: Color.yellow) {
                        print("Hello World")
                    }

Code代码

struct LargeButtonStyle: ButtonStyle {
    
    let backgroundColor: Color
    let foregroundColor: Color
    let isDisabled: Bool
    
    func makeBody(configuration: Self.Configuration) -> some View {
        let currentForegroundColor = isDisabled || configuration.isPressed ? foregroundColor.opacity(0.3) : foregroundColor
        return configuration.label
            .padding()
            .foregroundColor(currentForegroundColor)
            .background(isDisabled || configuration.isPressed ? backgroundColor.opacity(0.3) : backgroundColor)
            // This is the key part, we are using both an overlay as well as cornerRadius
            .cornerRadius(6)
            .overlay(
                RoundedRectangle(cornerRadius: 6)
                    .stroke(currentForegroundColor, lineWidth: 1)
        )
            .padding([.top, .bottom], 10)
            .font(Font.system(size: 19, weight: .semibold))
    }
}

struct LargeButton: View {
    
    private static let buttonHorizontalMargins: CGFloat = 20
    
    var backgroundColor: Color
    var foregroundColor: Color
    
    private let title: String
    private let action: () -> Void
    
    // It would be nice to make this into a binding.
    private let disabled: Bool
    
    init(title: String,
         disabled: Bool = false,
         backgroundColor: Color = Color.green,
         foregroundColor: Color = Color.white,
         action: @escaping () -> Void) {
        self.backgroundColor = backgroundColor
        self.foregroundColor = foregroundColor
        self.title = title
        self.action = action
        self.disabled = disabled
    }
    
    var body: some View {
        HStack {
            Spacer(minLength: LargeButton.buttonHorizontalMargins)
            Button(action:self.action) {
                Text(self.title)
                    .frame(maxWidth:.infinity)
            }
            .buttonStyle(LargeButtonStyle(backgroundColor: backgroundColor,
                                          foregroundColor: foregroundColor,
                                          isDisabled: disabled))
                .disabled(self.disabled)
            Spacer(minLength: LargeButton.buttonHorizontalMargins)
        }
        .frame(maxWidth:.infinity)
    }
}

Official .bordered modifier support in iOS 15+ iOS 15+ 中的官方.bordered修饰符支持

Button s now have baked in border styling support using the .buttonStyle(.bordered) modifier. Button现在已经使用.buttonStyle(.bordered)修饰符获得了边框样式支持。 I would suggest using the corner radius Apple provides for these buttons for the best platform-specific styling.我建议使用 Apple 为这些按钮提供的圆角半径,以获得最佳的特定于平台的样式。 We can change the color to be consistent with the system styles for buttons and tint the background as well as text using the .tint modifier:我们可以将颜色更改为与系统 styles 的按钮一致,并使用.tint修饰符为背景和文本着色:

Button("Add") { ... }
.buttonStyle(.bordered)
.tint(.green)

绿色色调按钮

You can make the tint color more prominent (bolder) using .borderedProminent and control the size using .controlSize :您可以使用.controlSize使色调颜色更加突出(更大胆)并使用.borderedProminent控制大小:

Button("food") { ... }
.tint(.red)
.controlSize(.small) // .large, .medium or .small
.buttonStyle(.borderedProminent)

小按钮

You can also use this modifier on parent View s of Button s and toggle lighter color schemes using .accentColor in child Button s:您还可以在Button的父View上使用此修饰符,并在子Button中使用.accentColor切换较浅的配色方案:

ScrollView {
    LazyVStack {
        Button("Test Button 1") { ... }
        .buttonStyle(.borderedProminent)
        .keyboardShortcut(.defaultAction) // Tapping `Return` key actions this button

        Button("Test Button 2") { ... }
        .tint(.accentColor)
    }
}
.buttonStyle(.bordered)
.controlSize(.large)

大按钮样式

Advice建议

Apple for some reason doesn't like single-line bordered buttons which is why the .border() modifier was deprecated in Xcode 12. With this change, I suggest developers avoid creating single-line bordered buttons because they now are not preferred in Apple's Human Interface Guidelines. Apple 出于某种原因不喜欢单线边框按钮,这就是为什么.border()修饰符在 Xcode 12 中被弃用的原因。通过此更改,我建议开发人员避免创建单线边框按钮,因为它们现在在 Apple 的人机界面指南。 Using prominent buttons everywhere also violates HIG.在任何地方使用突出的按钮也违反了 HIG。

Extra NOTE: Apple's .bordered style provides the standard platform style across device types.额外注意:Apple 的.bordered样式提供跨设备类型的标准平台样式。 In addition, the Button responds to Dark Mode dynamically and scales its size with Dynamic Type (native accessibility support).此外, Button动态响应暗模式并使用动态类型(本机可访问性支持)缩放其大小。

Swift 5 & iOS 14 – Borders also react when pressed Swift 5 & iOS 14 – 按下时边框也会反应

struct PrimaryButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding(5)
            .foregroundColor(configuration.isPressed ? Color.red.opacity(0.5) : .red)
            .overlay(
                RoundedRectangle(cornerRadius: 8)
                    .stroke(configuration.isPressed ? Color.red.opacity(0.5) : .red, lineWidth: 1.5)
            )
     }
}

How to use如何使用

Button("Hide") {
    print("tapped")
}.buttonStyle(PrimaryButtonStyle())

borders also react when pressed边框在按下时也会做出反应

Just add the cornerRadius argument:只需添加cornerRadius参数:

.border(Color.white, width: 2, cornerRadius: 25)

using this simple extension :使用这个简单的扩展

extension View {
    func border(_ color: Color, width: CGFloat, cornerRadius: CGFloat) -> some View {
        overlay(RoundedRectangle(cornerRadius: cornerRadius).stroke(color, lineWidth: width))
    }
}

预习

Xcode 11.4.1 Xcode 11.4.1

                            Button(action: self.action) {
                                Text("Button Name")
                                    .font(.system(size: 15))
                                    .fontWeight(.bold)
                                    .foregroundColor(.white)
                                    .padding(10)
                                    .background(Color.darkGray)
                                    .cornerRadius(10)
                            }
                            .buttonStyle(PlainButtonStyle())

There isn't a need to add an overlay.无需添加叠加层。 You can substitute padding modifier with frame modifier.您可以用帧修饰符替换填充修饰符。 The action is a non return method outside of the body variable.该操作是主体变量之外的非返回方法。

Right specifically for @MinonWeerasinghe:专门针对@MinonWeerasinghe:

Button(action: self.action) {
            Text("Button Name")
                .font(.system(size: 15))
                .fontWeight(.bold)
                .foregroundColor(.black)
                .padding(10)
                .background(RoundedRectangle(cornerRadius: 10).stroke().foregroundColor(Color.red))
                .cornerRadius(10)
        }
        .buttonStyle(PlainButtonStyle())

You can try this:你可以试试这个:

var body: some View {
        ZStack {
            Color.green
            .edgesIgnoringSafeArea(.all)

            HStack {
            Button(action: {
                    print("sign up bin tapped")
            }){
                HStack {
                    Text("SIGN UP")
                        .font(.system(size: 18))
                    }
                .frame(minWidth: 0, maxWidth: 300)
                .padding()
                .foregroundColor(.white)
                .overlay(
                    RoundedRectangle(cornerRadius: 40)
                        .stroke(Color.white, lineWidth: 2)
                )

                }
            }
        }
    }

I also did not set the maxWidth to.infinity because it means the button will fill the width of your container view.我也没有将 maxWidth 设置为.infinity,因为这意味着按钮将填充容器视图的宽度。

The result will be:结果将是:

在此处输入图像描述

Hope it helps:)希望能帮助到你:)

This worked for me这对我有用

Button(action: {
  print("Exit the onboarding")
}) {
HStack (spacing: 8) {
  Text("NEXT")
  .foregroundColor(Color("ColorAccentOppBlack"))
}
.padding(.horizontal, 16)
.padding(.vertical, 10)
.foregroundColor(Color("ColorYellowButton"))
.background(
   Capsule().strokeBorder(Color("ColorYellowButton"), lineWidth: 1.25)
 )
} 
.accentColor(Color("ColorYellowButton"))

You should use Capsule.你应该使用胶囊。 This is built-in into SwiftUI.这是内置在 SwiftUI 中的。 It takes care of rounded corners.它照顾圆角。 Full implementation is here https://redflowerinc.com/how-to-implement-rounded-corners-for-buttons-in-swiftui/完整的实现在这里https://redflowerinc.com/how-to-implement-rounded-corners-for-buttons-in-swiftui/

public struct ButtonStyling : ButtonStyle {
    public var type: ButtonType
    public init(type: ButtonType = .light) {
        self.type = type
    }
    public func makeBody(configuration: Configuration) -> some View {
        configuration.label.foregroundColor(Color.white)
            .padding(EdgeInsets(top: 12,
                                   leading: 12,
                                   bottom: 12,
                                   trailing: 12))
               .background(AnyView(Capsule().fill(Color.purple)))
               .overlay(RoundedRectangle(cornerRadius: 0).stroke(Color.gray, lineWidth: 0))
    }
}

在此处输入图像描述

To create a border with rounded corners, you can draw a rounded rectangle and overlay on the button like this:要创建带圆角的边框,您可以绘制一个圆角矩形并覆盖在按钮上,如下所示:

  Button(action: {
        print("Hello button tapped!")
    }) {
        Text("Hello World")
            .fontWeight(.bold)
            .font(.title)
            .foregroundColor(.purple)
            .padding()
            .overlay(
                RoundedRectangle(cornerRadius: 20)
                    .stroke(Color.purple, lineWidth: 5)
            )
    }

在此处输入图像描述

Swift version 5.6 You can use Button properties for example Swift 5.6 版您可以使用按钮属性,例如

       Button(action: {
            //define action
        }) {
            Image(systemName: "arrow.triangle.2.circlepath.circle.fill")
                .imageScale(.large)
            Text("Restart")
                .font(.system(.title2))
        }
        .buttonStyle(.borderedProminent)
        .buttonBorderShape(.capsule)
        .controlSize(.large)

在此处输入图像描述

        .buttonBorderShape(.roundedRectangle) //change bordershape see below

在此处输入图像描述

        .buttonBorderShape(.roundedRectangle(radius: 4)) // see below

在此处输入图像描述

similarly you can change the buttonSytle and controlSize同样,您可以更改buttonSytlecontrolSize

Wonder how to add button border with color gradient and corner radius Here's how..想知道如何使用颜色渐变和角半径添加按钮边框这是如何..

  Button(action: {self.isCreateAccountTapped = true},label: {Text("Create an Account")
.foregroundColor(Color("TextThemeColor36"))}
 )
.frame(height: 44)
.frame(width: 166)
.background(Color.clear)
.cornerRadius(8)
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(LinearGradient(gradient: Gradient(colors: [Color("BtnGradientClr1"),Color("BtnGradientClr2"),Color("BtnGradientClr3")]), startPoint: .leading, endPoint: .trailing)))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM