JZ.
JZ.

Reputation: 21907

SwiftUI how do I temporarily animate a view color's foregroundColor?

When a View is pressed I know through a model button.isSelected. How do I animate the view's foreground color, similar to the IOS calculators button press animation?

Something like:

White -> Grey -> White

struct ButtonView: View {
    let button: ViewModel.Button

    
    var body: some View {
        let shape = Rectangle()
        ZStack {
            shape.fill().foregroundColor(button.isSelected ? Color.gray : Color.white)
                .animation(Animation.linear(duration: 0.01))
            .border(Color.black, width: 0.33)
            Text(button.content)
            .font(Font.system(size:32))
            
        }
    }
}

Upvotes: 4

Views: 912

Answers (2)

aheze
aheze

Reputation: 30564

While DispatchQueue.main.asyncAfter() will work as Taeeun answered, note how the calculator app doesn't use a set delay. Instead, it changes color when the finger presses down, then reverts back upon release.

Pressing calculator buttons

So, you probably want something like ButtonStyle.

struct ContentView: View {
    var body: some View {
        ButtonView()
    }
}

struct CalculatorButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding() /// no need to use `shape` + `ZStack`, normal padding is ok
            .background(configuration.isPressed ? Color.gray : Color.white) /// use `isPressed` to determine if button is currently pressed or not
            .animation(Animation.linear(duration: 0.01))
            .cornerRadius(10)
    }
}

struct ButtonView: View {
    var body: some View {
        ZStack {
            Color.black /// for testing purposes (see the button better)
            
            Button {} label: {
                Text("Button")
                    .font(.system(size: 32))
            }
            .buttonStyle(CalculatorButtonStyle()) /// apply the style
        }
    }
}

Result:

Button fades when pressed

Upvotes: 2

Taeeun Kim
Taeeun Kim

Reputation: 1256

I think there are many ways to do this. Among them, I will write an example using DispatchQueue.main.asyncAfter()

struct ContentView: View {
    @State private var isSelected: Bool = false
    
    var body: some View {
        VStack {
            Button {
                isSelected = true
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.2 ) {
                    // To change the time, change 0.2 seconds above
                    isSelected = false
                }
            } label: {
                Text("Button")
                    .foregroundColor(isSelected ? Color.red : Color.blue)
            }
        }
    }
}

Upvotes: 4

Related Questions