makoラボ

日常や勉強会や技術ネタ

選択されているUITableViewのセルにチェックマークをつける

f:id:mako_wis:20140307110219p:plain

上の画像のようにUITableViewを使って選択肢を表示するようなUIを使うことって案外あるんですよね。 その時にはほぼ必ずチェックした事を示すためにチェックマークを付けると思います。

今回は選択されているUITableViewのセルにチェックマークをつける方法を書いていきます。

UITableView内で保持している選択状態に応じてチェックマークをつけていきます。配列とかに選択状態とか持たせた方がええんじゃね?とか意見があるような気がしますが今回はあくまでUITableViewの機能を利用しての方法で進めていきます。

ちなみに以前書いたUITableViewのセルを選択した時にチェックマークをつける方法はこちら

選択されているセルにチェックマークをつける

今回はcellForRowAtIndexPath内で選択されているセルに対してチェックマークをつけます。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    
    cell.textLabel.text = @"hogehoge";

    // 一旦チェックマークを外す
    cell.accessoryType = UITableViewCellAccessoryNone;    

    // UITableViewから選択済みのインデックスを取り出す
    for (NSIndexPath *selectedindex in [tableView indexPathsForSelectedRows]) {
        // 選択済みかどうかチェック
        NSComparisonResult result = [selectedindex compare:indexpath];
        if (result == NSOrderedSame) {
           // 選択済みであればチェックマークを付ける
           cell.accessoryType = UITableViewCellAccessoryCheckmark;
           break;
        }
    }
    
    return cell;
}

対象のUITableViewの中から選択済みのインデックスを全件取得して、現在表示しようとしているセルのインデックスと比較して選択済みであればAccessoryでチェックマークをつけています。

UITableView自体に対象のインデックスが選択済みかどうかのメソッドくらいあっても良さそうなのですが、残念ながらなさそうなので泥臭い事をしてしまってます。

今回は説明のためにcellForRowAtIndexPath内にインデックスのチェック処理を書いちゃってますが、UITableViewにカテゴリでチェック処理メソッドを追加しとくもの良いかと思います。

@implementation UITableView (hoge)

- (BOOL)isSelectedIndexpath:(NSIndexPath *)indexpath {
    for (NSIndexPath *selectedindex in [self indexPathsForSelectedRows]) {
        NSComparisonResult result = [selectedindex compare:indexpath];
        if (result == NSOrderedSame) {
            // 選択済みであればtrue
            return true;
        }
    }
    // 未選択であればfalse
    return false;
}
@end

おわり

選択されているUITableViewのセルにチェックマークをつける方法を書いてみました。以前書いた選択した時にチェックマークをつける方法と合わせ技で選択状態を配列等に入れて保持しなくてもチェックマークを表示する事ができると思います。

表示する度にグルグルと処理を回してるので件数が多い場合とかはチェック状態の保持を考えたほうが良さそうですね。

そもそもデフォルトでチェックマークをチェック状態の表示で使えないのはどうなんでしょうかねえ・・・そこがハイライトから切り替えられればこんなことしなくて良いのに・・・

git commit時にコメントをSublime Textで書きたい

git commitをした時にSublime Textでコメントを書きたかったので、設定してみたものの動か無かったりしたのでハマった所のメモ。

sublコマンドの登録

公式にそれぞれやり方が書いてあるので参考に登録。

Sublime Text 3

http://www.sublimetext.com/docs/3/osx_command_line.html

ln -s "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" ~/bin/subl

Sublime Text 2

http://www.sublimetext.com/docs/2/osx_command_line.html

ln -s "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl" ~/bin/subl

gitのコミット時のエディタをsublにする

gitの設定を変更します。

git config --global core.editor "subl -w"

なぜかコミット出来ない

これでだいたいのブログとかで書かれている手順は終了なのですがなぜか自分の環境では以下のエラーが出てコミット出来ない・・・

subl -w: subl: command not found
error: There was a problem with the editor 'subl -w'.
Please supply the message using either -m or -F option.

コマンドが見つからない?ちゃんと設定しているはずなのに・・・ と困っていて調べてみると以下の記事が出てきました。 http://stackoverflow.com/questions/10892368/problems-using-subl-command-in-terminal-command-not-found-no-such-file-or どうやらrvm関連でそっちにもシンボリックリンクを貼っておかないとダメみたい。

rvmのbinにsublコマンドを登録

ということなのでrvm配下のbinにシンボリックリンクを貼ります。

ln -s "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" ~/.rvm/bin/subl

これで無事コミットできるようになりました。

UISearchBarが空の状態でも検索ボタンを有効にする

f:id:mako_wis:20140309195642p:plain

UISearchBarはデフォルトの設定では、入力が空の状態ではキーボードの検索ボタンが無効になってしまいます。 でも、入力が空の状態でもキーボードの検索ボタンを有効にしたい場合があると思います。

今回はコード側で設定する方法について書いていこうと思います。

実装方法

UISearchBarに検索ボタンの有効・無効の設定項目は無く、UISearchBarの中にあるUITextFieldに設定があります。ですのでまずはUISearchBarの中のUITextFieldを取得する必要があります。

その後、取得したUITextFieldに対して検索ボタンの有効・無効の切り替えプロパティの設定を行います。

以下に順番に実装方法を書いていきます。

UISearchBarの中のUITextFieldの取得

// UISearchBar内のUITextFieldを取得する
- (UITextField *)getTextFieldFromView:(UIView *)view {
    for (UIView *subview in view.subviews) {
        if ([subview isKindOfClass:[UITextField class]]) {
            return (UITextField *)subview;
        } else {
            UITextField *textField = [self getTextFieldFromView:subview];
            if (textField) {
                return textField;
            }
        }
    }
    return nil;
}

上記のメソッドの引数にUISearchBarを渡して、UITextFieldを取得します。再帰構造にしているのはUISarchBarの直下のSubViewより深い階層にUITextFieldが設定されているためです。

プロパティの設定

// UISeachBar(self.searchBar)の検索ボタンを常に有効にする
[self getTextFieldFromView:self.searchBar].enablesReturnKeyAutomatically = NO;

上記のように取得したUITextFieldのリターンキーの自動有効・無効設定を切りに指定します。

おわり

ほんとはStoryboard上の設定ですべてを終わらせたいのですが、無いようなので今回のようなコード側での実装を行っています(あるよお前の目は節穴か!とい場合は是非教えて下さい。)

また、iOS6以前だとUISearchBar直下のSubViewの階層にUITextFieldがあったようなのですが、iOS7からは更に深い階層に潜っているようです。。。やっぱりStoryboardで設定したい。。。そもそもそういう使い方が良くないのかな。

UITableViewのセルを選択した時にチェックマークをつける

f:id:mako_wis:20140307110219p:plain

上の画像のようにUITableViewを使って選択肢を表示するようなUIを使うことって案外あるんですよね。 その時にはほぼ必ずチェックした事を示すためにチェックマークを付けると思います。

今回はチェックマークを選択された時にをつけたりはずしたりする方法を書いていこうと思います。

UITableViewの複数選択と単一選択

ちょっと本題に入る前にUITableViewの選択モードについて説明を簡単にしておきます。

UITableViewでは複数選択モードと単一選択モードがあります。セルを複数選択したり、一つだけ選択出来るようにしたり出来ます。

設定の切り替えは簡単でStoryboard上であればUITableViewのプロパティの「Selection」で「Multiple Selection」または「Single Selection」をそれぞれ指定する事で切り替えれます。ちなみにコード側で設定する場合は以下のコードで切り替えれます。

// YESで複数選択・NOで単一選択
self.conditionTableView.allowsMultipleSelection = YES;

選択されたときにチェックマークをつける

// セルが選択された時に呼び出される
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // 選択されたセルを取得
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    // セルのアクセサリにチェックマークを指定
    cell.accessoryType = UITableViewCellAccessoryCheckmark;
}

セルが選択された時にチェックマーク付ければ良いので上記のようなコードでチェックマークを付ける事が出来ます。

選択がはずれた時にチェックマークを外す

// セルの選択がはずれた時に呼び出される
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
    // 選択がはずれたセルを取得
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    // セルのアクセサリを解除する(チェックマークを外す)
    cell.accessoryType = UITableViewCellAccessoryNone;
}

選択がはずれた場合もその時のイベントで呼び出されるメソッドでチェックマークを外してやれば良いです。 選択したセルを再度タップして選択を解除した時はもちろん、単一選択の時に選択セルが変わった時にも外れる側のセルのインデックスが渡ってくるのでちゃんと解除出来ます。

おわり

今回はコードでチェックマークをつけたり外したりする方法を書いてみました。2つのUITableViewのイベントで付け替えをしてあげるだけで簡単にチェックマークを付け外しできますね。

Storyboard上の設定でUILabelを動的に変化させる

f:id:mako_wis:20140301224115p:plain

上の画像のようにUILabelのサイズや行数を動的に変化させたいシーンは多々あると思います。プログラムで裏側からゴリゴリっとサイズを変えるのも良いのですがStoryboard側の設定だけで出来たのでメモ代わりに書いてみる。

オートレイアウトを設定する

f:id:mako_wis:20140301224300p:plain

今回は単純にするために文字を表示するためのUILabelと「へぇ!」を増やすためのUIButtonだけを置いてます。

UILabelのオートレイアウトの設定

今回の例では下にラベルをのばそうと思うので、上と左右の余白を設定しています。ポイントはUIlabelの高さに伸びる余地がある設定をしておくということです。

下に伸ばす範囲も指定したい場合は下にも余白の下限値の設定を追加すると良いです。

プロパティの設定をする

f:id:mako_wis:20140301230441p:plain

ポイントはUILabelに以下の2つ設定をおこなうこと

  • Linesを0(無制限)または上限の行数に設定する
  • Line Breaksを「Character Wrap」または「Word Wrap」に設定する

これでUILabelのサイズを動的に変化させたい場合の設定が完了です。

動的に伸ばす

これだけだとUILabelのサイズを変化させようが無いのでボタンを押した時に文字をUILabelに追加するようにします。

// へぇボタンが押された時のアクション
- (IBAction)hee:(id)sender {
    // UILabelに「へぇ」を追加します。
    self.heeLabel.text = [self.heeLabel.text stringByAppendingString:@"へぇ!"];
}

実行してみるとへぇが1行に収まらなくなったら改行して次の行に表示されると思います。 今回プログラムで弄ってるのはここだけです。

まとめ

プログラム側でゴリゴリとUILabelのサイズを計算して適用してみたいな事をしなくて良いのはいいですね。といいつつも結局、伸ばせる上限が決まってる場合は文字サイズを小さくしたりゴニョゴニョプログラム側でやらないといけないのですが・・・何かStoryboard側だけで完結するいい方法はないものか。

プログラム側からUITabBarControllerを切り替えて、さらに画面遷移させたい時

f:id:mako_wis:20140228000303p:plain

今回やりたいこと

FirstViewの上に置いてある「Second → Third」ボタンを押すと、SecondViewのあるタブに切り替わってなおかつThirdViewに切り替わる。

実装する

Second → Third」ボタンプログラム側でやらないといけないことは大きく2つ

  • FirstViewからSecondViewのタブへの切替
  • SecondViewからThirdViewへの遷移

こちらを順番に行えば実現出来るはずということで、以下がそのソースです。

// ① 2番目のタブのViewControllerを取得する
UINavigationController *vc = self.tabBarController.viewControllers[1];
// ② 2番目のタブを選択済みにする
self.tabBarController.selectedViewController = vc;
// ③ UINavigationControllerに追加済みのViewを一旦取り除く
[vc popToRootViewControllerAnimated:NO];
// ④ SecondViewの画面遷移処理を呼び出す
[vc.viewControllers[0] performSegueWithIdentifier:@"ThirdViewを呼び出す" sender:nil];

① 2番目のタブのViewControllerを取得する

tabBarController内に設定されているviewControllerは今回の例だと「FirstView」と「SecondView」の2つ。遷移したい先は「SecondView」なのでそちらを取り出す。

今回は、「SecondView」はUINavigationControllerを使用しているのでそちらで取得する。「SecondView」に設定されているViewControllerじゃないので注意!UINavigationControllerを使用していなければそのまま取れます。

② 2番目のタブを選択済みにする

①で取得したViewを選択済みにします。ここはそのままなので説明は割愛。

③ UINavigationControllerに追加済みのViewを一旦取り除く

今回はpushで画面遷移するので、以前にpushされていると画面が複数呼び出される事になります。なので画面遷移を呼び出す前に「SecondView」で以前に画面遷移したものを掃除しておきます。

④ SecondViewの画面遷移処理を呼び出す

まずは、 vc.viewControllers[0] で「SecondView」のViewControllerを取得します。UINavigationControllerのrootに設定されいるので0番目を取得すればよいです。

その後、performSegueWithIdentifierで「ThirdView」への画面遷移処理を呼び出しています。

まとめ

今回の例ですと、遷移させたいViewがナビゲーション形式だったのでpushで画面遷移させてみました。他の画面遷移の方法でも同じようなやり方でいけると思います。

まぁそもそもこんな画面遷移をしたいことが稀だと思いますが・・・

Macの容量不足に悩まされた話

最近、Macの容量不足に悩まされていましたが解決したので同じようにしてる人の参考になれば。

状況

ある日からMacの容量不足警告が出るようになってしまっていました。

ソフトを入れすぎたか?と思い最近使ってないIDE等を削除してみたのですがしばらくするとまた容量エラー。

思いつく限りの必要ないファイルを消すのですがしばらくすると残り3GBあたりになってしまい、容量不足に悩まされていました。

解決方法

Macの再起動をする

解決方法は単純にこれだけでした。

僕の場合は使わない時はスリープモードにしていて、最後に電源を切ったのはいつだろうというくらい。
これだけで7Gくらい容量が増えましたとさ。

やっぱりたまには完全に休ませてあげることが大切ですね。