Swift UI中带有圆角的按钮边框

101

我试图设置一个按钮的圆角边框,但是按钮的边框不正确。

代码:

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)

输出:

enter image description here

正如您所看到的那样,角落处的边框被切掉了。

有什么建议我做错了什么吗?


你可以尝试参考这个链接:https://www.appcoda.com/swiftui-border/ - Aira Samson
14个回答

119

不要将cornerRadius设置为按钮,而是对内部视图使用覆盖层:

编辑:如果您对按钮有背景,则还需要将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
    

2
当我使用你的代码时,按钮内部的文本被隐藏了。 - Mahendra
4
如果我们给这个按钮添加背景颜色,那么还会显示一个矩形,但其四个角不是圆角的。 - Ammar Mujeeb
如果我们添加背景颜色,它就无法工作。 - Twitter khuong291
1
请使用“background”而不是“overlay”来隐藏文本。此外,将RoundedRectangle的foregroundColor用作按钮背景。 - Zahid
如果您有一个背景颜色,在应用此建议的叠加后,您仍然可以在其上应用cornerRadius,这对我来说似乎是有效的。 - C0D3
显示剩余3条评论

42

更新于Swift 5&iOS 13.4+,具有Press States!

对于具有深色和白色背景颜色的按钮以及没有按下状态更新的任何示例都不起作用,因此我构建了LargeButton视图,您可以在下面看到。希望这有所帮助,使用起来应该非常简单!

示例照片

输入图像描述

示例使用

// 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")
                    }

代码

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

1
同时应用.cornerRadius(6).overlay(RoundedRectangle(cornerRadius: 6))效果很好!谢谢! - Honghao Z

26

iOS 15+官方支持 .bordered 修饰符

现在,Button 使用 .buttonStyle(.bordered) 修饰符内置边框样式支持。为了获得最佳的平台特定样式,建议使用苹果提供的这些按钮的圆角半径。我们可以使用 .tint 修饰符将颜色更改为与系统风格一致的按钮样式,并调整背景和文本颜色:

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

绿色色调的按钮

您可以使用.borderedProminent让色调更加明显(加粗),并使用.controlSize控制大小:

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

小按钮

您还可以在包含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)

大型按钮样式

建议

由于某些原因,苹果不喜欢单线边框的按钮,这就是为什么在Xcode 12中.border()修饰符被弃用的原因。随着这一改变,我建议开发者避免创建单线边框的按钮,因为它们现在不再是苹果人机界面指南中的首选。在所有地方使用凸起按钮也违反了HIG。

额外说明:苹果的.bordered样式提供了跨设备类型的标准平台样式。此外,Button会动态响应暗模式,并与动态类型(本机无障碍支持)一起缩放其大小。


1
.controlProminence(.increased)已被弃用,推荐使用.buttonStyle(.borderedProminent)。https://www.fivestars.blog/articles/xcode-13-beta-4/ - Felix

10

只需要添加cornerRadius参数:

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

使用这个简单的扩展程序

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

Preview


在我的 macOS 上不起作用,出现错误“在调用中有额外的参数 'cornerRadius'”,因此该参数不可用。 - trinity420
你先实现了 extension 吗?@trinity420 - Mojtaba Hosseini
不,我是Swift的新手,忽略了这个问题,谢谢!我会再试一次。 - trinity420

9

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

如何使用

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

边框在被按下时也会有反应


9
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)

enter image description here

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

enter image description here

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

enter image description here

同样地,您可以更改按钮样式和控件大小。

7

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

不需要添加叠加层。您可以使用框架修饰符替换填充修饰符。动作是在body变量之外的非返回方法。

特别针对 @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())

2
边界在哪里? - carlosobedgomez
这个问题与添加边框有关,但是在这个解决方案中没有执行该操作的代码。 - Minon Weerasinghe
@MinonWeerasinghe 根据您的评论,答案已更新。 - Alexander

4
你可以尝试这个:
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)
                )

                }
            }
        }
    }

我也没有将maxWidth设置为.infinity,因为这意味着按钮将填充您的容器视图的宽度。
结果将会是:

enter image description here

希望能有所帮助 :)

2

要创建带有圆角的边框,您可以绘制一个圆角矩形并将其覆盖在按钮上,如下所示:

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

enter image description here


fontWeight - iOS 16^ - North Face

2

SwiftUI:- 你也可以尝试这个!

目前我在同一个按钮上添加了不同形状的检查。如果你想要,你可以将我的代码分开。

 // Global declaration
        @State var isFollowed = false
        Button {
            // Toggle Your isFollowed with true and false
            isFollowed = true
        } label: {
            Text(isFollowed ? "Following" : "Follow")
                .padding(.horizontal, 10)
                .padding(.vertical, 6)
                .foregroundColor(.white)
                .font(.custom(MyFont.GilroyBold, size: 13))
                .background(
                    ZStack {
                        RoundedRectangle(
                            cornerRadius: 20,
                            style: .continuous
                        )
                        .fill(isFollowed ? .red : .clear)
                        RoundedRectangle(
                            cornerRadius: 20,
                            style: .continuous
                        )
                        .stroke(.red, lineWidth: 2)
                    }
                )
        }

例如,我需要“关注”和“正在关注”按钮。 在“关注”按钮上,我显示圆角和仅边框。 在“正在关注”按钮上,我显示圆角和背景颜色。

enter image description here enter image description here


是的,很容易理解。非常适合我。 - Huynh Inc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接