我实现了
UISearchController
并且我从 js 回调中获取数据,但是当我录入 searchbar
时,需要一些时间来放置数据,所以我想知道如何实现将 indicator
加载到表中查看结果 UISearchController
用 Swift 3 编写了这个扩展,看起来效果很好。
extension UISearchBar {
private var textField: UITextField? {
return subviews.first?.subviews.flatMap { $0 as? UITextField }.first
}
private var activityIndicator: UIActivityIndicatorView? {
return textField?.leftView?.subviews.flatMap{ $0 as? UIActivityIndicatorView }.first
}
var isLoading: Bool {
get {
return activityIndicator != nil
} set {
if newValue {
if activityIndicator == nil {
let newActivityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
newActivityIndicator.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
newActivityIndicator.startAnimating()
newActivityIndicator.backgroundColor = UIColor.white
textField?.leftView?.addSubview(newActivityIndicator)
let leftViewSize = textField?.leftView?.frame.size ?? CGSize.zero
newActivityIndicator.center = CGPoint(x: leftViewSize.width/2, y: leftViewSize.height/2)
}
} else {
activityIndicator?.removeFromSuperview()
}
}
}
}
iOS 13 的更新解决方案:
extension UISearchBar {
var textField: UITextField? {
if #available(iOS 13.0, *) {
return searchTextField
} else {
if let textField = value(forKey: "searchField") as? UITextField {
return textField
}
return nil
}
}
private var activityIndicator: UIActivityIndicatorView? {
return textField?.leftView?.subviews.compactMap{ $0 as? UIActivityIndicatorView }.first
}
var isLoading: Bool {
get {
return activityIndicator != nil
} set {
if newValue {
if activityIndicator == nil {
let newActivityIndicator = UIActivityIndicatorView(style: .gray)
newActivityIndicator.startAnimating()
if #available(iOS 13.0, *) {
newActivityIndicator.backgroundColor = UIColor.systemGroupedBackground
} else {
newActivityIndicator.backgroundColor = UIColor.groupTableViewBackground
}
newActivityIndicator.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
textField?.leftView?.addSubview(newActivityIndicator)
let leftViewSize = textField?.leftView?.frame.size ?? CGSize.zero
newActivityIndicator.center = CGPoint(x: leftViewSize.width/2, y: leftViewSize.height/2)
}
} else {
activityIndicator?.removeFromSuperview()
}
}
}
}
适用于 iOS 13 及更高版本的更干净的解决方案:
extension UISearchController {
private static let defaultLeftView: UIView = {
UISearchTextField().leftView ?? UIView()
}()
private static let leftViewSize: CGSize = {
UISearchTextField().leftView?.frame.size ?? .zero
}()
private static let loadingLeftView: UIView = {
let view = UIView(frame: .init(origin: .zero, size: leftViewSize))
let activityIndicatorView = UIActivityIndicatorView(style: .medium)
activityIndicatorView.transform = .init(scaleX: 0.9, y: 0.9)
activityIndicatorView.startAnimating()
view.addSubview(activityIndicatorView)
activityIndicatorView.center = CGPoint(x: leftViewSize.width / 2, y: leftViewSize.height / 2)
return view
}()
func startLoading() {
searchBar.searchTextField.leftView = Self.loadingLeftView
}
func stopLoading() {
searchBar.searchTextField.leftView = Self.defaultLeftView
}
}
当您开始搜索时,您可以创建一个活动指示器,并使用
subview
方法将其添加为 UISearchBar
的 addSubView
。
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
//set your frame for activity indicator
[searchBar addSubview: spinner];
[spinner startAnimating];
完成搜索后,使用
removeFromSuperView
方法将其从搜索栏中删除。
请尝试一下这个。可能对你有帮助
SearchBarWithloading.h
#import <UIKit/UIKit.h>
@interface SearchBarWithloading : UISearchBar
- (void)startActivity; // increments startCount and shows activity indicator
- (void)finishActivity; // decrements startCount and hides activity indicator if 0
@end
SearchBarWithloading.m
import "SearchBarWithloading.h"
@interface SearchBarWithloading()
@property(nonatomic) UIActivityIndicatorView *activityIndicatorView;
@property(nonatomic) int startCount;
@end
@implementation SearchBarWithloading
- (void)layoutSubviews {
UITextField *searchField = nil;
for(UIView* view in self.subviews){
if([view isKindOfClass:[UITextField class]]){
searchField= (UITextField *)view;
break;
}
}
if(searchField) {
if (!self.activityIndicatorView) {
UIActivityIndicatorView *taiv = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
taiv.center = CGPointMake(searchField.leftView.bounds.origin.x + searchField.leftView.bounds.size.width/2,
searchField.leftView.bounds.origin.y + searchField.leftView.bounds.size.height/2);
taiv.hidesWhenStopped = YES;
taiv.backgroundColor = [UIColor whiteColor];
self.activityIndicatorView = taiv;
[taiv release];
_startCount = 0;
[searchField.leftView addSubview:self.activityIndicatorView];
}
}
[super layoutSubviews];
}
- (void)startActivity {
self.startCount = self.startCount + 1;
}
- (void)finishActivity {
self.startCount = self.startCount - 1;
}
- (void)setStartCount:(int)startCount {
_startCount = startCount;
if (_startCount > 0)
[self.activityIndicatorView startAnimating];
else {
[self.activityIndicatorView stopAnimating];
}
}
@end
sereisoglu 的解决方案会偶尔崩溃,可能是因为它在 defaultLeftView 静态变量中保存了不存在视图的子视图。
更稳定的解决方案:
extension UISearchBar {
private static let leftViewSize: CGSize = {
UISearchTextField().leftView?.frame.size ?? .zero
}()
private static let leftViewTint: UIColor? = {
UISearchTextField().leftView?.tintColor
}()
private static let loadingLeftView: UIView = {
let view = UIView(frame: .init(origin: .zero, size: leftViewSize))
let activityIndicatorView = UIActivityIndicatorView(style: .medium)
activityIndicatorView.transform = .init(scaleX: 0.9, y: 0.9)
activityIndicatorView.startAnimating()
view.addSubview(activityIndicatorView)
activityIndicatorView.center = CGPoint(x: leftViewSize.width / 2, y: leftViewSize.height / 2)
return view
}()
func startLoading() {
DispatchQueue.main.async {
self.searchTextField.leftView?.tintColor = .clear
self.searchTextField.leftView?.addSubview(Self.loadingLeftView)
}
}
func stopLoading() {
DispatchQueue.main.async {
self.searchTextField.leftView?.subviews[0].removeFromSuperview()
self.searchTextField.leftView?.tintColor = Self.leftViewTint
}
}
}