# Button ⟩ custom styles

[SwiftUI](/ios/swiftui.md) ⟩ [Controls](/ios/swiftui/control.md) ⟩ [Button](/ios/swiftui/control/button.md) ⟩&#x20;

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

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

* <mark style="color:red;">**btn1**</mark> 使用 [view modifier](/ios/swiftui/view/modifier/viewmodifier.md)，<mark style="color:red;">**btn2**</mark> 使用 <mark style="color:purple;">**custom button style**</mark>。
* 用 [view modifier](/ios/swiftui/view/modifier/viewmodifier.md) 必須<mark style="color:red;">**自行設定**</mark> [State](/ios/swiftui/view/state/value/state.md) 變數 **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](/ios/swiftui/view/state/value/state.md) 變數來「<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()](/ios/swiftui/view/modifier/examples/neumorphic.md) (<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](/ios/swiftui/view/modifier/viewmodifier.md)
* [.neumorphic()](/ios/swiftui/view/modifier/examples/neumorphic.md) - <mark style="color:red;">**modifier**</mark>
* [Label ⟩ custom styles](/ios/swiftui/control/label/builtin-styles/custom-styles.md)
* [Neu 🔸](/ios/master/todo/tutorials/neumorphism/gradients/neu.md)
  {% endtab %}
  {% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lochiwei.gitbook.io/ios/swiftui/control/button/styles/custom-styles.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
