我的变量正在识别更改,但实际上并未更新

问题描述 投票:0回答:1

我有一个名为 ExpandableText 的可重用结构,它可以让我缩短给它的文本(因此,如果我将其限制为两行,它会添加阅读更多内容并展开),但是当文本变量在不同视图上更改时(因此文本是编辑)它识别更改但不更新变量。当我在 ExpandableText 视图中放置 onChange 并打印

newValue
text
值时,
newValue
更新为其他视图中的更改,但
text
值仍保留旧值。我尝试将 text 设置为状态变量,然后 onChange 将其分配给 newValue,但这会导致 onChange 甚至不会被调用。我也搞乱了,但无法让
@Binding var text: String
与 init 中设置的 ShrinkText 初始值一起使用。从我读到的内容来看,这似乎是最好的选择,但我不断收到错误,无法在 _shrinkText init 中将
Binding<String>
分配给
string

import SwiftUI

struct ExpandableText: View {
    @State private var expanded: Bool = false
    @State private var truncated: Bool = false
    @State private var textChanged: Bool = false
    @State private var shrinkText: String
    private var text: String

    let font: UIFont
    let lineLimit: Int
    
    private var moreLessText: String {
        if !truncated {
            return ""
        } else {
            return self.expanded ? "Read Less" : "Read More"
        }
    }
    
    init(_ text: String, lineLimit: Int, font: UIFont = UIFont(name: "Manrope-Regular", size: 16)!) {
        self.text = text
        self.lineLimit = lineLimit
        _shrinkText =  State(wrappedValue: text)
        self.font = font
    }
    
    var body: some View {
        
        VStack(alignment: .leading) {
            Text(self.expanded ? text : shrinkText)
                .allowsTightening(true)
                .fixedSize(horizontal: false, vertical: true)
                .font(Font.custom("Manrope-Regular", size: 16))
                .dynamicTypeSize(...DynamicTypeSize.large)

            if truncated {
                Button {
                    withAnimation(.easeInOut) {
                        expanded.toggle()
                    }
                } label: {
                    Text(moreLessText)
                        .font(Font.custom("Manrope-SemiBold", size: 16))
                        .dynamicTypeSize(...DynamicTypeSize.large)
                }
            }
        }
        .lineLimit(expanded ? nil : lineLimit)
        .onChange(of: text) { newValue in
            print("text value: \(text)")
            print("new value: \(newValue)")
        }
        
        .background(
            Text(text).lineLimit(lineLimit)
                .background(GeometryReader { visibleTextGeometry in
                    Color.purple.onAppear() {
                        let size = CGSize(width: visibleTextGeometry.size.width, height: .greatestFiniteMagnitude)
                        let attributes:[NSAttributedString.Key:Any] = [NSAttributedString.Key.font: font]
                        var low  = 0
                        var heigh = shrinkText.count
                        var mid = heigh
                        while ((heigh - low) > 1) {
                            let attributedText = NSAttributedString(string: shrinkText + moreLessText, attributes: attributes)
                            let boundingRect = attributedText.boundingRect(with: size, options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil)
                            if boundingRect.size.height > visibleTextGeometry.size.height {
                                truncated = true
                                heigh = mid
                                mid = (heigh + low)/2
                            } else {
                                if mid == text.count {
                                    break
                                } else {
                                    low = mid
                                    mid = (low + heigh)/2
                                }
                            }
                            shrinkText = String("\(text.prefix(mid))...")
                        }
                    }
                })
                .hidden()
        )
        .font(Font.custom("Manrope-Regular", size: 16)).dynamicTypeSize(...DynamicTypeSize.large)
    }
    
}

更新初始化:

struct ExpandableText: View {
    @State private var expanded: Bool = false
    @State private var truncated: Bool = false
    @State private var textChanged: Bool = false
    @State private var shrinkText: String
    @Binding var text: String

    let font: UIFont
    let lineLimit: Int
    
    private var moreLessText: String {
        if !truncated {
            return ""
        } else {
            return self.expanded ? "Read Less" : "Read More"
        }
    }
    
    init(_ text: Binding<String>, lineLimit: Int, font: UIFont = UIFont(name: "Manrope-Regular", size: 16)!) {
        self._text = text
        self.lineLimit = lineLimit
        _shrinkText =  State(wrappedValue: text) //<-- error: "Cannot convert value of type 'Binding<String>' to expected argument type 'String'"
        self.font = font
    }
...
}
swift swiftui binding state
1个回答
0
投票

为了使

text
可从另一个视图更新,您需要将其转换为绑定。为此,您需要进行一些更改。

  1. 更换

    private var text: String
    在你的结构中使用
    @Binding var text : String

  2. 将结构中的

    init(_ text: String, …)
    替换为
    init(_ text: Binding<String>, …)

  3. 在初始化程序中,使用代码

    text
    分配变量
    self._text = text
    请注意名称前面的下划线 - 这是避免您描述的错误消息所需要的。 这个 StackOverflow 问题 详细讨论了下划线语法的含义。

  4. ExpandableText
    视图的父视图中(我假设您想要修改
    text
    ,因为 SwiftUI 通常需要将数据从父级传递到子级),添加一个状态属性:
    @State private var actualText : String = “Hello World!” 
    actualText
    的内容可以在父级内部发生变异,例如响应轻击手势。

  5. actualText
    子视图中使用
    ExpandableText
    ExpandableText($actualText, …)
    ,其中省略号将替换为其他参数。 SwiftUI 中的 $ 符号用于获取状态变量的绑定,以便该变量可以与视图的子级共享,如本用例所示。

希望这有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.