Parcourir la Source

Add professional hover lift animation to home action tiles.

This introduces a reusable hoverable tile view and animates icon elevation, shadow depth, and label emphasis so New meeting, Join, and Schedule feel more polished on pointer hover.

Made-with: Cursor
huzaifahayat12 il y a 4 jours
Parent
commit
eeb856b955
1 fichiers modifiés avec 43 ajouts et 2 suppressions
  1. 43 2
      zoom_app/ViewController.swift

+ 43 - 2
zoom_app/ViewController.swift

@@ -125,6 +125,34 @@ class ViewController: NSViewController {
125
         }
125
         }
126
     }
126
     }
127
 
127
 
128
+    private final class HoverTileView: NSView {
129
+        var onHoverChanged: ((Bool) -> Void)?
130
+        private var tracking: NSTrackingArea?
131
+
132
+        override func updateTrackingAreas() {
133
+            super.updateTrackingAreas()
134
+            if let tracking { removeTrackingArea(tracking) }
135
+            let area = NSTrackingArea(
136
+                rect: bounds,
137
+                options: [.activeInActiveApp, .mouseEnteredAndExited, .inVisibleRect],
138
+                owner: self,
139
+                userInfo: nil
140
+            )
141
+            addTrackingArea(area)
142
+            tracking = area
143
+        }
144
+
145
+        override func mouseEntered(with event: NSEvent) {
146
+            super.mouseEntered(with: event)
147
+            onHoverChanged?(true)
148
+        }
149
+
150
+        override func mouseExited(with event: NSEvent) {
151
+            super.mouseExited(with: event)
152
+            onHoverChanged?(false)
153
+        }
154
+    }
155
+
128
     private var palette = Palette(isDarkMode: true)
156
     private var palette = Palette(isDarkMode: true)
129
     private var darkModeEnabled: Bool {
157
     private var darkModeEnabled: Bool {
130
         get {
158
         get {
@@ -3752,7 +3780,7 @@ class ViewController: NSViewController {
3752
     }
3780
     }
3753
 
3781
 
3754
     private func makeActionTile(title: String, symbol: String, color: NSColor, action: Selector? = nil) -> NSView {
3782
     private func makeActionTile(title: String, symbol: String, color: NSColor, action: Selector? = nil) -> NSView {
3755
-        let root = NSView()
3783
+        let root = HoverTileView()
3756
         root.translatesAutoresizingMaskIntoConstraints = false
3784
         root.translatesAutoresizingMaskIntoConstraints = false
3757
         root.widthAnchor.constraint(equalToConstant: 88).isActive = true
3785
         root.widthAnchor.constraint(equalToConstant: 88).isActive = true
3758
         // Give caption text a little more vertical room so descenders (e.g. "g") are never clipped.
3786
         // Give caption text a little more vertical room so descenders (e.g. "g") are never clipped.
@@ -3779,8 +3807,9 @@ class ViewController: NSViewController {
3779
             $0.translatesAutoresizingMaskIntoConstraints = false
3807
             $0.translatesAutoresizingMaskIntoConstraints = false
3780
             root.addSubview($0)
3808
             root.addSubview($0)
3781
         }
3809
         }
3810
+        let iconTopConstraint = iconButton.topAnchor.constraint(equalTo: root.topAnchor)
3782
         NSLayoutConstraint.activate([
3811
         NSLayoutConstraint.activate([
3783
-            iconButton.topAnchor.constraint(equalTo: root.topAnchor),
3812
+            iconTopConstraint,
3784
             iconButton.centerXAnchor.constraint(equalTo: root.centerXAnchor),
3813
             iconButton.centerXAnchor.constraint(equalTo: root.centerXAnchor),
3785
             iconButton.widthAnchor.constraint(equalToConstant: 50),
3814
             iconButton.widthAnchor.constraint(equalToConstant: 50),
3786
             iconButton.heightAnchor.constraint(equalToConstant: 50),
3815
             iconButton.heightAnchor.constraint(equalToConstant: 50),
@@ -3788,6 +3817,18 @@ class ViewController: NSViewController {
3788
             label.centerXAnchor.constraint(equalTo: root.centerXAnchor),
3817
             label.centerXAnchor.constraint(equalTo: root.centerXAnchor),
3789
             label.bottomAnchor.constraint(equalTo: root.bottomAnchor)
3818
             label.bottomAnchor.constraint(equalTo: root.bottomAnchor)
3790
         ])
3819
         ])
3820
+        root.onHoverChanged = { [weak iconButton, weak label] hovering in
3821
+            NSAnimationContext.runAnimationGroup { context in
3822
+                context.duration = hovering ? 0.16 : 0.14
3823
+                context.timingFunction = CAMediaTimingFunction(name: hovering ? .easeOut : .easeInEaseOut)
3824
+                iconTopConstraint.animator().constant = hovering ? -3 : 0
3825
+                label?.animator().alphaValue = hovering ? 1.0 : 0.96
3826
+            }
3827
+            guard let iconButton else { return }
3828
+            iconButton.layer?.shadowOpacity = hovering ? 0.28 : 0.2
3829
+            iconButton.layer?.shadowRadius = hovering ? 10 : 7
3830
+            iconButton.layer?.shadowOffset = hovering ? NSSize(width: 0, height: -3) : NSSize(width: 0, height: -1)
3831
+        }
3791
         return root
3832
         return root
3792
     }
3833
     }
3793
 
3834