Page Menu
Home
Musing Studio
Search
Configure Global Search
Log In
Files
F12142819
PostTitleTextView.swift
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
4 KB
Subscribers
None
PostTitleTextView.swift
View Options
// Based on https://lostmoa.com/blog/DynamicHeightForTextFieldInSwiftUI and https://stackoverflow.com/a/56508132
import
SwiftUI
class
PostTitleCoordinator
:
NSObject
,
UITextViewDelegate
,
NSLayoutManagerDelegate
{
@
Binding
var
text
:
String
@
Binding
var
isFirstResponder
:
Bool
var
lineSpacingMultiplier
:
CGFloat
var
didBecomeFirstResponder
:
Bool
=
false
var
postTitleTextView
:
PostTitleTextView
weak
var
textView
:
UITextView
?
init
(
_
textView
:
PostTitleTextView
,
text
:
Binding
<
String
>,
isFirstResponder
:
Binding
<
Bool
>,
lineSpacingMultiplier
:
CGFloat
)
{
self
.
postTitleTextView
=
textView
_text
=
text
_isFirstResponder
=
isFirstResponder
self
.
lineSpacingMultiplier
=
lineSpacingMultiplier
}
func
textViewDidChange
(
_
textView
:
UITextView
)
{
DispatchQueue
.
main
.
async
{
self
.
postTitleTextView
.
text
=
textView
.
text
??
""
}
}
func
textView
(
_
textView
:
UITextView
,
shouldChangeTextIn
range
:
NSRange
,
replacementText
text
:
String
)
->
Bool
{
if
text
==
"
\n
"
{
self
.
isFirstResponder
.
toggle
()
self
.
didBecomeFirstResponder
=
false
return
false
}
return
true
}
func
layoutManager
(
_
layoutManager
:
NSLayoutManager
,
didCompleteLayoutFor
textContainer
:
NSTextContainer
?,
atEnd
layoutFinishedFlag
:
Bool
)
{
DispatchQueue
.
main
.
async
{
guard
let
view
=
self
.
textView
else
{
return
}
let
size
=
view
.
sizeThatFits
(
view
.
bounds
.
size
)
if
self
.
postTitleTextView
.
height
!=
size
.
height
{
self
.
postTitleTextView
.
height
=
size
.
height
}
}
}
func
layoutManager
(
_
layoutManager
:
NSLayoutManager
,
lineSpacingAfterGlyphAt
glyphIndex
:
Int
,
withProposedLineFragmentRect
rect
:
CGRect
)
->
CGFloat
{
// HACK: - This seems to be the only way to get line spacing to update dynamically on iPad
// when switching between full-screen, split-screen, and slide-over views.
if
let
window
=
UIApplication
.
shared
.
windows
.
filter
({
$0
.
isKeyWindow
}).
first
{
// Get the width of the window to determine the size class
if
window
.
frame
.
width
<
600
{
// Use 0.25 multiplier for compact size class
return
17
*
0.25
}
else
{
// Use 0.5 multiplier otherwise
return
17
*
0.5
}
}
else
{
return
17
*
lineSpacingMultiplier
}
}
}
struct
PostTitleTextView
:
UIViewRepresentable
{
@
Binding
var
text
:
String
@
Binding
var
textStyle
:
UIFont
@
Binding
var
height
:
CGFloat
@
Binding
var
isFirstResponder
:
Bool
@
State
var
lineSpacing
:
CGFloat
func
makeUIView
(
context
:
UIViewRepresentableContext
<
PostTitleTextView
>)
->
UITextView
{
let
textView
=
UITextView
()
textView
.
isEditable
=
true
textView
.
isUserInteractionEnabled
=
true
textView
.
isScrollEnabled
=
false
textView
.
alwaysBounceVertical
=
false
context
.
coordinator
.
textView
=
textView
textView
.
delegate
=
context
.
coordinator
textView
.
layoutManager
.
delegate
=
context
.
coordinator
let
font
=
textStyle
let
fontMetrics
=
UIFontMetrics
(
forTextStyle
:
.
largeTitle
)
textView
.
font
=
fontMetrics
.
scaledFont
(
for
:
font
)
textView
.
backgroundColor
=
UIColor
.
clear
return
textView
}
func
makeCoordinator
()
->
PostTitleCoordinator
{
return
Coordinator
(
self
,
text
:
$
text
,
isFirstResponder
:
$
isFirstResponder
,
lineSpacingMultiplier
:
lineSpacing
)
}
func
updateUIView
(
_
uiView
:
UITextView
,
context
:
UIViewRepresentableContext
<
PostTitleTextView
>)
{
if
uiView
.
text
!=
text
{
uiView
.
text
=
text
}
let
font
=
textStyle
let
fontMetrics
=
UIFontMetrics
(
forTextStyle
:
.
largeTitle
)
uiView
.
font
=
fontMetrics
.
scaledFont
(
for
:
font
)
// We don't want the text field to become first responder every time SwiftUI refreshes the view.
if
isFirstResponder
&&
!
context
.
coordinator
.
didBecomeFirstResponder
{
uiView
.
becomeFirstResponder
()
context
.
coordinator
.
didBecomeFirstResponder
=
true
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Fri, Oct 10, 1:42 AM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3440985
Attached To
rWFSUI WriteFreely SwiftUI
Event Timeline
Log In to Comment