簡體   English   中英

SwiftUI TextEditor 初始內容大小錯誤

[英]SwiftUI TextEditor Initial Content Size Is Wrong

iOS 14.4 + Xcode 12.4

我想在 iOS 上的 SwiftUI 中制作一個簡單的清單,其中每個項目的文本都是TextEditor

在此處輸入圖像描述

首先,我創建了基本的應用程序結構並用一些演示內容填充它:

import SwiftUI

@main
struct TestApp: App {
  @State var alpha = "Alpha"
  @State var bravo = "Bravo is a really long one that should wrap to multiple lines."
  @State var charlie = "Charlie"
  
  init(){
    //Remove the default background of the TextEditor/UITextView
    UITextView.appearance().backgroundColor = .clear
  }
  
  var body: some Scene {
    WindowGroup {
      ScrollView{
        VStack(spacing: 7){
          TaskView(text: $alpha)
          TaskView(text: $bravo)
          TaskView(text: $charlie)
        }
        .padding(20)
      }
      .background(Color.gray)
    }
  }
}

然后每個TaskView代表列表中的一個任務(白框):

struct TaskView:View{
  @Binding var text:String
  
  var body: some View{
    HStack(alignment:.top, spacing:8){
      Button(action: {
        print("Test")
      }){
        Circle()
          .strokeBorder(Color.gray,lineWidth: 1)
          .background(Circle().foregroundColor(Color.white))
          .frame(width:22, height: 22)
      }
      .buttonStyle(PlainButtonStyle())
      
      FieldView(name: $text)
       
    }
    .frame(maxWidth: .infinity, alignment: .leading)
    .padding(EdgeInsets(top:10, leading:10, bottom: 10, trailing: 30))
    .background(Color.white)
    .cornerRadius(5)
  }
}

最后,每個TextEditor都在FieldView中,如下所示:

struct FieldView: View{
  @Binding var name: String
  var body: some View{
    ZStack{
      Text(name)
        .padding(EdgeInsets(top: -7, leading: -3, bottom: -5, trailing: -3))
        .opacity(0)
      TextEditor(text: $name)
        .fixedSize(horizontal: false, vertical: true)
        .padding(EdgeInsets(top: -7, leading: -3, bottom: -5, trailing: -3))
    }
  }
}

正如您在上面的屏幕截圖中看到的, TextEditor的初始高度不會自動調整大小以適應文本。 但是一旦我輸入它,它就會適當地調整大小。 這是一個視頻,顯示:

在此處輸入圖像描述

如何讓視圖具有正確的初始高度? 在我輸入之前, TextEditor會垂直滾動,因此它似乎具有錯誤的內在內容大小。

注意:視圖是半透明的,帶有邊框,因此您可以查看/調試正在發生的事情。

struct FieldView: View{
    @Binding var name: String
    @State private var textEditorHeight : CGFloat = 100
    var body: some View{
        ZStack(alignment: .topLeading) {
            Text(name)
                .background(GeometryReader {
                    Color.clear
                        .preference(key: ViewHeightKey.self,
                                           value: $0.frame(in: .local).size.height)

                })
                //.opacity(0)
                .border(Color.pink)
                .foregroundColor(Color.red)
                
            TextEditor(text: $name)
                .padding(EdgeInsets(top: -7, leading: -3, bottom: -5, trailing: -7))
                .frame(height: textEditorHeight + 12)
                .border(Color.green)
                .opacity(0.4)
        }
        .onPreferenceChange(ViewHeightKey.self) { textEditorHeight = $0 }
    }
}

struct ViewHeightKey: PreferenceKey {
    static var defaultValue: CGFloat { 0 }
    static func reduce(value: inout Value, nextValue: () -> Value) {
        value = value + nextValue()
        print("Reporting height: \(value)")
    }
}

首先,我使用PreferenceKey將“不可見”文本視圖的高度傳遞回視圖層次結構。 然后,我使用該值設置TextEditor框架的高度。

請注意,視圖現在與topLeading對齊——在您的初始示例中,不可見文本居中對齊。

我不喜歡的一件事是邊緣插圖的使用——這些感覺就像魔術數字(嗯,它們是……),我寧願有一個沒有它們的解決方案,它仍然保持TextTextEditor完全對齊. 但是,這暫時有效。

更新,使用 UIViewRepresentable 和 UITextView

這似乎有效並避免了滾動問題:


struct TaskView:View{
    @Binding var text:String
    @State private var textHeight : CGFloat = 40
    
    var body: some View{
        HStack(alignment:.top, spacing:8){
            Button(action: {
                print("Test")
            }){
                Circle()
                    .strokeBorder(Color.gray,lineWidth: 1)
                    .background(Circle().foregroundColor(Color.white))
                    .frame(width:22, height: 22)
            }
            .buttonStyle(PlainButtonStyle())
            
            FieldView(text: $text, heightToTransmit: $textHeight)
                .frame(height: textHeight)
                .border(Color.red)
            
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(EdgeInsets(top:10, leading:10, bottom: 10, trailing: 30))
        .background(Color.white)
        .cornerRadius(5)
    }
}

struct FieldView : UIViewRepresentable {
    @Binding var text : String
    @Binding var heightToTransmit: CGFloat
    
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        let textView = UITextView(frame: .zero, textContainer: nil)
        textView.delegate = context.coordinator
        textView.backgroundColor = .yellow // visual debugging
        textView.isScrollEnabled = false   // causes expanding height
        context.coordinator.textView = textView
        textView.text = text
        view.addSubview(textView)

        // Auto Layout
        textView.translatesAutoresizingMaskIntoConstraints = false
        let safeArea = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            textView.topAnchor.constraint(equalTo: safeArea.topAnchor),
            textView.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
            textView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor)
        ])
        
        return view
    }
    
    func updateUIView(_ view: UIView, context: Context) {
        context.coordinator.heightBinding = $heightToTransmit
        context.coordinator.textBinding = $text
        DispatchQueue.main.async {
            context.coordinator.runSizing()
        }
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }
    
    class Coordinator : NSObject, UITextViewDelegate {
        var textBinding : Binding<String>?
        var heightBinding : Binding<CGFloat>?
        var textView : UITextView?
        
        func runSizing() {
            guard let textView = textView else { return }
            textView.sizeToFit()
            self.textBinding?.wrappedValue = textView.text
            self.heightBinding?.wrappedValue = textView.frame.size.height
        }
        
        func textViewDidChange(_ textView: UITextView) {
            runSizing()
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM