title: How to make animation of lines in OTP move one at a time when pasting a text in SwiftUI
body: <p>I created an OTP field which will animate the lines each time you type a digit. This works well. However, I want the animation of green lines to run one at time(from left to right) when pasting just like when typing a number.</p>
  <p>Currently when you paste a text, all lines are animating simulaneously as seen in the video.</p>
  <p><a href="https://i.stack.imgur.com/0imRj.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0imRj.gif" alt="Current Behavior" /></a></p>
  <p>The expected should be that the line should turn green one at a time from left to right when pasting.</p>
  <p>Please note that my paste button is a custom button I created as a workaround on some other feature.</p>
  <p>I can also use only Xcode 12.3.</p>
  <p>Here is my code:</p>
  <p>Some hex colors and font are custom. You may replace it when replicating.</p>
  <pre><code>
  @available(iOS 13.0, *)
  class OTPViewModel: ObservableObject {
      
      var numberOfFields: Int
      
      init(numberOfFields: Int = 6) {
          self.numberOfFields = numberOfFields
      }
      
      @Published var otpField = &quot;&quot; {
          didSet {
              showPasteButton = false
              guard otpField.last?.isNumber ?? true else {
                  otpField = oldValue
                  return
              }
              if otpField.count == numberOfFields {
                  showPasteButton = false
              }
          }
      }
      
      @Published var isEditing = false {
          didSet {
              if !isEditing { showPasteButton = isEditing }
          }
      }
      
      @Published var showPasteButton = false
      
      func otp(digit: Int) -&gt; String {
          guard otpField.count &gt;= digit else {
              return &quot;&quot;
          }
          return String(Array(otpField)[digit - 1])
      }
      
      private func hideKeyboard() {
          UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
      }
  }
  
  @available(iOS 13.0, *)
  struct CXLRPOTPView: View {
      @ObservedObject var viewModel = OTPViewModel()
      @Environment(\.colorScheme) var colorScheme
      
      private let textBoxWidth: CGFloat = 41
      private let textBoxHeight = UIScreen.main.bounds.width / 8
      private let spaceBetweenLines: CGFloat = 16
      private let paddingOfBox: CGFloat = 1
      private var textFieldOriginalWidth: CGFloat {
          (textBoxWidth + CGFloat(18)) * CGFloat(viewModel.numberOfFields)
      }
      var body: some View {
          VStack {
              ZStack {
                  // DOUBLE TAP AND LONG PRESS LISTENER
                  Text(&quot;123456&quot;)
                      .onTapGesture(count: 2) {
                          viewModel.showPasteButton = true
                      }
                      .frame(width: textFieldOriginalWidth, height: textBoxHeight)
                      .background(Color.clear)
                      .font(Font.system(size: 90, design: .default))
                      .foregroundColor(Color.clear)
                      .onLongPressGesture(minimumDuration: 0.5) {
                          self.viewModel.showPasteButton = true
                      }
                  
                  // OTP TEXT
                  HStack (spacing: spaceBetweenLines) {
                      ForEach(1 ... viewModel.numberOfFields, id: \.self) { digit in
                          otpText(
                              text: viewModel.otp(digit: digit),
                              isEditing: viewModel.isEditing,
                              beforeCursor: digit - 1 &lt; viewModel.otpField.count,
                              afterCursor: viewModel.otpField.count &lt; digit - 1
                          )
                      }
                  } //: HSTACK
                  
                  // TEXTFIELD FOR EDITING
                  TextField(&quot;&quot;, text: $viewModel.otpField) { isEditing in
                      viewModel.isEditing = isEditing
                  }
                  .font(Font.system(size: 90, design: .default))
                  .offset(x: 12, y: 10)
                  .frame(width: viewModel.isEditing ? 0 : textFieldOriginalWidth, height: textBoxHeight)
                  .textContentType(.oneTimeCode)
                  .foregroundColor(.clear)
                  .background(Color.clear)
                  .keyboardType(.numberPad)
                  .accentColor(.clear)
                  
                  // PASTE BUTTON
                  Button(action: pasteText, label: {
                      Text(&quot;Paste&quot;)
                  })
                  .padding(.top, 9)
                  .padding(.bottom, 9)
                  .padding(.trailing, 16)
                  .padding(.leading, 16)
                  .font(Font.system(size: 14, design: .default))
                  .accentColor(Color(.white))
                  .background(Color(colorScheme == .light ? UIColor.black : UIColor.systemGray6))
                  .cornerRadius(7.0)
                  .overlay(
                      RoundedRectangle(cornerRadius: 7).stroke(Color(.black), lineWidth: 2)
                  )
                  .opacity(viewModel.showPasteButton ? 1 : 0)
                  .offset(x: viewModel.numberOfFields == 6 ? -150 : -100, y: -40)
              } //: ZSTACK
          } //: VSTACK
      }
      
      func pasteText() {
          let pasteboard = UIPasteboard.general
          guard let pastedString = pasteboard.string else {
              return
          }
          let decimalInputOnly = pastedString
              .components(separatedBy:CharacterSet.decimalDigits.inverted)
              .joined()
          let otpField = decimalInputOnly.prefix(viewModel.numberOfFields)
          viewModel.otpField = String(otpField)
      }
      
      @available(iOS 13.0, *)
      private func otpText(
          text: String,
          isEditing: Bool,
          beforeCursor: Bool,
          afterCursor: Bool
      ) -&gt; some View {
          return Text(text)
              .font(Font.custom(&quot;GTWalsheim-Regular&quot;, size: 34))
              .frame(width: textBoxWidth, height: textBoxHeight)
              .background(VStack{
                  Spacer()
                      .frame(height: 65)
                  ZStack {
                      Capsule()
                          .frame(width: textBoxWidth, height: 2)
                          .foregroundColor(Color(hex: &quot;#BCBEC0&quot;))
                      
                      Capsule()
                          .frame(width: textBoxWidth, height: 2)
                          .foregroundColor(Color(hex: &quot;#367878&quot;))
                          .offset(x: (beforeCursor ? textBoxWidth : 0) + (afterCursor ? -textBoxWidth : 0))
                          .animation(.easeInOut, value: [beforeCursor, afterCursor])
                      .opacity(isEditing ? 1 : 0)
                  } //: ZSTACK
                  .clipped()
              })
              .padding(paddingOfBox)
      }
  }
  
  @available(iOS 13.0.0, *)
  struct CXLRPOTPView_Previews: PreviewProvider {
      static var previews: some View {
          CXLRPOTPView(viewModel: OTPViewModel())
              .previewLayout(.sizeThatFits)
      }
  }
  </code></pre>