Issue with Buttons in SwiftUI on MacOS

swiftui button
swiftui button(action function)
swiftui done button
swiftui floating button
swiftui button to new view
swiftui button alignment
swiftui sheet
swiftui padding

I'm using SwiftUI on MACOS

If I do this:

      Button(action: { } ) {
        Text("Press")
        .padding()
        .background(Color.blue)
      }

I get this:

and the two grey areas are the ends of a tappable button. but I would expect the button to be the shape of the blue area. Any ideas how I can get the whole blue area to be tappable.

(I did look at using .onTapGesture but this doesn't animate the button so that you know you've tapped it.)

You can achieve the look you want by using a ButtonStyle and then specifying colors and other style attributes based on the configuration values being passed in.

It would be nice if there was a happy medium where you could inherit the default button radius, automatic width based on the text length and other attributes, but at least there is the ability to specify all the attributes and get the look you want.

Hope this helps!

import SwiftUI

struct BlueButtonStyle: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .foregroundColor(configuration.isPressed ? Color.blue : Color.white)
            .background(configuration.isPressed ? Color.white : Color.blue)
            .cornerRadius(6.0)
            .padding()
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello World")
                .frame(maxWidth: .infinity, maxHeight: .infinity)

            Button(action: {
            }) {
                Text("Press")
                    .frame(maxWidth: 100, maxHeight: 24)
            }
            .buttonStyle(BlueButtonStyle())
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Button, A control that performs an action when triggered. Availability. iOS 13.0+; macOS 10.15+; Mac Catalyst 13.0+; tvOS 13.0+; watchOS 6.0+. Framework. SwiftUI. In macOS, the user triggers a standard button by clicking on it. In tvOS, the user triggers a standard button by pressing “select” on an external remote, like the Siri Remote, while focusing on the button. Adding Buttons to Containers. Use buttons for any user interface element that triggers actions on press.

Inspired by @Gene Z. Ragan 's great answer I've started with that answer and taken this a bit further:

Making the ButtonStyle a bit more flexible:

struct NiceButtonStyle: ButtonStyle {
  var foregroundColor: Color
  var backgroundColor: Color
  var pressedColor: Color

  func makeBody(configuration: Self.Configuration) -> some View {
    configuration.label
      .font(.headline)
      .padding(10)
      .foregroundColor(foregroundColor)
      .background(configuration.isPressed ? pressedColor : backgroundColor)
      .cornerRadius(5)
  }
}

and then some sugar to make it cleaner at the call site:

extension View {
  func niceButton(
    foregroundColor: Color = .white,
    backgroundColor: Color = .gray,
    pressedColor: Color = .accentColor
  ) -> some View {
    self.buttonStyle(
      NiceButtonStyle(
        foregroundColor: foregroundColor,
        backgroundColor: backgroundColor,
        pressedColor: pressedColor
      )
    )
  }
}

then means we can use default colouring: white foreground, grey background and accentedColor pressedColor

  Button(action: { } ) {
    Text("Button A")
  }
  .niceButton()

or we can customise the colours:

  Button(action: { } ) {
    Text("Button B has a long description")
  }
  .niceButton(
    foregroundColor: .blue,
    backgroundColor: .yellow,
    pressedColor: .orange
  )

And we get:

Thanks again Gene.

Hacking with macOS SwiftUI 2, Hacking with macOS SwiftUI 2 - Buttons not refreshing The problem seems to be with the if statement inside a for loop - for some reason that  I thought the goal of SwiftUI was to build apps that work either in macOS or iOS. However, the one of the most basic functions for a UI - making a button - seems to work differently. It appears in iOS you can easily make a custom View be a button: Button(action: {myAction()}) { MyCustomView()} Great - I can turn my Views into buttons.

I don't think this is possible but you could try using this

Supports SPM, is build for Swift 5.1 and is lean

How to create a tappable button, SwiftUI's button is similar to UIButton , except it's more flexible in terms of what To create a button you would start with code like this: iPad, Safari, App Store, watchOS, tvOS, Mac and macOS are trademarks of Apple Inc.,  Basic SwiftUI alerts look like this: Alert(title: Text("Important message"), message: Text("Wear sunscreen"), dismissButton: .default(Text("Got it!"))) However, you will often want to attach actions to buttons to perform specific actions when they are tapped.

I raised this with Apple on the Feedback assistant to see if they had any useful thoughts.

Dialogue here:

I said:

If on MACOS with SwiftUI I do this:

  Button(action: { } ) {
    Text("Press")
    .padding()
    .background(Color.blue)
  }

I get a blue box with two grey bits sticking out the sides. Image attached. These are the two grey areas are the ends of a tappable button. but I would expect the button to be the shape of the blue area.

The same code works fine as expected on iOS.

(I did look at using .onTapGesture but this doesn't animate the button so that you know you've tapped it.)

Apple said:

iOS and macOS have different default ButtonStyles — iOS is borderless, macOS has that standard bezel effect.

It sounds like you’re trying to create a custom ButtonStyle (and so not have any system provided chrome). So you’ll want to create that, which can apply that blue background to the label of the button, and then apply that to your simple button with Text, e.g.

Button("Press"), action {}).buttonStyle(BluePaddingButtonStyle()

This will ensure that it has the same appearance on every platform you run it on.

I said:

Hi, Thanks for the explanation. I get what you are saying and I’m ok with the method I’ve come up with.

It still doesn’t seem right that:

  Button(action: { } ) {
    Text("Press")
    .padding()
    .background(Color.blue)
  }

should produce something so odd looking. I don’t understand why that bit of code couldn’t just produce a blue button.

As I say - it’s not a problem because I’ve worked around it but it currently doesn’t seem intuitive.

Apple said:

The provided content inside the ViewBuilder is used as the label of the button: not the entire button. The button will still come with the surrounding background, bezel, foreground styling, etc as described by it’s ButtonStyle. So if your button needs to have a very specific appearance, then it needs to customize that style: either to the BorderlessButtonStyle (though note that still does come with a specific foreground appearance style), or to a custom ButtonStyle.

My thoughts:

This did help me understand why it shows as it does but intuitively it still seems wrong !!!

Buttons in SwiftUI (macOS) : swift, I'm trying to learn SwiftUI to built a few apps for personal use. stackoverflow.​com/questions/58419161/issue-with-buttons-in-swiftui-on-macos. All you need to ensure is check the Use SwiftUI option. Once you save the project, Xcode should load the ContentView.swift file and display a preview in the design canvas. In case the preview is not displayed, you can click the Resume button in the canvas. Creating a Simple Button with SwiftUI. It’s very easy to create a button using SwiftUI.

A Beginner's Guide to SwiftUI Buttons, Intermediate iOS 13 Programming with Swift. Written for developers with some iOS programming experience. The book uses a problem-solution  So far, nearly all the articles I have seen about SwiftUI show it being used for iOS, more particularly for iPhone. But SwiftUI works on all Apple’s platforms, and as I am primarily a Mac developer, I decided to try out a Mac app and see what happened. Setup. I opened up Xcode and created a new project selecting the macOS App template.

SwiftUI ButtonStyle, How to create a reusable button style in SwiftUI. My first thought to tackle this problem is an old friend ViewModifier. macOS button styles  Here is sample code of how to use a Button Style in SwiftUI. Button ( action : { print ( " plain " ) }) { Text ( " Borderless button " ) }. buttonStyle ( BorderlessButtonStyle ()) In the GitHub repo , there is an Xcode project with each button style used.

sindresorhus/CustomButton: Customizable button for your macOS app, SwiftUI does indeed make it much easier to create custom-looking buttons, but SwiftUI is still immature and most companies will not be able to require macOS  This is a table explaining the different button styles in SwiftUI and which platform each Button Style is available on. If you enjoyed this post and want more, please consider subscribing to my…

Comments
  • This is the common issue with swiftUI. I have. faced same issue with Image.
  • Thanks @Gene Z. Ragan - works a treat :-) Will be interested to see whether Apple respond to my feedback.
  • Please post a comment if they get back to you. Glad this is working for you!
  • Will do. From your great base, I've taken this a bit further to make it a bit cleaner and more flexible. I will post as a separate answer.
  • Same approach also discussed at: alejandromp.com/blog/2019/06/22/swiftui-reusable-button-style
  • Same approach also discussed at: alejandromp.com/blog/2019/06/22/swiftui-reusable-button-style
  • Thanks @krjw - much appreciated. CustomButton looks good but I can't see how I would turn it into a View to use with SwiftUI?
  • I'm also thinking that my bit o code in my question seems reasonable - would you agree this is effectively a bug?
  • To be honest I only have used SwiftUI on iOS and just tried your code on a new project to find out if it helps to apply the modifiers to the button itself... and I played around a little bit and thought this is not the correct behaviour. I would't say it's a bug because I don't know te expected behaviour, but for me it seems wrong at least
  • I also had been using Button in iOS and it worked fine. I was surprised that it didn't have the same or at least similar result on MacOS as part of the idea of SwiftUI is that you can move between platforms with the same code.
  • Do you know how I would get CustomButton to work with SwiftUI. I presume I need some sort of wrapper which conformed to View?