Skip to content

Commit 1dc6c3b

Browse files
committed
Replace Safe Area With Top Padding, Smoother Animations
1 parent c349cd6 commit 1dc6c3b

File tree

6 files changed

+46
-44
lines changed

6 files changed

+46
-44
lines changed

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ let package = Package(
1717
// A fast, efficient, text view for code.
1818
.package(
1919
url: "https://github.com/CodeEditApp/CodeEditTextView.git",
20-
from: "0.7.9"
20+
from: "0.8.1"
2121
),
2222
// tree-sitter languages
2323
.package(

Sources/CodeEditSourceEditor/Controller/TextViewController+LoadView.swift

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ extension TextViewController {
2929
for: .horizontal
3030
)
3131

32-
let searchController = FindViewController(target: self, childView: scrollView)
33-
addChild(searchController)
34-
self.view.addSubview(searchController.view)
35-
searchController.view.viewDidMoveToSuperview()
36-
self.searchController = searchController
32+
let findViewController = FindViewController(target: self, childView: scrollView)
33+
addChild(findViewController)
34+
self.findViewController = findViewController
35+
self.view.addSubview(findViewController.view)
36+
findViewController.view.viewDidMoveToSuperview()
37+
self.findViewController = findViewController
38+
39+
findViewController.topPadding = contentInsets?.top ?? view.safeAreaInsets.top
3740

3841
if let _undoManager {
3942
textView.setUndoManager(_undoManager)
@@ -46,10 +49,10 @@ extension TextViewController {
4649
setUpTextFormation()
4750

4851
NSLayoutConstraint.activate([
49-
searchController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
50-
searchController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
51-
searchController.view.topAnchor.constraint(equalTo: view.topAnchor),
52-
searchController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
52+
findViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
53+
findViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
54+
findViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
55+
findViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
5356
])
5457

5558
if !cursorPositions.isEmpty {
@@ -110,7 +113,7 @@ extension TextViewController {
110113
// Reset content insets and gutter position when appearance changes
111114
if let contentInsets = self.contentInsets {
112115
self.scrollView.contentInsets = contentInsets
113-
if let searchController = self.searchController, searchController.isShowingFindPanel {
116+
if let findViewController = self.findViewController, findViewController.isShowingFindPanel {
114117
self.scrollView.contentInsets.top += FindPanel.height
115118
}
116119
self.gutterView.frame.origin.y = -self.scrollView.contentInsets.top
@@ -156,10 +159,10 @@ extension TextViewController {
156159
return nil
157160
case (commandKey, "f"):
158161
_ = self.textView.resignFirstResponder()
159-
self.searchController?.showFindPanel()
162+
self.findViewController?.showFindPanel()
160163
return nil
161164
case (0, "\u{1b}"): // Escape key
162-
self.searchController?.findPanel.dismiss()
165+
self.findViewController?.findPanel.dismiss()
163166
return nil
164167
case (_, _):
165168
return event

Sources/CodeEditSourceEditor/Controller/TextViewController.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class TextViewController: NSViewController {
2020
// swiftlint:disable:next line_length
2121
public static let cursorPositionUpdatedNotification: Notification.Name = .init("TextViewController.cursorPositionNotification")
2222

23-
weak var searchController: FindViewController?
23+
weak var findViewController: FindViewController?
2424

2525
var scrollView: NSScrollView!
2626

@@ -124,7 +124,11 @@ public class TextViewController: NSViewController {
124124
public var highlightProviders: [HighlightProviding]
125125

126126
/// Optional insets to offset the text view in the scroll view by.
127-
public var contentInsets: NSEdgeInsets?
127+
public var contentInsets: NSEdgeInsets? {
128+
didSet {
129+
findViewController?.topPadding = contentInsets?.top ?? view.safeAreaInsets.top
130+
}
131+
}
128132

129133
/// Whether or not text view is editable by user
130134
public var isEditable: Bool {

Sources/CodeEditSourceEditor/Find/FindViewController+Toggle.swift

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,13 @@ extension FindViewController {
2525
setFindPanelConstraintShow()
2626
}
2727

28+
// Smooth this animation
29+
findPanel.isHidden = false
30+
findPanelVerticalConstraint.constant = topPadding - FindPanel.height
31+
view.layoutSubtreeIfNeeded()
32+
2833
if animated {
29-
withAnimation(updates)
34+
withAnimation(updates) { }
3035
} else {
3136
updates()
3237
}
@@ -47,9 +52,12 @@ extension FindViewController {
4752
}
4853

4954
if animated {
50-
withAnimation(updates)
55+
withAnimation(updates) { [weak self] in
56+
self?.findPanel.isHidden = true
57+
}
5158
} else {
5259
updates()
60+
findPanel.isHidden = true
5361
}
5462

5563
// Set first responder back to text view
@@ -61,7 +69,7 @@ extension FindViewController {
6169
/// Runs the `animatable` callback in an animation context with implicit animation enabled.
6270
/// - Parameter animatable: The callback run in the animation context. Perform layout or view updates in this
6371
/// callback to have them animated.
64-
private func withAnimation(_ animatable: () -> Void) {
72+
private func withAnimation(_ animatable: () -> Void, onComplete: @escaping () -> Void) {
6573
NSAnimationContext.runAnimationGroup { animator in
6674
animator.duration = 0.2
6775
animator.allowsImplicitAnimation = true
@@ -70,26 +78,28 @@ extension FindViewController {
7078

7179
view.updateConstraints()
7280
view.layoutSubtreeIfNeeded()
81+
} completionHandler: {
82+
onComplete()
7383
}
7484
}
7585

7686
/// Sets the find panel constraint to show the find panel.
7787
/// Can be animated using implicit animation.
78-
private func setFindPanelConstraintShow() {
88+
func setFindPanelConstraintShow() {
7989
// Update the find panel's top to be equal to the view's top.
80-
findPanelVerticalConstraint.constant = view.safeAreaInsets.top
90+
findPanelVerticalConstraint.constant = topPadding
8191
findPanelVerticalConstraint.isActive = true
8292
}
8393

8494
/// Sets the find panel constraint to hide the find panel.
8595
/// Can be animated using implicit animation.
86-
private func setFindPanelConstraintHide() {
96+
func setFindPanelConstraintHide() {
8797
// Update the find panel's top anchor to be equal to it's negative height, hiding it above the view.
8898

8999
// SwiftUI hates us. It refuses to move views outside of the safe are if they don't have the `.ignoresSafeArea`
90100
// modifier, but with that modifier on it refuses to allow it to be animated outside the safe area.
91101
// The only way I found to fix it was to multiply the height by 3 here.
92-
findPanelVerticalConstraint.constant = view.safeAreaInsets.top - (FindPanel.height * 3)
102+
findPanelVerticalConstraint.constant = topPadding - FindPanel.height
93103
findPanelVerticalConstraint.isActive = true
94104
}
95105
}

Sources/CodeEditSourceEditor/Find/FindViewController.swift

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@ import CodeEditTextView
1111
/// Creates a container controller for displaying and hiding a find panel with a content view.
1212
final class FindViewController: NSViewController {
1313
weak var target: FindPanelTarget?
14+
15+
var topPadding: CGFloat = 0.0
16+
1417
var childView: NSView
1518
var findPanel: FindPanel!
1619
var findMatches: [NSRange] = []
20+
1721
var currentFindMatchIndex: Int = 0
1822
var findText: String = ""
1923
var findPanelVerticalConstraint: NSLayoutConstraint!
24+
2025
var isShowingFindPanel: Bool = false
2126

2227
init(target: FindPanelTarget, childView: NSView) {
@@ -92,24 +97,4 @@ final class FindViewController: NSViewController {
9297
setFindPanelConstraintHide()
9398
}
9499
}
95-
96-
/// Sets the find panel constraint to show the find panel.
97-
/// Can be animated using implicit animation.
98-
private func setFindPanelConstraintShow() {
99-
// Update the find panel's top to be equal to the view's top.
100-
findPanelVerticalConstraint.constant = view.safeAreaInsets.top
101-
findPanelVerticalConstraint.isActive = true
102-
}
103-
104-
/// Sets the find panel constraint to hide the find panel.
105-
/// Can be animated using implicit animation.
106-
private func setFindPanelConstraintHide() {
107-
// Update the find panel's top anchor to be equal to it's negative height, hiding it above the view.
108-
109-
// SwiftUI hates us. It refuses to move views outside of the safe are if they don't have the `.ignoresSafeArea`
110-
// modifier, but with that modifier on it refuses to allow it to be animated outside the safe area.
111-
// The only way I found to fix it was to multiply the height by 3 here.
112-
findPanelVerticalConstraint.constant = view.safeAreaInsets.top - (FindPanel.height * 3)
113-
findPanelVerticalConstraint.isActive = true
114-
}
115100
}

0 commit comments

Comments
 (0)