-
-
Save bubudrc/3076b83dc628a1828b9cf280d498dfc2 to your computer and use it in GitHub Desktop.
A small extension for UISearchBar which shows an UIActivityIndicator while searching
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// UISearchBar+Ext.swift | |
// frazeit | |
// | |
// Created by Maysam Shahsavari on 7/30/18. | |
// Updated on 9/26/19. | |
// Copyright © 2018 Maysam Shahsavari. All rights reserved. | |
// Updated: 10/02/2020. | |
import Foundation | |
import UIKit | |
extension UIImage { | |
func imageWithPixelSize(size: CGSize, filledWithColor color: UIColor = UIColor.clear, opaque: Bool = false) -> UIImage? { | |
return imageWithSize(size: size, filledWithColor: color, scale: 1.0, opaque: opaque) | |
} | |
func imageWithSize(size: CGSize, filledWithColor color: UIColor = UIColor.clear, scale: CGFloat = 0.0, opaque: Bool = false) -> UIImage? { | |
let rect = CGRect.init(x: 0, y: 0, width: size.width, height: size.height) | |
UIGraphicsBeginImageContextWithOptions(size, opaque, scale) | |
color.set() | |
UIRectFill(rect) | |
let image = UIGraphicsGetImageFromCurrentImageContext() | |
UIGraphicsEndImageContext() | |
return image | |
} | |
} | |
extension UISearchBar { | |
private var textField: UITextField? { | |
let subViews = self.subviews.flatMap { $0.subviews } | |
if #available(iOS 13, *) { | |
if let _subViews = subViews.last?.subviews { | |
return (_subViews.filter { $0 is UITextField }).first as? UITextField | |
}else{ | |
return nil | |
} | |
} else { | |
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 func getViewElement<T>(type: T.Type) -> T? { | |
let svs = subviews.flatMap { $0.subviews } | |
guard let element = (svs.filter { $0 is T }).first as? T else { return nil } | |
return element | |
} | |
func getSearchBarTextField() -> UITextField? { | |
return getViewElement(type: UITextField.self) | |
} | |
func setTextColor(color: UIColor) { | |
if let textField = getSearchBarTextField() { | |
textField.textColor = color | |
} | |
} | |
func setTextFieldColor(color: UIColor) { | |
if let textField = getViewElement(type: UITextField.self) { | |
switch searchBarStyle { | |
case .minimal: | |
textField.layer.backgroundColor = color.cgColor | |
textField.layer.cornerRadius = 6 | |
case .prominent, .default: | |
textField.backgroundColor = color | |
@unknown default: | |
break | |
} | |
} | |
} | |
func setPlaceholderTextColor(color: UIColor) { | |
if let textField = getSearchBarTextField() { | |
textField.attributedPlaceholder = NSAttributedString(string: self.placeholder != nil ? self.placeholder! : "", attributes: [NSAttributedString.Key.foregroundColor: color]) | |
} | |
} | |
/////// | |
private var activityIndicator: UIActivityIndicatorView? { | |
return textField?.leftView?.subviews.compactMap{ $0 as? UIActivityIndicatorView }.first | |
} | |
// Public API | |
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 | |
let clearImage = UIImage().imageWithPixelSize(size: CGSize.init(width: 14, height: 14)) ?? UIImage() | |
self.setImage(clearImage, for: .search, state: .normal) | |
textField?.leftViewMode = .always | |
textField?.leftView?.addSubview(_activityIndicator) | |
let leftViewSize = CGSize.init(width: 14.0, height: 14.0) | |
_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 | |
} | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment