swift – The way to get iOS to really utterly replace and launch the display screen, the UI, between every step, when for instance loading a stack?

0
26
swift – The way to get iOS to really utterly replace and launch the display screen, the UI, between every step, when for instance loading a stack?


This is one thing I’ve by no means been in a position to determine in UIKit.

In Xcode click on a brand new app mission, swift/sboard

import UIKit
class ViewController: UIViewController {

    let stack = UIStackView.Typical
    
    override func viewDidLoad() {
        tremendous.viewDidLoad()
        _setup()
    }
    
    @objc func load() {
        stack.removeFullyAll()
        for _ in 1...50 {
            let l = UILabel.Typical
            l.backgroundColor = .randomSoft
            l.textual content = [String](repeating: "string", rely: 20).joined(separator: " ")
            stack.addArrangedSubview(l)
        }
    }
    
    func _setup() {
        let scroll = UIScrollView.Typical
        view.addSubview(scroll)
        scroll.addSubview(stack)
        scroll.backgroundColor = .systemPink
        stack.axis = .vertical
        stack.spacing = 2
        
        let b = UIButton.Typical
        view.addSubview(b)
        b.setImage(.init(systemName: "wand.and.stars"), for: [])
        b.setTitle(" fill ", for: [])
        b.backgroundColor = .yellow
        b.setTitleColor(.label, for: [])
        b.addTarget(self, motion: #selector(load), for: .primaryActionTriggered)
        
        NSLayoutConstraint.activate([
            scroll.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 50),
            scroll.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -50),
            scroll.topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
            scroll.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -100),
            stack.leftAnchor.constraint(equalTo: scroll.leftAnchor, constant: 2),
            stack.rightAnchor.constraint(equalTo: scroll.rightAnchor, constant: -2),
            stack.topAnchor.constraint(equalTo: scroll.topAnchor, constant: 2),
            stack.bottomAnchor.constraint(equalTo: scroll.bottomAnchor, constant: -2),
            b.leftAnchor.constraint(equalTo: scroll.leftAnchor),
            b.bottomAnchor.constraint(equalTo: scroll.topAnchor, constant: -4),
        ])
    }
}

extension UIView {
    static var Typical: Self {
        let v = Self()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .clear
        return v
    }
}
extension UIColor {
    static var randomSoft: UIColor {
        return UIColor(hue: CGFloat(Int.random(in: 0..<20)) / 20.0,
          saturation: 0.3, brightness: 0.8, alpha: 1)
    }
}
extension UIStackView {
    func removeFully(view: UIView) {
        removeArrangedSubview(view)
        view.removeFromSuperview()
    }
    func removeFullyAll() {
        arrangedSubviews.forEach { (view) in
            removeFully(view: view)
        }
    }
}

UIKit puzzle

Run, and faucet the fill button. It’s going to “immediately” populate.

Now strive

        for _ in 1...2000 {

relying in your machine, it’s going to now hold for a number of seconds, whereas it figures this out.

This is the factor. I need it to

  • put in a single view
  • really “try this”, and draw it to the display screen through the window engine (or regardless of the hell it is doing)
  • begin desirous about the subsequent one,
  • try this one and repeat

Purely as an instance, now swap on this operate:

@objc func load() {
    stack.removeFullyAll()
    for i in 1...2000 {
        delay(Double(i) * 0.05) {
            let l = UILabel.Typical
            l.backgroundColor = .randomSoft
            l.textual content = [String](repeating: "string", rely: 20).joined(separator: " ")
            self.stack.addArrangedSubview(l)
        }
    }
}

Run. Discover it really works, illustratively, superbly – it brings them in one after the other, and, you may frequently scroll in two instructions and so on because it does so, the scroll bars slowly reshape and so on.

(Observe this doesn’t in fact “work very well”, it is only a demo to elucidate the specified consequence. the .05 is a multitude clearly and the approximate wanted time goes haywire because it will get larger; strive a good bigger rely, 10,000 or such, and it collapses. Once more that is only a demo to point out you the specified consequence.)

Now, I’ve all the time thought that this type of factor ought to work,

@objc func load() {
    stack.removeFullyAll()
    for _ in 1...550 {
        let l = UILabel.Typical
        l.backgroundColor = .randomSoft
        l.textual content = [String](repeating: "string", rely: 20).joined(separator: " ")
        stack.addArrangedSubview(l)
        
        view.setNeedsLayout()
        view.layoutIfNeeded()
        print("wth")
    }
}

Nevertheless it doesn’t work – strive it. (It is really a lot slower.)

Knock your self out, strive

        stack.setNeedsLayout()
        view.layoutIfNeeded()

or any mixture. strive throwing in

        RunLoop.major.run(mode: .frequent, earlier than: Date.now)

as a lot as you need .. no good.

(PS, I do not care about stack views particularly, this comes up on a regular basis whenever you’re constructing “tons and plenty of stuff”; I simply used a stack view on this right here demo since it is simple to stick. An equal demo can be, say, simply stick 10,00 labels on the display screen every with two constraints – no matter.)

I’ve defined it as clearly as might be. How on earth to get the UI thread to take over, do it is stuff, launch once more, after which do its stuff once more – word how all the things nonetheless responsive all through the progressive construct within the low cost “0.05” demo.

Why does not layoutIfNeeded do that, am I making some mistake, why does triggering the run loop do nothing?

The way to obtain it?

LEAVE A REPLY

Please enter your comment!
Please enter your name here