Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to put ActivityIndicator inside UIImage inside UITableView using Swift?

I have UITableView where each cell has one UIImage and the image is being downloaded from an API using JSON.

I handled the initial images and data via Background Threading. However, as user scrolls down inside table view, images to other cells begins to download, so those cells requires some refreshing.

I thought about adding an ActivityIndicator inside UIImageView, so user will notice image is being downloaded.

Additional info, UIImageView is inside an UIStackView. I thought about isHidden method, could not implemented.

Thank you for your time.

like image 661
Vetuka Avatar asked Feb 03 '26 06:02

Vetuka


1 Answers

Ordinarily I'd recommend using a library like Kingfisher to manage this for you (I believe you can set a placeholder view to display while you're loading) but if you want to do this manually you could have something like

enum LoadingState {
    case notLoading
    case loading
    case loaded(UIImage)
}

class MyTableViewCell: UITableViewCell {
    let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
    let imageStackView = UIStackView()
    let myImageView = UIImageView() // can't be named imageView because UITableViewCell already has one with that name

    var loadingState: LoadingState = .notLoading {  // many ways you could do this, you just need one or more "update" mechanisms to start/stop the spinner and set your image
        didSet {
            switch loadingState {
            case .notLoading:
                myImageView.image = nil
                activityIndicator.stopAnimating()
            case .loading:
                myImageView.image = nil
                activityIndicator.startAnimating()
            case let .loaded(img):
                myImageView.image = img
                activityIndicator.stopAnimating()
            }
        }
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        configure()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        configure()
    }

    private func configure() {
        contentView.addSubview(activityIndicator)
        contentView.addSubview(imageStackView)
        imageStackView.addArrangedSubview(myImageView)
        // constrain activity indicator and stack view
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        loadingState = .notLoading
    }
}
like image 151
jefflovejapan Avatar answered Feb 05 '26 20:02

jefflovejapan