NewImage

UISearchBarまとめ | SpiriteK Blog より

iOSアプリの検索バーUIである、UISearchBarですがあまり機能的なカスタマイズは用意されていないようで、
横に表示できるボタンもCacelButtonだけとなっています。 

キャンセルだけではなく、入力した内容をそのまま使うなど、
補完と入力の両方を実現したい場合には、入力内容をそのまま使うボタンをCancelの位置におくようなUIが欲しくなると思います。

今回は、UISearchBarで補完候補を表示できる jcoleman/JCAutocompletingSearch · GitHub ライブラリのUISearchBarの見た目をカスタマイズしてみたいと思います。

サンプルのプロジェクトは azu/SearchBarCustomize · GitHub においてあります。

今時のプロジェクトならCocoaPodsを使ってライブラリ管理していると思うので、 JCAutocompletingSearchをcocoapodsでインストールします。
(cocoapodsを使ってないなら  JCAutocompletingSearch のファイルをそのままプロジェクトに入れればいいと思います)

platform :ios, '5.0'

pod 'JCAutocompletingSearch'

で `$ pod install` しておきます。(開くプロジェクトはSearchBarCustomize.xcworkspaceの方)

JCAutocompletingSearchのデフォルトで用意されている検索UIもそのまま検索バーとしてしか使えないようになっています。

IOSシミュレータ  iPhone  Retina 3 5 inch iOS 6 1  10B141 2013 02 18 11 11 19

この検索画面のJCAutocompletingSearchViewControllerのサブクラスを作って、補完と入力ができるUIを作ってみたいと思います。

作りたいUIは以下のような感じで、Cancelの位置にそのまま入力を使う決定ボタン、キャンセルを入力補完画面を閉じるボタンという感じにしたいと思います。

IOSシミュレータ  iPhone  Retina 3 5 inch iOS 6 1  10B141 2013 02 18 11 33 50

これを作るためには実際にサンプルを開いて見るとわかるのですが、UIToolBarの中にUIBarButtonのViewとして、UISearchBarを入れて、
同じように決定ボタンもUIBarButtonとして配置します。 

SearchBarCustomize xcworkspace  AZAutCompletingViewController storyboard 2013 02 18 11 36 52

recursiveDescription でダンプしてみると以下の様な構造ですね。

<UIToolbar: 0x917b690; frame = (0 44; 320 44); autoresize = W+BM; layer = <CALayer: 0x917b770>>
   | <_UIToolbarBackground: 0x917bf90; frame = (0 0; 320 44); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x917c040>>
   | <UIImageView: 0x917c4c0; frame = (0 -3; 320 3); opaque = NO; autoresize = W+BM; userInteractionEnabled = NO; layer = <CALayer: 0x917c520>>
   | <UIView: 0x917bae0; frame = (12 0; 247 44); autoresize = RM; layer = <CALayer: 0x917bb40>>
   |    | <AZCustomSearchBar: 0x9176710; baseClass = UISearchBar; frame = (0 0; 247 44); text = ''; autoresize = W+BM; layer = <CALayer: 0x91767c0>>
   |    |    | <UISearchBarBackground: 0x9177e80; frame = (0 0; 247 44); userInteractionEnabled = NO; layer = <CALayer: 0x9177f40>>
   |    |    | <UISearchBarTextField: 0x9178450; frame = (0 0; 0 0); text = ''; clipsToBounds = YES; opaque = NO; gestureRecognizers = <NSArray: 0x9178d60>; layer = <CALayer: 0x9178600>>
   | <UIToolbarTextButton: 0x917c7f0; frame = (270 0; 44 44); opaque = NO; layer = <CALayer: 0x917d9e0>>
   |    | <UIButton: 0x917c910; frame = (0 8; 44 30); opaque = NO; layer = <CALayer: 0x917c9d0>>
   |    |    | <UIImageView: 0x917df20; frame = (0 0; 44 30); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x917df80>>
   |    |    | <UIButtonLabel: 0x917cc20; frame = (10 7; 24 15); text = '決定'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x917cd10>>

ただし、上記のスクリーンショットでもわかるように、UIToolbarの背景と、UISearchBarの背景が重なって一部が出っ張って見えてしまいます。
これの見た目を治すために、 UISearchBarの背景画像を透明にしてしまうのが簡単な方法です。

サンプルでは以下のように透明の画像を作りUIAppearanceを使って背景画像に適応しています。
(範囲をこのViewControllerだけに限定するために、appearanceWhenContainedInを使います) 

UIImage *(^createImageFromUIColor)(UIColor *) = ^(UIColor *color) {
    CGRect rect = CGRectMake(0, 0, 1, 1);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef contextRef = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(contextRef, [color CGColor]);
    CGContextFillRect(contextRef, rect);
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
};

- (void)awakeFromNib {
    [super awakeFromNib];
    // 背景画像を透明にする
    [[UISearchBar appearanceWhenContainedIn:[AZAutCompletingViewController class], nil]
            setBackgroundImage:createImageFromUIColor([UIColor clearColor])];
    // 検索アイコンを変更(透明にする)
    [[UISearchBar appearanceWhenContainedIn:[AZAutCompletingViewController class], nil]
            setImage:createImageFromUIColor([UIColor clearColor]) forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
}

 

利用できる、UIAppearanceはUISearchBar Class Referenceにまとまっています。
サブクラスで直接subViewsのプロパティをいじって変更することもできますが、将来的な変更などで壊れる可能性があるので、UIAppearanceを使った見た目の変更をしたほうがいいです。

これで、以下の様な見た目を作ることができます。
決定ボタンやキャンセルボタンは通常のUIBarButtonなので、普通にイベントをつけたりすれば自由に扱えるようになるはずです。
(サンプルではJCAutocompletingSearchViewControllerDelegateにsubmitのdelegateを追加して決定ボタンの挙動を作ってあります) 

IOSシミュレータ  iPhone  Retina 3 5 inch iOS 6 1  10B141 2013 02 18 11 33 50

これで、UISearchBarに決定ボタンを持たすような見た目のものが出来上がりました。

今回利用したJCAutocompletingSearchIMOAutocompletionViewControllerと違い非同期での補完候補を絞込みができるため、
大量の補完単語を用意した場合でも問題無く動きます。
また日本語等の入力も問題なく動作すると思います。

今回のように既存のライブラリの機能は欲しいけど見た目や機能を少し付け加えたいと思った時に、こういうサブクラスなどで機能を引き継いで
見た目や機能を追加するアプローチは結構重要だと思います。
cocoapodsを使ってインストールしたライブラリに対して直接ライブラリをいじるのは行儀が良くないので、サブクラスだとライブラリ本体と分離して実装することができるため、色々使い所が出てくると思います。 

Post Navigation