Reputation: 539
I'm having some issues with SwiftUI's SignInWithAppleButton
's signInWithAppleButtonStyle
. I am trying to change the color of the button based on the user's current scheme or if it changes.
This is iOS 14 and SwiftUI:
@Environment(\.colorScheme) var currentScheme
@State var appleButtonWhite = false
VStack{
SignInWithAppleButton(
.signUp,
onRequest: { request in
request.requestedScopes = [.fullName, .email]
},
onCompletion: { result in
switch result {
case .success (let authResults):
print("Authorization successful.")
case .failure (let error):
print("Authorization failed: " + error.localizedDescription)
}
}
)
.frame(minWidth: 0, maxWidth: .infinity)
.signInWithAppleButtonStyle(appleButtonWhite ? .white : .black)
}
.onChange(of: currentScheme, perform: { (scheme) in
if scheme == .light
{
appleButtonWhite = false
}
else
{
appleButtonWhite = true
}
})
When appleButtonWhite
changes values, it renders the view as it should since the state is changing. When I debug the button it has the correct appleButtonWhite value, but for some reason the style just never changes. I have no idea why. I have done many style changes in my code with regular buttons and it works correctly based on different states. Any ideas why Apple's doesn't change?
Upvotes: 6
Views: 3276
Reputation: 286
For button to take new style, you need to set different id to it as signInWithAppleButtonStyle don't seem to update internal state of this view, which prevent re-rending of this view
SignInWithAppleButton(
onRequest: { request in
request.requestedScopes = [.email,.fullName]
},
onCompletion: resultHandler(result:)
)
.signInWithAppleButtonStyle(colorScheme == .dark ? .white : .black)
.id(colorScheme == .dark ? "dark-btn": "light-btn")
Upvotes: 0
Reputation: 51
You can assign an ID to the 'Sign in with Apple' button so that when you change the color scheme, you can refresh this view by its ID. Please see the example below. This logic is valid for any other views that don't refresh their UI.
@State private var signInAppleButtonId = UUID().uuidString
@Environment(\.colorScheme) private var scheme
@ViewBuilder
private var SignInWithApple: some View {
SignInWithAppleButton(
onRequest: { request in
///
},
onCompletion: { result in
///
}
)
.id(signInAppleButtonId)
.signInWithAppleButtonStyle(scheme == .light ? .black : .white)
.onChange(of: scheme, { oldValue, newValue in
signInAppleButtonId = UUID().uuidString
})
.frame(width: 280, height: 45, alignment: .center)
.shadow(radius: 10)
}
Upvotes: 0
Reputation: 233
We can write even more elegant solution. Based on the mrjohnsly answer above 👆
Here's a resource that explain how to efficiently use Swift views https://developer.apple.com/wwdc21/10022
struct ContentView: View {
@Environment(\.colorScheme) var currentScheme
var body: some View {
VStack {
SignInWithAppleButton { request in
// request handeling
} onCompletion: { result in
// result handeling
}
.signInWithAppleButtonStyle(currentScheme == .light ? .black : .white) // <- here
.frame(width: 250, height: 45, alignment: .center)
}
}
}
Upvotes: 3
Reputation: 320
I managed to solve this by moving the SignInWithAppleButton
to its own View, without signInWithAppleButtonStyle
Then using @Environment(\.colorScheme)
create an if statement
and import the SignInWithAppleButtonView
styling with signInWithAppleButtonStyle
.
import SwiftUI
import AuthenticationServices
struct ContentView: View {
@Environment(\.colorScheme) var currentScheme
var body: some View {
if self.currentScheme == .light {
SignInWithAppleButtonView()
.signInWithAppleButtonStyle(.black)
} else {
SignInWithAppleButtonView()
.signInWithAppleButtonStyle(.white)
}
}
}
struct SignInWithAppleButtonView: View {
var body: some View {
SignInWithAppleButton(
.signUp,
onRequest: {_ in },
onCompletion: {_ in }
)
}
}
Upvotes: 10