# Button ⟩ custom styles

[SwiftUI](https://lochiwei.gitbook.io/ios/swiftui) ⟩ [Controls](https://lochiwei.gitbook.io/ios/swiftui/control) ⟩ [Button](https://lochiwei.gitbook.io/ios/swiftui/control/button) ⟩&#x20;

{% tabs %}
{% tab title="💈範例" %}
{% embed url="<https://youtu.be/PivgVbL3ct0>" %}

{% hint style="warning" %}
注意：本例使用**兩種不同方法**來控制 Button 的外觀。

* <mark style="color:red;">**btn1**</mark> 使用 [view modifier](https://lochiwei.gitbook.io/ios/swiftui/view/modifier/viewmodifier)，<mark style="color:red;">**btn2**</mark> 使用 <mark style="color:purple;">**custom button style**</mark>。
* 用 [view modifier](https://lochiwei.gitbook.io/ios/swiftui/view/modifier/viewmodifier) 必須<mark style="color:red;">**自行設定**</mark> [State](https://lochiwei.gitbook.io/ios/swiftui/view/state/value/state) 變數 **isPressed**，然而 <mark style="color:purple;">**custom button style**</mark> 則由 [configuration.isPressed](https://developer.apple.com/documentation/swiftui/buttonstyleconfiguration/ispressed) 自動監控，<mark style="color:red;">**不需另行設定**</mark> State 變數。
* 由於 <mark style="color:red;">**btn1**</mark> 是由 [State](https://lochiwei.gitbook.io/ios/swiftui/view/state/value/state) 變數來「<mark style="color:red;">**切換**</mark>」isPressed 的狀態，所以只要按一下 btn1，按鈕就會陷下去，而且<mark style="color:red;">**不會彈回來**</mark>。<mark style="color:red;">**btn2**</mark> 則由 [configuration.isPressed](https://developer.apple.com/documentation/swiftui/buttonstyleconfiguration/ispressed) 自動監控，所以只有<mark style="color:red;">**持續按住**</mark>，才會保持「**按下的狀態**」。
  {% endhint %}

⬆️ 需要： [neumorphic](https://lochiwei.gitbook.io/ios/swiftui/view/modifier/examples/neumorphic "mention") (<mark style="color:red;">**modifier**</mark>)

```swift
struct ContentView: View {
    
    @State private var isPressed: Bool = false
    let color = Color(white: 0.9)
    
    var body: some View {
        HStack {
            VStack(alignment: .trailing, spacing: 40) {
                btn1        // ⭐️ 1. use view modifier
                btn2        // ⭐️ 2. use custom button style
            }
            .offset(x: -80)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(color)
        
    }
    
    var btn1: some View {
        Button{
            self.isPressed.toggle()
        } label: {
            Label("Hello", systemImage: "person")
                // ⭐️ 1. view modifier
                .neumorphic(isPressed: $isPressed, color: color)
        }
        .background(color)
        .overlay { 
            Text("點一下就會下沉")
                .foregroundColor(.gray)
                .offset(x: 150)
        }
    }
    
    var btn2: some View {
        Button{} label: {
            Label("World", systemImage: "globe")
        }
        // ⭐️ 2. custom button style
        .buttonStyle(.neumorphic(color: color))   // 🌀 .neumorphic() 
        .overlay { 
            Text("要按住才會下沉")
                .foregroundColor(.gray)
                .offset(x: 150)
        }
    }
}
```

{% endtab %}

{% tab title="🌀 .neumorphic()" %}

```swift
import SwiftUI

public struct NeumorphicButtonStyle: ButtonStyle {
    
    var color: Color
    
    // ⭐ protocol's only requirement
    public func makeBody(configuration: Self.Configuration) -> some View {
        
        // ⭐ `configuration` contains:
        //   - .label    : content of the button (View)
        //   - .isPressed: state of the button (Bool)
        let isPressed = configuration.isPressed
        
        let s: CGFloat = isPressed ? 5: 15       // positive shadow offset
        let r: CGFloat = isPressed ? 7: 10       // shadow radius
        let k: CGFloat = isPressed ? 0.95 : 1    // scale
        
        configuration.label
            .foregroundColor(.black)
            .padding(20)
            .background(
                ZStack {
                    RoundedRectangle(cornerRadius: 10, style: .continuous)
                        .shadow(color: .white, radius: r, x: -s, y: -s)
                        .shadow(color: .black, radius: r, x: s, y: s)
                        .blendMode(.overlay)
                    RoundedRectangle(cornerRadius: 10, style: .continuous)
                        .fill(color)
                }
            )
            .scaleEffect(k)
            .foregroundColor(.primary)
            .animation(.spring())
    }
}

// 🌀 .neumorphic(color:)
//                    ╭───────── ⭐️ important ──────────╮
extension ButtonStyle where Self == NeumorphicButtonStyle {
    public static func neumorphic(color: Color) -> some ButtonStyle {
        NeumorphicButtonStyle(color: color)
    } 
}
```

{% endtab %}

{% tab title="📗 參考" %}

* [x] Sarun ⟩ [How to create a custom button style?](https://sarunw.com/posts/swiftui-buttonstyle/#how-to-create-a-custom-button-style%3F)
  {% endtab %}

{% tab title="📘 手冊" %}

* SwiftUI ⟩ Controls ⟩ [Button](https://developer.apple.com/documentation/swiftui/button) ⟩
  * [.buttonStyle\<S: ButtonStyle>()](https://developer.apple.com/documentation/swiftui/view/buttonstyle\(_:\)-7qx1)
  * [.buttonStyle\<S: PrimitiveButtonStyle>(\_:)](https://developer.apple.com/documentation/swiftui/view/buttonstyle\(_:\)-66fbx)
  * [ButtonStyle](https://developer.apple.com/documentation/swiftui/buttonstyle) (<mark style="color:red;">**protocol**</mark>) - <mark style="color:orange;">**standard**</mark> button interaction behavior.
  * [PrimitiveButtonStyle](https://developer.apple.com/documentation/swiftui/primitivebuttonstyle) (<mark style="color:red;">**protocol**</mark>) - <mark style="color:orange;">**custom**</mark> interaction behavior & appearance.
    * .[automatic](https://developer.apple.com/documentation/swiftui/primitivebuttonstyle/automatic), .bordered, .borderedProminent, .borderless, .plain
    * .card (tvOS 14), .link (macOS 10.15)
  * [ButtonStyleConfiguration](https://developer.apple.com/documentation/swiftui/buttonstyleconfiguration) ⟩&#x20;
    * [isPressed](https://developer.apple.com/documentation/swiftui/buttonstyleconfiguration/ispressed)
    * [label](https://developer.apple.com/documentation/swiftui/buttonstyleconfiguration/label-swift.property)
      {% endtab %}

{% tab title="👥 相關" %}

* [viewmodifier](https://lochiwei.gitbook.io/ios/swiftui/view/modifier/viewmodifier "mention")
* [neumorphic](https://lochiwei.gitbook.io/ios/swiftui/view/modifier/examples/neumorphic "mention") - <mark style="color:red;">**modifier**</mark>
* [custom-styles](https://lochiwei.gitbook.io/ios/swiftui/control/label/builtin-styles/custom-styles "mention")
* [neu](https://lochiwei.gitbook.io/ios/master/todo/tutorials/neumorphism/gradients/neu "mention")
  {% endtab %}
  {% endtabs %}
