Search code examples
swiftxcode11ios13

Replacing UISearchBar magnifying icon with UIActivityViewController


I've been searching all day but couldn't find out a fix for this code. This extension replaces the UISearchField magnifying icon with UIActivityView (shows the loading icon when is true)

The extension was working fine on iOS 12, Xcode 10.3 but after I've changed into iOS 13, Xcode 11 Beta 4 it stopped working.

I've still made a workaround using this:

if let textFieldInsideSearchBar = searchBar.value(forKey: "searchField") as? UITextField {
      let loadingIcon = UIActivityIndicatorView()
      loadingIcon.style = .medium
      loadingIcon.backgroundColor = UIColor.clear
      loadingIcon.startAnimating()
      textFieldInsideSearchBar.leftView = loadingIcon
}

But I can't understand the reason why the extension stopped working. Also I've noticed that .flatMap was deprecated in iOS 13 and changed to .compactMap but as I understood there were no differences, and I've already tried to change the .flatMap to .compactMap but still didn't work.

Here is the extension:

extension UISearchBar {
    private var textField: UITextField? {
        let subViews = self.subviews.compactMap { $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()
                    _activityIndicator.style = .medium
                    _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()
            }
        }
    }
}

Solution

  • There have been some changes with iOS 13 in terms of UISearchBar, And you can use UISearchBar.searchTextField instead of searchBar.value(forKey: "searchField")

    searchBar.searchTextField.backgroundColor = .red
    

    Or if you want to keep it work with the extension, You can do this:

    var searchTextField: UITextField? {
        let subViews = self.subviews.first?.subviews.last?.subviews
        return subViews?.first as? UITextField
    }