1.はじめに
仕事で、UISearchBarで初期描画時にフォーカスを当てた状態で表示する必要がある場面がありました。
一行追加するだけでフォーカス状態にできるようですので共有したいと思います。
2. UISearchBarでのフォーカスについて
UISearchBarの初期フォーカスについては、
UIResponderのbecomeFirstResponderを使ってフォーカス状態にできるようです。
UIResponderクラスは画面タッチやデバイスのモーションなどのイベントを管理するクラスです。イベントには、タッチイベント、モーションイベント、リモコンイベント、プレスイベントなど、いくつかの種類があります。
becomeFirstResponderの説明に戻りますが、
Apple Developper - becomeFirstResponder()には下記のように説明書きが載っています。
UIKit に、このオブジェクトをウィンドウの最初のレスポンダにするように依頼します。
では実際に実装を見てみましょう。
※UISearchBarの他、textField単体にbecomeFirstResponderを設定しても、フォーカス状態になります。その際はUISearchBar同様、入力のキーボードが表示されるはずです。
●Swift
実際のソースコード実装を見てみましょう。
ここで肝になるのは
self.searchBar.becomeFirstResponder()
の部分です。becomeFirstResponderでフォーカスを当てるので、この一文を追加して設定します。
class ViewController: UIViewController, UISearchBarDelegate {
private var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
self.searchBar = UISearchBar(frame: CGRect(x: 10, y: 50, width: self.view.frame.size.width - 20, height: 40))
self.searchBar.delegate = self
self.searchBar.backgroundColor = UIColor.gray
self.searchBar.searchTextField.textColor = .white
self.searchBar.placeholder = "検索する"
self.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "検索する",attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])
self.searchBar.backgroundImage = UIImage.init()
self.view.addSubview(self.searchBar)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.searchBar.becomeFirstResponder() //←ここでフォーカス設定をする
}
}
「viewDidLoadで設定しないの?」
と思った方もいるかもしれませんが、viewDidLoad内でbecomeFirstResponderを呼び出してもフォーカスが当たった状態で表示されません。
・なぜviewDidLoadで設定しても反映されないのか?
これはライフサイクルが影響しています。
ここで問題なのは、UISerchBarがロード中にbecomeFirstResponderの呼び出しが行われてしまうこと にあります。
Apple Developper - becomeFirstResponder()には下記のように記載されています。
Only call this method on views that are part of the active view hierarchy. To determine whether a view is onscreen, check its window property. If that property contains a valid window, it’s part of an active view hierarchy.
訳:このメソッドは、アクティブなビュー階層の一部であるビューに対してのみ呼び出します。ビューが画面上にあるかどうかを判断するには、そのウィンドウプロパティを確認します。そのプロパティが有効なウィンドウを含んでいる場合、それはアクティブなビュー階層の一部です。
つまり、viewDidLoadを読み込んでいる途中で設定しても、UISerchBarが表示が完了していないため、アクティブなビューとはみなせない ということです。
そのため、viewDidAppearで設定すれば描画された後ですので、アクティブなビューとみなされ、設定が効くというわけです。
viewDidAppearは完全に遷移が行われ、スクリーン上にViewが表示された時(画面に描画されている状態)のタイミングでのメソッドです。
●Objective-C
では、Objective-Cではどのような実装になるのでしょうか?
ここでも肝になるのは
[self.searchBar becomeFirstResponder];
の部分です。
Objective-Cでも上記解説の理由から、viewDidAppearでbecomeFirstResponderを設定します。
@interface SampleSearchBarViewController ()
@end
@implementation SampleSearchBarViewController
- (void)viewDidLoad;
{
[super viewDidLoad];
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(10.f, 50.f, self.view.frame.size.width - 20.f, 40)];
self.searchBar.delegate = self;
self.searchBar.backgroundColor = [UIColor grayColor];
self.searchBar.searchTextField.textColor = [UIColor whiteColor];
self.searchBar.searchTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"検索する" attributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}];
self.searchBar.backgroundImage = [[UIImage alloc] init];
[self.view addSubview:self.searchBar];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.searchBar becomeFirstResponder];
}
@end
これで初期表示でUISearchBarでフォーカスを当てる事ができます。
3.まとめ
このように簡単に初期表示でフォーカス状態に設定することができます。
viewDidLoad内で、DispatchQueue.main.asyncを使って非同期にbecomeFirstResponderを設定することもできるようですが、今回はviewDidAppearの方法での実装でした。
これで、「ユーザー体験として検索画面に遷移した際、そのまま検索ワードを入力できる状態にしたい」などの要望に答える事ができます。まだまだ勉強途中ですので、ご指摘があった場合や追記必要であれば、また修正しようと思います。
4.参考記事・サイト
・Apple Developper - becomeFirstResponder()
・iPhoneアプリ開発虎の巻 UIResponder
・searchBarをfirstResponderとして設定できません