首页 > 解决方案 > SwiftUi如何防止文本自动截断以适应

问题描述

我有一个包含多个项目的 hstack,当第一个文本太长时,它会被截断,并且行中的其他元素也会被截断,因此元素仍在 hstack 中,但对齐方式很奇怪,我发布了问题的屏幕截图以及我想要达到的目标。如果用户名太长并且不适合它,我需要它应该与其他元素换行。

[![这就是现在发生的事情][1]][1]

[![这就是我需要的][2]][2]

HStack {
  Text("longtext username test")

  // Block 1
  Text(Image(systemName: "network")) +
  Text("12345")
                            
  // Block 2
  Text(Image(systemName: "network")) +
  Text("2.0K")
                            
  // Block 3
  Text(Image(systemName: "network")) +
  Text("2H")
                            
  // Block 4
  Text(Image(systemName: "network"))
  Text(Image(systemName: "network"))
  Text(Image(systemName: "network"))
}


  [1]: https://i.stack.imgur.com/Bj1Cb.png
  [2]: https://i.stack.imgur.com/wITRf.png


// if the username is short and fit in the line
// Place all items in the same line

short-username text2 text3 text4..



// If the username is too long and doesn't fit
// Make a new line with all the other elements

long-username
text2 text3 test4..

标签: swiftxcodeswiftui

解决方案


这涉及更多一点。它需要与PreferenceKeys. 这段代码可能会被缩短,但它可以工作......

struct InlineTextView: View {
    
    @State var userName = "longtext username test"
    @State var userNamePref: CGFloat = 0
    @State var additionalTextPref: CGFloat = 0
    @State var hStackPref: CGFloat = 0
    @State var totalWidth: CGFloat = 0
    @State var isTooWide: Bool = true
    
    var body: some View {
        GeometryReader {outerGeometry in
            VStack(alignment: .leading, spacing: 20) {
                Group {
                    if isTooWide {
                        Text(userName)
                            .background(GeometryReader { userGeometry in
                                Color.clear.preference(
                                    key: UsernameWidthPreferenceKey.self,
                                    value: userGeometry.size.width)
                            })
                    additionalInlineText
                            .onTapGesture {
                                print("tapped")
                            }
                            .background(GeometryReader { addGeometry in
                                Color.clear.preference(
                                    key: AdditionalWidthPreferenceKey.self,
                                    value: addGeometry.size.width)
                            })
                    } else {
                        HStack {
                            Text(userName)
                                .background(GeometryReader { geometry in
                                    Color.clear.preference(
                                        key: UsernameWidthPreferenceKey.self,
                                        value: geometry.size.width)
                                })
                            additionalInlineTextView
                                .background(GeometryReader { geometry in
                                    Color.clear.preference(
                                        key: AdditionalWidthPreferenceKey.self,
                                        value: geometry.size.width)
                                })
                        }
                    }
                }
                .onPreferenceChange(UsernameWidthPreferenceKey.self) {
                    userNamePref = max($0, userNamePref)
                    totalWidth = userNamePref + additionalTextPref
                    isTooWide = totalWidth > outerGeometry.size.width
                    print("userNamePref = \(userNamePref)")
                    print("additionalTextPref = \(additionalTextPref)")
                    print("hStackPref = \(hStackPref)")
                    print("totalWidth = \(totalWidth)")
                    print("outerGeo = \(outerGeometry.size.width)")
                }
                .onPreferenceChange(AdditionalWidthPreferenceKey.self) {
                    additionalTextPref = max($0, additionalTextPref)
                    totalWidth = userNamePref + additionalTextPref
                    isTooWide = totalWidth > outerGeometry.size.width
                    print("userNamePref = \(userNamePref)")
                    print("additionalTextPref = \(additionalTextPref)")
                    print("hStackPref = \(hStackPref)")
                    print("totalWidth = \(totalWidth)")
                    print("outerGeo = \(outerGeometry.size.width)")
                }
                
                Button {
                    if userName == "longtext username test" {
                        userNamePref = 0
                        userName = "userName"
                    } else {
                        userNamePref = 0
                        userName = "longtext username test"
                    }
                } label: {
                    Text("Change name.")
                }
                
            }
        }
    }
    
    var additionalInlineText: Text {
        // Block 1
        Text(Image(systemName: "network")) +
        Text("12345") +
        
        // Block 2
        Text(Image(systemName: "network")) +
        Text("2.0K") +
        
        // Block 3
        Text(Image(systemName: "network")) +
        Text("2H") +
        
        // Block 4
        Text(Image(systemName: "network")) +
        Text(Image(systemName: "network")) +
        Text(Image(systemName: "network")) +
        Text("1234")
        
        
    }
}

private extension InlineTextView {
    struct UsernameWidthPreferenceKey: PreferenceKey {
        static let defaultValue: CGFloat = 0
        
        static func reduce(value: inout CGFloat,
                           nextValue: () -> CGFloat) {
            value = max(value, nextValue())
        }
    }
    
    struct AdditionalWidthPreferenceKey: PreferenceKey {
        static let defaultValue: CGFloat = 0
        
        static func reduce(value: inout CGFloat,
                           nextValue: () -> CGFloat) {
            value = max(value, nextValue())
        }
    }
}

编辑:使 AdditionalInlineText 可点击并更改名称以明确它是文本。

是的,GeometryReader确定屏幕的宽度,而首选项键确定视图的宽度。我开始他们,VStack所以他们读他们的最大宽度。如果您注意到何时userName更改,我会重置userNamePref以获取新读数。这有点脆弱,但它是做你想做的事情的唯一方法。


推荐阅读