繁体   English   中英

swiftUI 使用 firstResponder() 隐藏文本字段

[英]swiftUI hiding textfield with firstResponder()

新人来了😬

我正在尝试使用不同的字体大小在 SwiftUI 中进行“输入”。

从我从其他帖子中了解到的情况,原生 TextField 无法做到这一点,因此我创建了一个带有 splicedText 的 HStack,并分别渲染我的文本的每个部分以达到预期的结果。 这一点工作正常。

但是,现在我有一个普通的 TextField 和我的“标签”,我不知道如何隐藏这个文本字段并仍然保持.decimalPad打开。

这是我想要实现的外观:

在此处输入图片说明

这是我到目前为止:

在此处输入图片说明

正如你所看到的,我的价值出现了两次。 一种格式几乎正确,另一种未格式化(TextField)。

我尝试将.hidden()添加到 TextField,虽然这确实隐藏了 TextField(),但我的 firstResponder() .decimalPad不再显示,我无法输入我的值 :(

我不想只是将它设置为具有opacity(0) ,因为我不希望它在我看来占据任何空间。

此屏幕上最终将有 2 个输入,我需要能够单击“标签”以再次打开.decimalPad 然而,我还没有走到这一步。

这是呈现这个的代码:

import SwiftUI
import SwiftUIX

struct CreateEntryView : View {
    
    class ViewModel: ObservableObject {
        @Published var value = "$17.00" {
            didSet {
                let validCharSet = CharacterSet(charactersIn: "$1234567890.,")
                
                print("value: " + value)
                // add "$" prefix
                if value.prefix(1) != "$" { value = "$" + value  }
                
                //check if the new string contains any invalid characters
                if (value).rangeOfCharacter(from: validCharSet.inverted) != nil {
                    // remove any invalid characters
                    value = String(value.unicodeScalars.filter {
                        validCharSet.contains($0)
                    })
                }
                
                // replace ',' with '.' (required to handle all locales w/ decimalPad)
                let test = value.replacingOccurrences(of: ",", with: ".")
                print("replace comma: " + test)
                
                
                // check if there's more than 2 decimals
                // check if there's more than 1 dot
                // check if there's more than 1 dollar-sign
                
                
            }
        }
    }
    
    @ObservedObject var viewModel = ViewModel()
    
    // create splicedLabel for making label with varyign fontSize
    var splicedLabel: [String] {
        var spliceString = viewModel.value
        // remove $ from string
        spliceString.remove(at: spliceString.startIndex)
        return spliceString.split(separator: ".").map(String.init)
    }
    
    
    var body: some View {
        VStack {
            HStack(alignment: .bottom, spacing: 0) {
                Text("$")
                    .font(.body)
                    .fontWeight(.bold)
                    .padding(.bottom, 5)
                if self.splicedLabel.indices.contains(0) {
                    Text(self.splicedLabel[0])
                        .font(.largeTitle)
                        .fontWeight(.bold)
                }
                if self.splicedLabel.indices.contains(1) {
                    HStack(alignment: .bottom, spacing: 0) {
                        Text(".")
                            .font(.body)
                            .fontWeight(.bold)
                        Text(self.splicedLabel[1])
                            .font(.body)
                            .fontWeight(.bold)
                    }.padding(.bottom, 5)
                }
            }
            
    
            CocoaTextField("$123", text: $viewModel.value)
                .isFirstResponder(true) // autoFocus
                .keyboardType(.decimalPad)
            
        }
    }
}

非常感谢有关如何实现这一目标的一些意见。 也许我尝试在 HStack 中使用 Texts 来处理不同的 fontSize 是完全错误的。

也许你可以通过使用 UITextfield 和NSAttributedString来做到这一点,它们可以用不同的字体大小或颜色来装饰。

import UIKit
import SwiftUI
import Combine

struct MyTextField: UIViewRepresentable {
  private var placeholder: String
  @Binding private var text: String
  private var textField = UITextField()

  init(_ placeholder: String, text: Binding<String>) {
    self.placeholder = placeholder
    self._text = text
  }

  func makeCoordinator() -> Coordinator {
    Coordinator(textField: self.textField, text: self._text)
  }

  func makeUIView(context: Context) -> UITextField {
    textField.placeholder = self.placeholder
    textField.font = UIFont.boldSystemFont(ofSize: 17)
    textField.keyboardType = .decimalPad
    textField.text = self.text
    return textField
  }

  func updateUIView(_ uiView: UITextField, context: Context) {
  }

  class Coordinator: NSObject {
    private var dispose = Set<AnyCancellable>()
    @Binding var text: String

    init(textField: UITextField, text: Binding<String>) {
      self._text = text
      super.init()

      let publisher = NotificationCenter.default
        .publisher(for: UITextField.textDidChangeNotification, object: textField)
        .compactMap { $0.object as? UITextField }
        .share()
        
      publisher.compactMap { $0.text }
        .receive(on: RunLoop.main)
        .assign(to: \.text, on: self)
        .store(in: &dispose)
      
      publisher.receive(on: RunLoop.main)
        .sink(receiveValue: { (textField: UITextField) in
          Coordinator.setAttributedString(textField: textField)
        })
        .store(in: &dispose)
    }
    
    static func setAttributedString(textField: UITextField) {
      guard var text = textField.attributedText?.string else { return }
      text = text.prefix(1) == "$" ? text : "$" + text
      
      let dollarAttributes: [NSAttributedString.Key: Any] = [
        .foregroundColor: UIColor.black,
        .font: UIFont.boldSystemFont(ofSize: 34)
      ]
      let otherAttributes: [NSAttributedString.Key: Any] = [
        .foregroundColor: UIColor.black,
        .font: UIFont.boldSystemFont(ofSize: 17)
      ]
      
      let attributedText = NSMutableAttributedString(string: text)
      attributedText.addAttributes(dollarAttributes, range: NSRange(location: 1, length: text.count - 1))
      
      let strings = text.split(separator: ".")
      if let dollar = strings.first, strings.count > 1 {
        let range = NSRange(location: dollar.count, length: text.count - dollar.count)
        attributedText.addAttributes(otherAttributes, range: range)
      }
      textField.attributedText = attributedText
    }
  }
}

extension MyTextField.Coordinator: UITextFieldDelegate {
  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    textField.resignFirstResponder()
  }
}

struct ContentView: View {
  @State var text: String = "$"

  var body: some View {
    VStack {
      MyTextField("placeholder", text: self.$text).padding()
      Text(self.text).foregroundColor(.red).padding()
    }
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM