有没有办法在不删除视图并重新添加的情况下更新 StackView 中的视图?

Posted

技术标签:

【中文标题】有没有办法在不删除视图并重新添加的情况下更新 StackView 中的视图?【英文标题】:Is there a way to update views in StackView without removing the view and re adding it? 【发布时间】:2021-02-19 09:52:10 【问题描述】:

我有使用自动布局的视图。我知道我希望每个视图的确切宽度(每个宽度都不同)。 StackView 嵌套在集合视图中。堆栈视图中的视图是从主视图控制器动态加载的。我想在集合视图重新加载时更新堆栈视图视图,而不删除视图并再次添加它们。我无法删除视图并重新添加它们,因为某些视图具有文本字段,如果重新加载它们会关闭键盘。我已经解释了下面的代码

感谢您的帮助。


编辑

这是我正在寻找的布局。

我使用Carbon 将视图呈现到集合视图中:

    private func render() 
        renderer.render 
            Section(
                id: "testing row collection",
                cells: 
                    Row(id: "row id", data: [
                        Input(
                            id: 6,
                            props: InputContent.State(
                                text: self.state.inputText,
                                placeholder: "Search",
                                size: .medium
                            ),
                            onChange:  [weak self] text in
                                print("text is:", text)
                                self?.state.inputText = text
                            
                        )
                    ])
                
            )
        
    

注意:图像和代码与实现不匹配。图片显示3个视图,代码只显示1个。

Row 类是呈现包含 UIStackView 的视图的类。在里面我有一个视图列表,目前只有 1 个视图。它将text 设置为self.state.inputText,这是视图控制器中的一个变量。然后在文本字段中的任何更改我将self.state.inputText 设置为该文本。当设置变量state 时,运行render()

Row 类:

这个类渲染实际的 UIView,它被称为RowContent。它调用RowContent 类中显示的updateState(state:) 方法。当集合视图呈现时调用它

RowContent 类:

class RowContent: UIView 

    var stack: UIStackView

    var state: State
    
    struct State 
        var views: [UIView] = [UIView]()
    
    
    public func updateState(_ state: State? = nil) 
        self.state = state ?? self.state
        //updateView()
    
    
    required init(state: State) 
        self.state = state
        self.stack = UIStackView(arrangedSubviews: state.views)
        super.init(frame: .zero)
        self.setupStackView()
    

    ...


堆栈视图在初始化程序中填充视图,然后我在setupStackview()中添加约束

目前,当集合视图重新呈现时,视图永远不会更新,这意味着 Input 中的 text 属性永远不会更新。我想在集合视图重新呈现时更新视图。这将在被注释掉的updateView() 方法中。我不知道如何在不删除视图并重新添加它们的情况下更新 collectionView 中的视图。

谢谢。

我在这里添加了一个例子:https://github.com/4ndrewHarri5/ExampleRow

【问题讨论】:

有点困惑...不管您的尺寸问题如何,您是否需要使用集合视图?或者堆栈视图(一旦您了解如何在不关闭键盘的情况下更新排列的子视图的高度)就足够了? 嗨,我不需要使用集合视图,最好使用堆栈视图。谢谢 OK - 你的目标是拥有一个水平滚动的stackView吗?如果您显示您正在尝试实现的布局的图像会有所帮助... 嗨@DonMag,我已经更新了问题,谢谢 您的图像是否显示 3 个“列”?哪里,第 1 列和第 3 列大小相等,而中间列更宽?而且,什么是可编辑的,可以调出键盘?搜索“细胞”?中间单元格?第一列和第二列是否显示相同的文本,或者可能不同?而且,这最终会有一系列看起来像这样的“行”吗? 【参考方案1】:

试试这个...

我们从一个标签“基础”视图类开始——它将为标签视图设置背景颜色和圆角:

// background and rounded corners
class TagBaseView: UIView 
    
    override init(frame: CGRect) 
        super.init(frame: frame)
        commonInit()
    
    required init?(coder: NSCoder) 
        super.init(coder: coder)
        commonInit()
    
    func commonInit() -> Void 
        layer.cornerRadius = 12
        layer.masksToBounds = true
        backgroundColor = UIColor(red: 0.96, green: 0.95, blue: 0.97, alpha: 1.0)
    
    

子类TagBaseView,添加UILabel

class TagLabelView: TagBaseView 
    
    let label = UILabel()
    
    override init(frame: CGRect) 
        super.init(frame: frame)
        commonInit()
    
    required init?(coder: NSCoder) 
        super.init(coder: coder)
        commonInit()
    
    override func commonInit() -> Void 
        super.commonInit()

        label.font = .boldSystemFont(ofSize: 18.0)
        label.numberOfLines = 0
        addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
            label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
            label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
            label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0),
        ])

    
    

子类TagBaseView,添加UITextField

class TagFieldView: TagBaseView 
    
    let field = UITextField()
    
    var textChangeCallback: ((String)->())?
    
    override init(frame: CGRect) 
        super.init(frame: frame)
        commonInit()
    
    required init?(coder: NSCoder) 
        super.init(coder: coder)
        commonInit()
    
    override func commonInit() -> Void 
        super.commonInit()
        
        field.font = .boldSystemFont(ofSize: 18.0)
        addSubview(field)
        field.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            // constrain text field Leading / Trailing
            field.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
            field.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
            // center it vertically
            field.centerYAnchor.constraint(equalTo: centerYAnchor),
            // require at least 8-pts Top and Bottom
            field.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: 8.0),
            field.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor, constant: -8.0),
        ])
        
        field.addTarget(self, action: #selector(self.textDidChange(_:)), for: .editingChanged)
        
    

    @objc func textDidChange(_ textField: UITextField) -> Void 
        guard let s = textField.text else 
            return
        
        // tell the controller the text changed
        textChangeCallback?(s)
    
    

视图控制器类 - 创建一个水平堆栈视图,具有 TagLabelView“左”视图、TagLabelView“中心”视图和 TagFieldView“右”视图。

当我们在“右”视图中编辑文本字段时,它将使用闭包“回调”到我们处理文本更改并更新左视图和中心视图的控制器:

class EditStackViewController: UIViewController 
    
    let stack: UIStackView = 
        let v = UIStackView()
        v.spacing = 8
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    ()
    
    let leftView = TagLabelView()
    let centerView = TagLabelView()
    let rightView = TagFieldView()
    
    override func viewDidLoad() 
        super.viewDidLoad()
        
        view.addSubview(stack)
        
        stack.addArrangedSubview(leftView)
        stack.addArrangedSubview(centerView)
        stack.addArrangedSubview(rightView)

        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // constrain stack view Top / Leading / Trailing
            //  (no Bottom or Height)
            stack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            stack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
            stack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
            
            // make "center" view 45% of the width
            centerView.widthAnchor.constraint(equalTo: stack.widthAnchor, multiplier: 0.45),
            
            // make "right" view equal width to "left" view
            rightView.widthAnchor.constraint(equalTo: leftView.widthAnchor),
            
        ])
        
        rightView.field.placeholder = "Search"

        // TagSearchView tells us when the field is being edited
        rightView.textChangeCallback =  [weak self] str in
            guard let self = self else 
                return
            
            self.leftView.label.text = str
            self.centerView.label.text = str
        
        
    
    

结果:

【讨论】:

感谢您的深入回答。我觉得你还不够了解我。堆栈视图嵌套在 collectionView 单元格内。 leftView、centerView 和 rightView 从数组中的 viewController 传递到该单元格。在重新加载时,我想更新视图。每个视图都不同,所以我不知道在文本更改时能够设置视图文本或设置任何其他属性的类型。带有堆栈视图的单元格应该足够通用,可以传入任何 UIViews 并且视图得到更新,而无需设置文本更改的属性。谢谢 @AndrewHarris - 正如我在我的 cmets 中所说的,难以掌握你的目标。我问你是否需要一个集合视图,你说不,堆栈视图可以工作。您添加到问题中的图像并未显示与集合视图真正相关的任何内容。如果您可以提供有关您要做什么的完整详细信息 - 即不仅仅是 3 个圆角矩形 - 我可以尝试提供帮助。而且,尝试这样做而不需要你对“碳”所做的任何事情......我认为这只是令人困惑的事情。 我的意思是使用嵌套的collectionView而不是嵌套的stackView。就像通过使用集合视图来复制堆栈视图一样,因为我在更新堆栈视图内部的视图时遇到了麻烦。我提到碳是因为你以声明的方式声明了你想要的视图,所以它说“我想要一个带有单元格的部分,我想要的单元格是行”然后在行内我传入“数据”,这是里面的视图堆栈视图。很抱歉让您感到困惑,我不想提供太多可能不相关的细节。我可以提供一个显示问题的示例项目。 我在问题中添加了一个示例。谢谢 @AndrewHarris - 我抓住了你的 GitHub 存储库...点击第二行上的任一“字段”会打开键盘,在该字段中输入会更新“第一”行,包括更改高度当它需要包装时。所以......仍然不清楚问题是什么?

以上是关于有没有办法在不删除视图并重新添加的情况下更新 StackView 中的视图?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI - 有没有办法在不覆盖子视图的任何手势的情况下向视图添加手势?

有没有办法在不重新启动 Solr 服务器的情况下动态更新同义词文件?

如何在不删除适配器的情况下更新数据集以反映数据源中添加的列?

我们如何在不重新加载页面的情况下使用 javascript/jQuery 更新 URL 或查询字符串?

在不重新加载的情况下更新 UITableViewCell

有没有办法在不创建新套接字的情况下处理 CRL 更新