Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/93.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何在视图不闪烁的情况下删除和添加ArrangedSubvew?_Ios_Swift_Uiview_Uistackview - Fatal编程技术网

Ios 如何在视图不闪烁的情况下删除和添加ArrangedSubvew?

Ios 如何在视图不闪烁的情况下删除和添加ArrangedSubvew?,ios,swift,uiview,uistackview,Ios,Swift,Uiview,Uistackview,我有一些从一个stackview组成的视图。每隔n秒,我都应该用服务器上的数据更新此视图。当新数据出现时,我清理stackView(使用其子级的方法removeFromSuperView)并再次添加ArrangedSubview以更新UI。有时,服务器发送与旧数据相同的数据。但在做这个更新操作时,我的观点有点不寒而栗。每次我清理并向stackview添加视图时,它都有点拖拉和颤抖。当然,我只能在oldData!=新数据。但这种竞争很难找到正确的答案。那么,如何使用新数据更新stackview而不

我有一些从一个stackview组成的视图。每隔
n
秒,我都应该用服务器上的数据更新此视图。当新数据出现时,我清理stackView(使用其子级的方法removeFromSuperView)并再次添加ArrangedSubview以更新UI。有时,服务器发送与旧数据相同的数据。但在做这个更新操作时,我的观点有点不寒而栗。每次我清理并向stackview添加视图时,它都有点拖拉和颤抖。当然,我只能在oldData!=新数据。但这种竞争很难找到正确的答案。那么,如何使用新数据更新stackview而不抖动和闪烁

这是我的密码:

func configure(_ items: [Item]) {
    stackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
    items.forEach { 
       let someView = SomeView()
       someView.configure($0)
       stackView.addArrangedSubview(someView)
    }
}

而不是删除/重新添加视图到堆栈视图

  • 仅当项目多于当前排列的子视图时,才添加新视图
  • 设置数据-
    configure()
    -每个排列的子视图
  • 如果现有排列的子视图超过需要,则隐藏现有排列的子视图
例如:

func configure(_ items: [Item]) {
    // if we have fewer arranged subviews than items
    //  add new ones
    while stackView.arrangedSubviews.count < items.count {
        stackView.addArrangedSubview(SomeView())
    }
    // hide any existing arranged subviews if we have too many
    for i in 0..<stackView.arrangedSubviews.count {
        stackView.arrangedSubviews[i].isHidden = i >= items.count
    }
    // update the existing arranged subviews with the new data
    for (thisItem, thisView) in zip(items, stackView.arrangedSubviews) {
        // unwrap the arranged subview
        guard let v = thisView as? SomeView else {
            continue
        }
        v.configure(thisItem)
    }
}
带有两个标签的示例“SomeView”类:

class SomeView: UIView {
    let titleLabel = UILabel()
    let descLabel = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        backgroundColor = .systemYellow
        titleLabel.font = .boldSystemFont(ofSize: 18.0)
        descLabel.font = .italicSystemFont(ofSize: 15.0)
        [titleLabel, descLabel].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
            v.backgroundColor = .white // so we can see the label frames at run-time
            addSubview(v)
        }
        NSLayoutConstraint.activate([
            titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
            titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),

            descLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4.0),

            descLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
            descLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
            descLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0),
        ])
    }
    
    func configure(_ item: Item) -> Void {
        titleLabel.text = item.title
        descLabel.text = item.desc
    }
}
带有堆栈视图的示例“NeoView”类:

class NeoView: UIView {

    let stackView: UIStackView = {
        let v = UIStackView()
        v.axis = .vertical
        v.spacing = 8
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        stackView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(stackView)
        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: topAnchor, constant: 0.0),
            stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0),
            stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0.0),
            stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0),
        ])
    }
    
    func configure(_ items: [Item]) {
        // if we have fewer arranged subviews than items
        //  add new ones
        while stackView.arrangedSubviews.count < items.count {
            stackView.addArrangedSubview(SomeView())
        }
        // hide any existing arranged subviews if we have too many
        for i in 0..<stackView.arrangedSubviews.count {
            stackView.arrangedSubviews[i].isHidden = i >= items.count
        }
        // update the existing arranged subviews with the new data
        for (thisItem, thisView) in zip(items, stackView.arrangedSubviews) {
            // unwrap the arranged subview
            guard let v = thisView as? SomeView else {
                continue
            }
            v.configure(thisItem)
        }
    }
}

为什么要重新创建视图?为什么您不能只创建一次,并保持对这些视图的引用,并每n秒更新一次,这样视图将在不闪烁的情况下更新。支持,我保持引用并将其存储为数组,如[SomeView]。但下一次更新的数据的长度大于[SomeView]长度。如您所见,无论如何,我应该重新创建视图。为什么不使用
UICollectionView
(或者
UITableView
)呢?这些设计用于(取消)当前不可能的视图队列。因为所有的项目都在类似卡片的视图中。是否可以将tableview放在类似卡片的视图中,并使卡片的高度适合tableview?我现在不知道。@neo-什么是
SomeView
?您不必删除和添加所有排列的子视图来更新它们。如果您向我们展示什么是
SomeView
(以及
Item
是什么),我可以向您展示更好的方法。
class NeoView: UIView {

    let stackView: UIStackView = {
        let v = UIStackView()
        v.axis = .vertical
        v.spacing = 8
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        stackView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(stackView)
        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: topAnchor, constant: 0.0),
            stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0),
            stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0.0),
            stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0),
        ])
    }
    
    func configure(_ items: [Item]) {
        // if we have fewer arranged subviews than items
        //  add new ones
        while stackView.arrangedSubviews.count < items.count {
            stackView.addArrangedSubview(SomeView())
        }
        // hide any existing arranged subviews if we have too many
        for i in 0..<stackView.arrangedSubviews.count {
            stackView.arrangedSubviews[i].isHidden = i >= items.count
        }
        // update the existing arranged subviews with the new data
        for (thisItem, thisView) in zip(items, stackView.arrangedSubviews) {
            // unwrap the arranged subview
            guard let v = thisView as? SomeView else {
                continue
            }
            v.configure(thisItem)
        }
    }
}
class NeoTestViewController: UIViewController {
    
    let neoView: NeoView = {
        let v = NeoView()
        v.backgroundColor = .systemTeal
        return v
    }()
    
    var items: [[Item]] = []
    var idx: Int = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        neoView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(neoView)
        
        // respect safe area
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            neoView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            neoView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            neoView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            // no bottom constraint
        ])
        
        items = sampleData()
        
        var idx: Int = 0
        self.neoView.configure(self.items[idx % self.items.count])

        // update neoView with a new set of items every 1.5 seconds
        Timer.scheduledTimer(withTimeInterval: 1.5, repeats: true) { timer in
            idx += 1
            self.neoView.configure(self.items[idx % self.items.count])
        }
        
    }
    
    func sampleData() -> [[Item]] {

        // we'll create 8 sets of [Item] arrays
        //  each with a different number of Items
        let numItems: [Int] = [
            4, 2, 6, 3, 7, 8, 3, 5,
        ]
        
        var items: [[Item]] = []
        var i: Int = 1
        numItems.forEach { n in
            var theseItems: [Item] = []
            for j in 1...n {
                let thisItem = Item(title: "Set \(i) item \(j) title.", desc: "Set \(i) item \(j) description.")
                theseItems.append(thisItem)
            }
            theseItems[0].title = "Set \(i) has \(n) items."
            items.append(theseItems)
            i += 1
        }

        return items
    }
    
}