6

I'm building essentially a memorization app, where tapping a button on the keyboard takes the next word from a predetermined string, and adds it to the outputted text as shown below:

struct TypingGameView: View {
   @State var text: String = "Some text that wraps at the incorrect spot and is quite annoying."
   @State var outputText: String = ""
   @State private var enteredText: String = ""
   @State private var wordsTapped = 0

   var body: some View {
      ZStack {
         TextField("", text: $enteredText)
            .onChange(of: enteredText) { newValue in
               addToOutputText(newValue)
            }
         Rectangle()
            .foregroundColor(.white)
         VStack {
            Text(outputText)
               .frame(maxWidth: .infinity, alignment: .leading)
               .padding()
            Spacer()
         }
      }
   }

   func addToOutputText(_ val: String) {
      let words = text.components(seperatedBy: " ")

      for (index, word) in words.enumerated() {
         if index = wordsTapped {
            outputText += "\(word) "
            wordsTapped += 1
            return
         }
      }      
   }
}

The problem is, the last word of the first line jumps to the next line only if there is one other word after it, but then jumps back to the first line once there are more words after that. See below:

Auto orphaning fix in action

To the best of my knowledge, this is an automatic feature of the Text view in SwiftUI to prevent there being any orphaned words. I want to disable this as it makes the words jump around in the view I've created. I've seen solutions with using a CATextLayer in UIKit (see UILabel and UITextView line breaks don't match and Get each line of text in a UILabel), but I need something that works with SwiftUI @State wrappers and would prefer a solution that uses all SwiftUI. End goal is to get same functionality as in above video, but with no automatic orphan fixing.

Edit: Just tried using Group with individual Text views inside for each word. Still does the same thing :/

Dcfunkster
  • 130
  • 9
  • Have you found a way to overcome this? – demon9733 May 27 '22 at 19:22
  • 1
    @demon9733 The best I've been able to figure out so far is having all text displayed on screen at once, but set to `.foregroundColor(.clear)`, and then setting one word at a time to `.black` when the correct letter is typed. It feels quite hacky, takes up a lot of system resources and probably isn't great for accessibility, but it's the best I've got. – Dcfunkster May 28 '22 at 20:04

0 Answers0