I have code like this:
VStack {
ForEach(Array($ingredientNames.enumerated()), id:\.offset) { (idx, $str) in
if idx != 0{
TextField("Player \(idx + 1)", text: $str)
.foregroundColor(Color.white)
.fontWeight(.bold)
.shadow(color: .white, radius: 20)
.background(Color("AccentColor"))
.multilineTextAlignment(.center)
.font(Font.system(size: 26))
}
else {
TextField("Player", text: $str)
.foregroundColor(Color.white)
.fontWeight(.bold)
.shadow(color: .white, radius: 20)
.background(Color("AccentColor"))
.multilineTextAlignment(.center)
.font(Font.system(size: 26))
}
}
}
But actually the color of "player" is gray (default). How can I make it for example white? Adding a .foregroundColor doesn't work as you can see - now it's working when user type something - then it's turning white. But how can I make it white as a default with no need to input something into this to work?
Add this extension to your project:
extension View {
func placeholder<Content: View>(
when present: Bool,
alignment: Alignment = .leading,
#ViewBuilder content: () -> Content) -> some View {
ZStack(alignment: alignment) {
content().opacity(present ? 1 : 0)
self
}
}
}
Then in your code use this:
TextField("", text: $text)
.placeholder(when: text.isEmpty) {
Text("Player").foregroundColor(.white)
}
.foregroundColor(Color.white)
.fontWeight(.bold)
.shadow(color: .white, radius: 20)
.background(Color("AccentColor"))
.multilineTextAlignment(.center)
.font(Font.system(size: 26))
Below is my code : This code gives shadow to all part of button. I only want to give shadow to bottom part of button
Button should look like something like this :
var body: some View {
Button(action: {
self.action(self.title)
self.hover.toggle()
}) {
if title == "x" {
ZStack {
Image(systemName: "delete.left").cornerRadius(5).font(Font.system(size: 28, weight: .medium))
.background(Color..secondaryBG)
.accentColor(.accentTint)
}
} else {
Text(title).customText(titleColor: .accentTint, fontName: .gothamMedium, fontSize: 28)
.background(Color.secondaryBG)
}
}
.withBackground(color: .accentTint)
.frame(width: 76, height: 76)
.cornerRadius(5)
.shadow(color: .numberPadShadowColor, radius: 5, x: 0, y: 1) // This gives shadow to all the parts. I do not want to give shadow to top part of button
}
What you show is more like a drop shadow with hard edges:
give it a solid background and shift it down:
struct ContentView: View {
var body: some View {
Button(action: {
//
}) {
Image(systemName: "delete.left")
.font(Font.system(size: 28, weight: .medium))
.foregroundColor(.black)
}
.frame(width: 76, height: 76)
.background(Color(uiColor: .lightGray))
.cornerRadius(5)
.background(
RoundedRectangle(cornerRadius: 5)
.offset(x: 0, y: 1)
)
}
}
I have a simple loading view on SwiftUI.
When I am displaying this loading screen with .navigationBarHidden(true) on NavigationView.
There is an issue that animation has an unwanted effect on it.
This is my loading animation
struct LoaderThreeDot: View {
var size: CGFloat = 20
#State private var shouldAnimate = false
var body: some View {
HStack(alignment: .center) {
Circle()
.fill(Color.blue)
.scaleEffect(shouldAnimate ? 1.0 : 0.5, anchor: .center)
.animation(Animation.easeInOut(duration: 0.5).repeatForever())
.frame(width: size, height: size)
Circle()
.fill(Color.blue)
.scaleEffect(shouldAnimate ? 1.0 : 0.5, anchor: .center)
.animation(Animation.easeInOut(duration: 0.5).repeatForever().delay(0.3))
.frame(width: size, height: size, alignment: .center)
Circle()
.fill(Color.blue)
.scaleEffect(shouldAnimate ? 1.0 : 0.5, anchor: .center)
.animation(Animation.easeInOut(duration: 0.5).repeatForever().delay(0.6))
.frame(width: size, height: size, alignment: .center)
}
.onAppear {
self.shouldAnimate = true
}
}
}
LoadingView as follow:
struct LoadingView<Content>: View where Content: View {
let title: String
var content: () -> Content
#State var showLoader = false
var body: some View {
ZStack {
self.content()
.disabled(true)
.blur(radius: 3)
Rectangle()
.foregroundColor(Color.black.opacity(0.4))
.ignoresSafeArea()
VStack {
if showLoader {
LoaderThreeDot()
}
Text(title)
.foregroundColor(.black)
.font(.body)
.padding(.top, 10)
}
.padding(.all, 60)
.background(backgroundView)
}
.onAppear {
showLoader.toggle()
}
}
private var backgroundView: some View {
RoundedRectangle(cornerRadius: 12)
.foregroundColor(Color.white)
.shadow(radius: 10)
}
}
And simply presenting it as follow:
NavigationView {
ZStack {
LoadingView(title: "Loading...") {
Rectangle()
.foregroundColor(.red)
}
}
.navigationBarHidden(true)
}
If I remove .navigationBarHidden(true) animation looks ok.
So I am guessing that the animation effect started when the navigation bar was shown and it somehow affecting the animation after the navigation bar is hidden.
Is there any way I can avoid this?
Change your toggle on the main thered.
// Other code
.onAppear() {
DispatchQueue.main.async { //<--- Here
showLoader.toggle()
}
}
// Other code
My Button requires a couple overlays to get the style it needs (stroke, shadow etc).
However these overlays then go over the Button text.
View:
struct ProfileTest: View {
var body: some View {
Button(action: {
}){
HStack {
Text("OFFLINE")
.font(.custom("Seravek-Bold", size: 25))
.fontWeight(.bold)
.foregroundColor(Color.blue)
}
}.padding(EdgeInsets(top: 12, leading: 15, bottom: 12, trailing: 15))
.cornerRadius(50)
.overlay(
RoundedRectangle(cornerRadius: 50)
.stroke(Color.black, lineWidth: 1)
)
.overlay(
RoundedRectangle(cornerRadius: 50)
.fill(Color.red)
.shadow(color: Color.black.opacity(1), radius: 1)
)
.opacity(0.7)
.padding(.bottom, 100)
.padding(.bottom, 20)
}
}
How can I adjust my view so that the blue text shows above the background?
You can use a custom ButtonStyle.
Create your own shape and add .overlay(configuration.label) on top of it:
struct CustomButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.hidden()
.padding(EdgeInsets(top: 12, leading: 15, bottom: 12, trailing: 15))
.cornerRadius(50)
.overlay(
RoundedRectangle(cornerRadius: 50)
.stroke(Color.black, lineWidth: 1)
)
.overlay(
RoundedRectangle(cornerRadius: 50)
.fill(Color.red)
.shadow(color: Color.black.opacity(1), radius: 1)
)
.opacity(0.7)
.overlay(configuration.label)
.padding(.bottom, 100)
.padding(.bottom, 20)
}
}
You can also use configuration.isPressed to customise your label behaviour on button press.
Apply it to your Button:
struct ContentView: View {
var body: some View {
Button(action: {}) {
HStack {
Text("OFFLINE")
.font(.custom("Seravek-Bold", size: 25))
.fontWeight(.bold)
.foregroundColor(Color.blue)
}
}
.buttonStyle(CustomButtonStyle())
}
}
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:
As you can see the border at corner are cut-off.
Any suggestion what am I doing wrong?
Instead of setting the cornerRadius to the Button use an overlay for the inside View:
Edit: If you have a background for the button you also need to apply the cornerRadius to the background.
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
Updated for Swift 5 & iOS 13.4+ with Press States!
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. 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+
Buttons now have baked in border styling support using the .buttonStyle(.bordered) modifier. I would suggest using the corner radius Apple provides for these buttons for the best platform-specific styling. 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:
Button("Add") { ... }
.buttonStyle(.bordered)
.tint(.green)
You can make the tint color more prominent (bolder) using .borderedProminent and control the size using .controlSize:
Button("food") { ... }
.tint(.red)
.controlSize(.small) // .large, .medium or .small
.buttonStyle(.borderedProminent)
You can also use this modifier on parent Views of Buttons and toggle lighter color schemes using .accentColor in child Buttons:
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. Using prominent buttons everywhere also violates HIG.
Extra NOTE: Apple's .bordered style provides the standard platform style across device types. In addition, the Button responds to Dark Mode dynamically and scales its size with Dynamic Type (native accessibility support).
Swift 5 & iOS 14 – Borders also react when pressed
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
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:
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())
Just add the cornerRadius argument:
.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))
}
}
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.
The result will be :
Hope it helps :)
Swift version 5.6
You can use Button properties for example
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
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. It takes care of rounded corners. Full implementation is here 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)
)
}
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)))