使 TextEditor 动态高度 SwiftUI

Make TextEditor dynamic height SwiftUI

我正在尝试创建一个不断增长的 TextEditor 作为聊天视图的输入。

例如,目标是有一个扩展框,直到达到 6 行。之后它应该是可滚动的。

我已经设法用包含换行符的字符串做到这一点 \n

                        TextEditor(text: $composedMessage)
                            .onChange(of: self.composedMessage, perform: { value in
                                withAnimation(.easeInOut(duration: 0.1), {
                                    if (value.numberOfLines() < 6) {
                                        height = startHeight + CGFloat((value.numberOfLines() * 20))
                                    }
                                    if value.numberOfLines() == 0 || value.isEmpty {
                                        height = 50
                                    }
                                })
                            })

我创建了一个字符串扩展,其中 returns 通过调用 string.numberOfLines() var startHeight: CGFloat = 50

换行符的数量

问题:如果我粘贴的文本包含很长的文本,当该字符串没有换行符时它不会扩展。 TextEditor 中的文本损坏了。

如何计算 TextEditor 打断的次数并在该位置放置换行符?

我找到了解决办法!

对于其他试图解决此问题的人:

我添加了一个与输入字段宽度相同的 Text,然后使用 GeometryReader 来计算自动换行的文本高度。然后,如果您将高度除以字体大小,您将得到行数。

您可以隐藏文本字段(已在 iOS 14 和 iOS 15 beta 3 中测试)

这是根据问答改编的解决方案,

struct ChatView: View {
    @State var text: String = ""

    // initial height
    @State var height: CGFloat = 30

    var body: some View {
        ZStack(alignment: .topLeading) {
            Text("Placeholder")
                .foregroundColor(.appLightGray)
                .font(Font.custom(CustomFont.sofiaProMedium, size: 13.5))
                .padding(.horizontal, 4)
                .padding(.vertical, 9)
                .opacity(text.isEmpty ? 1 : 0)

            TextEditor(text: $text)
                .foregroundColor(.appBlack)
                .font(Font.custom(CustomFont.sofiaProMedium, size: 14))
                .frame(height: height)
                .opacity(text.isEmpty ? 0.25 : 1)
                .onChange(of: self.text, perform: { value in
                    withAnimation(.easeInOut(duration: 0.1), {
                        if (value.numberOfLines() < 6) {
                            // new height
                            height = 120
                        }
                        if value.numberOfLines() == 0 || value.isEmpty {
                            // initial height
                            height = 30
                        }
                    })
                })
        }
        .padding(4)
        .overlay(
            RoundedRectangle(cornerRadius: 8)
                .stroke(Color.appLightGray, lineWidth: 0.5)
        )
    }

}

还有扩展,

extension String {
    func numberOfLines() -> Int {
        return self.numberOfOccurrencesOf(string: "\n") + 1
    }

    func numberOfOccurrencesOf(string: String) -> Int {
        return self.components(separatedBy:string).count - 1
    }

}