Enum for Buttonstyle in Swiftui

Enum for ButtonStyle in SwiftUI

Here is a demo of possible approach - use own modifier and own enum, so have complete control on everything.

Usage

Button("Demo") {}
.myStyle(.default)

And helper extensions

enum MyButtonStyle {
case `default`
case borderless
// .. extend with any custom here
}

extension Button {

@ViewBuilder
func myStyle(_ style: MyButtonStyle) -> some View {
switch style {
case .default:
self.buttonStyle(DefaultButtonStyle())
case .borderless:
self.buttonStyle(BorderlessButtonStyle())
// .. extend with any custom here
}
}
}

How to change style of View based on binding enum in SwiftUI?

Here is fixed variant. Tested with Xcode 11.4 / iOS 13.4

enum Status {
case offline(color: Color = .black)
case loading(color: Color = .gray)
case online(color: Color = .green)

var color: Color {
switch self {
case .offline(let color):
return color
case .loading(let color):
return color
case .online(let color):
return color
}
}
}

struct StatusView: View {
@State var status: Status = .offline()

var body: some View {
Button(action: { self.goOnline() }){
Text("Offline")
.statusButtonStyle(color: status.color)
}.padding().background(Color.black).opacity(0.7).cornerRadius(40.0)
}
}

extension Text {
func statusButtonStyle(color: Color) -> Text {
return self
.foregroundColor(color)
}
}

How to create an enum based .textStyle(.title) modifier for Text(...) components in SwiftUI?

It works different way. As all this is around generics we need to restrict declarations for known concrete types.

So, having TitleStyle and BodyStyle declared and concrete, we can specify

extension ViewModifier where Self == TitleStyle {
static var title: TitleStyle { TitleStyle() }
}

extension ViewModifier where Self == BodyStyle {
static var body: BodyStyle { BodyStyle() }
}

and then declare extension to use above like

extension View {
func textStyle<Style: ViewModifier>(_ style: Style) -> some View {
ModifiedContent(content: self, modifier: style)
}
}

so as a result we can do as demo

struct Demo_Previews: PreviewProvider {
static var previews: some View {
Text("Demo")
.textStyle(.title)
}
}

demo

Prepared with Xcode 13.4 / iOS 15.5

Test module in GitHub

SwiftUI : Apply different animation style for Button using enum(s)?

Here's some code to get you started the right path. I don't have your custom icons, so I just used a systemIcon for the example.

Notes:

  • In SwiftUI it's extremely powerful to use ternary operators to manage the state of a view. This way, for example, you only need to write out Image() and set its font/frame/etc. one time. They basically let you write "If true do x otherwise do y."
  • By setting an image's renderingMode to Template, you can change it's color (if it's a compatible format)
  • I added a bunch of comments within the code too. Your question talked about adding a 'second animation'. In SwiftUI you can basically animate as many modifiers as you want to add multiple animations to a view.
  • I used a .onTapGesture() instead of a Button(). It's just a personal preference for this use case, but you can change it back if you prefer.

Code:

enum Icons: String,CaseIterable, Hashable {
case overlayText = "Text"
case image = "Image"
case rotate = "Rotate"
case audio = "Audio"
case merge = "Merge"
case split = "Split"
case duplicate = "Duplicate"
case none
}

struct EffectPanel: View {
@State var currentIconSelected: Icons = .none
@State var listIcons = [Bool](repeating: false, count: Icons.allCases.count)

var body: some View {
VStack {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 10) {
ForEach(Icons.allCases, id: \.self) { icon in
if icon != .none {
// You are looping on the icon already
// Don't need to init a new Icon()
EffectIcon2(icon: icon, currentIconSelected: $currentIconSelected)
}
}
}
.background(Color.black)
}
}
}
}

struct EffectIcon2: View {

var icon: Icons
@Binding var currentIconSelected: Icons

var body: some View {
Image(systemName:
currentIconSelected == icon ?
"heart.fill" : // selected image
"heart" // not selected image
)
.renderingMode(.template)
.font(.title2)
.frame(width: 65, height: 70)
// animate color when selected
.foregroundColor(
icon == currentIconSelected ? .orange : .white
)
// animate opacity for .audio
.opacity(
(icon == .audio && icon == currentIconSelected) ?
0.1 :
1.0
)
// animate rotation for .rotate
.rotationEffect(
Angle(degrees:
(icon == .rotate && icon == currentIconSelected) ?
360 :
0
)
)
// animate scale for .merge
.scaleEffect(
(icon == .merge && icon == currentIconSelected) ?
1.5 :
1.0
)
// When icon is selected, Animation is set to .repeatForever
// When not selected, Animation returns to .default
// Autoreverses set to false for .rotate animation only (optional)
// - You can change .linear(duration) for different animation timing
// - You can remove .repeatForever(autoreverses) for only 1 loop
.animation(
currentIconSelected == icon ?
Animation.linear(duration: 1.0)
.repeatForever(autoreverses: (icon == .rotate) ? false : true) :
.default
)
// Add a background layer with the Text
// This is similar to a ZStack (a matter of coding preference)
// The order which you add modifers is important in SwiftUI
// By adding .background after the .animation, it will NOT animate with the previous
// Like ZStack, Background layers have alignment abilities (currently .bottom)
// Animate opacity so that Text only appears when selected
.background(
Text("\(icon.rawValue)")
.fontWeight(.bold)
.font(.caption)
.foregroundColor(.orange)
.lineLimit(1)
.opacity(
icon == currentIconSelected ?
1.0 :
0.0
)
.padding(.bottom, 4)
.animation(.easeInOut)

, alignment: .bottom
)
.onTapGesture {
currentIconSelected = icon
}
}

}

SwiftUI ButtonStyle - how to check if button is disabled or enabled?

I found the answer thanks to this blog: https://swiftui-lab.com/custom-styling/

You can get the enabled state from the environment by creating a wrapper view and using it inside the style struct:

struct MyButtonStyle: ButtonStyle {
func makeBody(configuration: ButtonStyle.Configuration) -> some View {
MyButton(configuration: configuration)
}

struct MyButton: View {
let configuration: ButtonStyle.Configuration
@Environment(\.isEnabled) private var isEnabled: Bool
var body: some View {
configuration.label.foregroundColor(isEnabled ? Color.green : Color.red)
}
}
}

This example demonstrates how to get the state and use it to change the appearance of the button. It changes the button text color to red if the button is disabled or green if it's enabled.

Can't use toggle behaviour to trigger .buttonStyle in SWIFTUI

one approach would be to bypass the problem:

            if self.hoursOn {
Button(action: {self.hoursOn.toggle()}) {
Text("Hours").font(.headline)
}.buttonStyle(mainButtonOn())
} else {
Button(action: {self.hoursOn.toggle()}) {
Text("Hours").font(.headline)
}.buttonStyle(mainButtonOff())
}

another more concise approach is this:

struct mainButtonOnOff: ButtonStyle {
let onoff: Bool

init(_ switsh: Bool) {
self.onoff = switsh
}

func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.frame(width: 110, height: 35, alignment: .center)
.background(self.onoff ? Color.blue : Color.white)
.foregroundColor(self.onoff ? Color.white : Color.gray)
.cornerRadius(30)
.overlay(RoundedRectangle(cornerRadius: 30) .stroke(self.onoff ? Color.blue : Color.gray, lineWidth: 1))
}
}

and:

Button(action: {self.hoursOn.toggle()}) {
Text("Hours") .font(.headline)
}.buttonStyle(mainButtonOnOff(self.hoursOn))


Related Topics



Leave a reply



Submit