From 51f8495a06edd2100848c5808788b47e215d72f2 Mon Sep 17 00:00:00 2001 From: Angelo Stavrow Date: Mon, 2 Nov 2020 15:03:31 -0500 Subject: [PATCH] Make Return key navigate from title field to last body field position --- iOS/PostEditor/PostBodyTextView.swift | 22 ++++++++++++++++++++++ iOS/PostEditor/PostTextEditingView.swift | 2 ++ iOS/PostEditor/PostTitleTextView.swift | 1 + 3 files changed, 25 insertions(+) diff --git a/iOS/PostEditor/PostBodyTextView.swift b/iOS/PostEditor/PostBodyTextView.swift index 7530fd5..4dfa0b2 100644 --- a/iOS/PostEditor/PostBodyTextView.swift +++ b/iOS/PostEditor/PostBodyTextView.swift @@ -5,6 +5,7 @@ import SwiftUI class PostBodyCoordinator: NSObject, UITextViewDelegate, NSLayoutManagerDelegate { @Binding var text: String @Binding var isFirstResponder: Bool + @Binding var currentTextPosition: UITextRange? var lineSpacingMultiplier: CGFloat var didBecomeFirstResponder: Bool = false var postBodyTextView: PostBodyTextView @@ -15,12 +16,14 @@ class PostBodyCoordinator: NSObject, UITextViewDelegate, NSLayoutManagerDelegate _ textView: PostBodyTextView, text: Binding, isFirstResponder: Binding, + currentTextPosition: Binding, lineSpacingMultiplier: CGFloat ) { self.postBodyTextView = textView _text = text _isFirstResponder = isFirstResponder self.lineSpacingMultiplier = lineSpacingMultiplier + _currentTextPosition = currentTextPosition } func textViewDidChange(_ textView: UITextView) { @@ -29,6 +32,23 @@ class PostBodyCoordinator: NSObject, UITextViewDelegate, NSLayoutManagerDelegate } } + func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + self.currentTextPosition = textView.selectedTextRange + return true + } + + func textViewDidBeginEditing(_ textView: UITextView) { + if let textPosition = currentTextPosition { + textView.selectedTextRange = textPosition + } + } + + func textViewDidEndEditing(_ textView: UITextView) { + self.isFirstResponder = false + self.didBecomeFirstResponder = false + self.currentTextPosition = textView.selectedTextRange + } + func layoutManager( _ layoutManager: NSLayoutManager, lineSpacingAfterGlyphAt glyphIndex: Int, @@ -55,6 +75,7 @@ struct PostBodyTextView: UIViewRepresentable { @Binding var text: String @Binding var textStyle: UIFont @Binding var isFirstResponder: Bool + @Binding var currentTextPosition: UITextRange? @State var lineSpacing: CGFloat func makeUIView(context: UIViewRepresentableContext) -> UITextView { @@ -82,6 +103,7 @@ struct PostBodyTextView: UIViewRepresentable { self, text: $text, isFirstResponder: $isFirstResponder, + currentTextPosition: $currentTextPosition, lineSpacingMultiplier: lineSpacing ) } diff --git a/iOS/PostEditor/PostTextEditingView.swift b/iOS/PostEditor/PostTextEditingView.swift index a58fbae..90a1e5c 100644 --- a/iOS/PostEditor/PostTextEditingView.swift +++ b/iOS/PostEditor/PostTextEditingView.swift @@ -11,6 +11,7 @@ struct PostTextEditingView: View { @State private var titleIsFirstResponder: Bool = true @State private var bodyTextStyle: UIFont = UIFont(name: "Lora-Regular", size: 17)! @State private var bodyIsFirstResponder: Bool = false + @State private var bodyCursorPosition: UITextRange? private let lineSpacingMultiplier: CGFloat = 0.5 init( @@ -71,6 +72,7 @@ struct PostTextEditingView: View { text: $post.body, textStyle: $bodyTextStyle, isFirstResponder: $bodyIsFirstResponder, + currentTextPosition: $bodyCursorPosition, lineSpacing: horizontalSizeClass == .compact ? lineSpacingMultiplier / 2 : lineSpacingMultiplier ) .onChange(of: post.body) { _ in diff --git a/iOS/PostEditor/PostTitleTextView.swift b/iOS/PostEditor/PostTitleTextView.swift index 510ea31..53d8bb8 100644 --- a/iOS/PostEditor/PostTitleTextView.swift +++ b/iOS/PostEditor/PostTitleTextView.swift @@ -32,6 +32,7 @@ class PostTitleCoordinator: NSObject, UITextViewDelegate, NSLayoutManagerDelegat func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { if text == "\n" { self.isFirstResponder.toggle() + self.didBecomeFirstResponder = false return false } return true