I've read all the comments above (and in the Internet at all), combined some of them and decided to come to this solution:
- Create custom Binding wrapper
- Create TextEditor and Text with this binding
- Add some modifications to make all this pixel-perfect.
Let's start with creating wrapper:
extension Binding where Value: Equatable {
init(_ source: Binding<Value?>, replacingNilWith nilProxy: Value) {
self.init(
get: { source.wrappedValue ?? nilProxy },
set: { newValue in
if newValue == nilProxy {
source.wrappedValue = nil
} else {
source.wrappedValue = newValue
}
})
}
}
Next step is to initialize our binding as usual:
@State private var yourTextVariable: String?
After that put TextEditor and Text in the ZStack:
ZStack(alignment: .topLeading) {
Text(YOUR_HINT_TEXT)
.padding(EdgeInsets(top: 6, leading: 4, bottom: 0, trailing: 0))
.foregroundColor(.black)
.opacity(yourTextVariable == nil ? 1 : 0)
TextEditor(text: Binding($yourTextVariable, replacingNilWith: ""))
.padding(.all, 0)
.opacity(yourTextVariable != nil ? 1 : 0.8)
}
And this will give us pixel-perfect UI with needed functionality:
https://youtu.be/T1TcSWo-Mtc