Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A small extension for UISearchBar which shows an UIActivityIndicator while searching
//
// UISearchBar+Ext.swift
// frazeit
//
// Created by Maysam Shahsavari on 7/30/18.
// Edited on 16/05/19 for Swift 5.0.
// Copyright © 2018 Maysam Shahsavari. All rights reserved.
//
import Foundation
import UIKit
extension UISearchBar {
private var textField: UITextField? {
let subViews = self.subviews.flatMap { $0.subviews }
return (subViews.filter { $0 is UITextField }).first as? UITextField
}
private var searchIcon: UIImage? {
let subViews = subviews.flatMap { $0.subviews }
return ((subViews.filter { $0 is UIImageView }).first as? UIImageView)?.image
}
private var activityIndicator: UIActivityIndicatorView? {
return textField?.leftView?.subviews.compactMap{ $0 as? UIActivityIndicatorView }.first
}
var isLoading: Bool {
get {
return activityIndicator != nil
} set {
let _searchIcon = searchIcon
if newValue {
if activityIndicator == nil {
let _activityIndicator = UIActivityIndicatorView(style: .gray)
_activityIndicator.startAnimating()
_activityIndicator.backgroundColor = UIColor.clear
self.setImage(UIImage(), for: .search, state: .normal)
textField?.leftView?.addSubview(_activityIndicator)
let leftViewSize = textField?.leftView?.frame.size ?? CGSize.zero
_activityIndicator.center = CGPoint(x: leftViewSize.width/2, y: leftViewSize.height/2)
}
} else {
self.setImage(_searchIcon, for: .search, state: .normal)
activityIndicator?.removeFromSuperview()
}
}
}
}
/*
Usage:
To show the acttivity indicator
searchController.searchBar.isLoading = true
To stop the activity indicator (assuming it will be called when a network or extensive block is finished)
DispatchQueue.main.async {
searchController.searchBar.isLoading = false
}
*/
@johnjcamilleri

This comment has been minimized.

Copy link

commented Jan 24, 2019

Great extension, works like a charm!

@antoinepemeja

This comment has been minimized.

Copy link

commented Mar 19, 2019

Yes great extension, thank you.
Unfortunately it doesn't work on iOS 10, it shows a square. Do you have an idea to fix it ?

@antoinepemeja

This comment has been minimized.

Copy link

commented Mar 20, 2019

Hello,

My suggestion to support iOS 10 :

    var isLoading: Bool {
        get {
            
            return activityIndicator != nil
        } set {
            if newValue {
                if activityIndicator == nil {
                    
                    var style: UIActivityIndicatorView.Style = UIActivityIndicatorView.Style.gray
                    var backgroundColor: UIColor = UIColor.white
                    
                    if #available(iOS 11.0, *) {
                        style = UIActivityIndicatorView.Style.white
                        backgroundColor = UIColor.clear
                    }
                    
                    let _activityIndicator = UIActivityIndicatorView(style: style)
                    _activityIndicator.startAnimating()
                    _activityIndicator.backgroundColor = backgroundColor

                    if #available(iOS 11.0, *) {
                        self.setImage(UIImage(), for: .search, state: .normal)
                    }

                    textField?.leftView?.addSubview(_activityIndicator)
                    let leftViewSize = textField?.leftView?.frame.size ?? CGSize.zero
                    _activityIndicator.center = CGPoint(x: leftViewSize.width/2, y: leftViewSize.height/2)
                }
            } else {
                if #available(iOS 11.0, *) {
                    let _searchIcon = searchIcon
                    self.setImage(_searchIcon, for: .search, state: .normal)
                }
                activityIndicator?.removeFromSuperview()
            }
        }
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.