Objective-Cでtableviewをカスタムセルで作ってスワイプで削除してみた
20150411修正:「9.1.ストーリーボードのTableView紐付け」の項目を削除、githubも修正
20150404追記:お勧めできない項目追加
20150327追記:ページ最下に関連記事の項目追記
同日修正:紛らわしかったxibのファイル名を変えて、差し替え版を上げました。
今回、参考にした記事はこの辺。dev.classmethod.jp
hetyo-pg.blog.jp
本当はSWTableViewCellというアドオン拡張的なものを使うと楽らしいのだが、ここはswiftを見越してできるだけ拡張せずにやってみた。機能テスト的な感じでいじった。
http://pickslife.me/cocoa-pods-search
既にswiftでセルのスライドをテストしてる人もいるというね。さすがはてなーですわ。
AutoLayoutでスワイプできるUITableViewCellを実装する - tomoyaonishiのブログ
ものはここに上げた。
csny/swipe-customcell · GitHub
今回の作りはお勧めできない
こんな記事作っといてなんだけど、実はxibを使う方法はお勧めできない。わざわざxibに分ける理由が見つからないのだ。カスタマイズといいセル高の自動調整とい、StoryBoard上でできないことはないと思っていい。やるとしたら推奨構成の形がいいと思う。
完成画像
右スワイプをswipe gesture recognizerでお手軽に実装し、NSLogだけしてみる。データの入ったセルではindexpath.rowを、入っていないセルではスワイプ無効という表示を出した。
左スワイプをすると、editActionsForRowAtIndexPath:によりボタンっぽいものが出る。iOS8かららしいが、ネット上の噂によるとiOS7でも出てくるらしい。
削除機能のみ実装した。
作成手順
1.xcodeの初期設定
SingleViewで始める。名前や保存場所は適当に。
2.ストーリーボードにある既存のviewcontrollerとクラスファイルViewController.mと.hを削除
3.ストーリーボードのオブジェクト及びクラスファイルを新規作成
ストーリーボードの何もない空間にNavigationControllerを追加。
NewFileからクラスファイルを新規作成し、CocoaTouchClass→UITableViewControllerサブクラスの「RootViewController」というクラス名のファイルを作る。
4.xibファイルの新規作成
GUIでセルをカスタマイズしたいので、NewFileからUser Interface→Emptyを選択。
ここでは、「XibCustomCell.xib」という名前にしておく。
5.xibへオブジェクト及びクラスファイルを新規作成
作成した空のxib内にTableViewCellを新規追加。適当にLabelやボタンなどを配置。今回はラベルのみ。
NewFileからCocoaTouchClass→UITableViewCellサブクラスの「CustomTableViewCell」というクラス名のファイルを作る。
6.「NavigationController」を最初に起動するオブジェクトとして設定
ストーリーボードの「NavigationController」のAttributes inspectorの「is Initial View Controller」にチェックを入れる。
7.オブジェクトとクラスファイルの紐付け
7.1.ストーリーボード
3.で作ったクラスファイル名「RootViewController」をストーリーボードでRootViewControllerのClassに貼り付けて、リターン。Classの項目は、Identity inspectorにある。
7.2.xib
4.で作ったクラスファイル名「CustomTableViewCell」を、xib上でTableViewCellの一番上位にあるオブジェクトのClassに貼り付けて、リターン。
Classの項目は、Identity inspectorにある。
8.セルのオブジェクト設定
8.1.ストーリーボードのTableViewの付属のセルを削除
ストーリーボードのRootViewController内のTableViewを選択し、Prototype Cellsを0に変更して、ContentのDynamicやselectionのSingleを確認。
8.2.xibのカスタマイズセルにIdentifierを設定
TableViewCellの一番上位にあるオブジェクトのidに「Cell」を入力して、リターン。
9.オブジェクトの紐付け
9.1.xibのラベル位置調整とセルの幅決定
xibを開き、5.でカスタムセルに貼り付けたラベルやボタンの位置を修正しつつ、セルの幅を調整し決定します。ここでは「60.0」にしました。
TableViewCellを選択、Size inspectorを開くとRow Heightが60.0に変わり、Customにチェックが入っているはずです。セルを掴みながら幅を動かすと、ここの値も随時変わるのが見られるでしょう。あとで使うのでこの数値を覚えておきます。
9.2.xibのラベル紐付け
xibの画面で、Assistant editorで右側に「CustomTableViewCell.h」を開き、5.でカスタムセルに貼り付けたラベルやボタン全てについて、@interfaceの下の行あたりにControl+ドラッグ&ドロップ。
Outletのまま、適当に名前をつける。今回使う分として「labelDate」のみキッチリ名前を付ける。ボタンなどActionが必要であればActionで配置。
10.右スワイプ機能の準備
Swipe Gesture RecognizerをRootViewControllerへドロップ。
Swipe Gesture RecognizerのConnections inspectorを開き、Referencing Outlet CollectionsからRootViewControllerのTableViewへドロップしてgestureRecognizersを選択。画像は既に全部実施した後の状態なので、最終的にはこのようなコネクションになる。
Swipe Gesture RecognizerのAttribute inspectorを開き、swipeをRIGHTに設定。これで右向きのスワイプしか受け付けない。
Assistant editorで右側に「RootViewController.h」を開き、Swipe Gesture Recognizerから@interfaceの下の行あたりへControl+ドラッグ&ドロップ。
Actionを選択して、「swipedRight」と名付ける。
11.カスタムセルの幅を通知する準備
9.2.でTableViewCellの幅として決めた「60.0」をここで使います。
以下のファイルへ以下のコードを入力。
「+」でメソッドを定義しているのがミソです。これをクラスメソッドと言い、「ー」で宣言するインスタンスメソッドとは呼び出し方が変わります。詳しくはクラス変数、インスタンス変数でググるといいかも。
CustomTableViewCell.h
// クラスメソッド宣言 + (CGFloat)rowHeight;
CustomTableViewCell.m
// セルの高さのクラスメソッド + (CGFloat)rowHeight { return 60.0f; }
12.RootViewControllerへCustomTableViewCellのインポート
「RootViewController.h」の冒頭に以下を追記。
#import "CustomTableViewCell.h" |
13.インスタンス変数を宣言しておく
配列を入れて使い回すために、インスタンス変数を1つ作っておく。「RootViewController.h」の@interfaceの下あたりに以下を追記。今回は配列の要素を削除する操作を入れたいので、NSMutableArrayで宣言。
// property*iphoneModelsは手入力、インスタンス変数iphoneModelsを準備
@property NSMutableArray *iphoneModels;
貼り付け後の「RootViewController.h」はこうなっているはず。
swipe-customcell/RootViewController.h at master · csny/swipe-customcell · GitHub
14.「RootViewController.m」へコード入力
以下、不明なところはコードを見てもらった方が早いかも。
swipe-customcell/RootViewController.m at master · csny/swipe-customcell · GitHub
14.1.xibファイルをコードへ紐付け
@implementationの上の行あたりに以下のコードを入れることで、xibファイルをstatic指定子でクラス変数として宣言&初期化。xibを呼び出す処理は次の項目で説明する。
/* サムネイル・デバイス名・セル番号で構成されたカスタムセルのID "XibCustomCell.xib"ファイルとの紐付け */ static NSString * const TableViewCustomCellIdentifier = @"XibCustomCell";
14.2.viewDidLoad編集
配列の初期化をして、カスタマイズしたxibのセルをtableViewに呼び出す処理。
- (void)viewDidLoad { [super viewDidLoad]; // テーブルに表示したい配列を用意 _iphoneModels = [NSMutableArray arrayWithObjects:@"iPhone 4", @"iPhone 4S", @"iPhone 5", @"iPhone 5c", @"iPhone 5s", @"iPhone 6c", @"iPhone 6 plus", nil]; // カスタマイズしたセルをテーブルビューにセット UINib *nib = [UINib nibWithNibName:TableViewCustomCellIdentifier bundle:nil]; [self.tableView registerNib:nib forCellReuseIdentifier:@"Cell"]; }
14.3.カスタムセルの高さをtableviewに通知
heightForRowAtIndexPath:メソッドを作成。普段あんまり使わんね。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [CustomTableViewCell rowHeight]; }
14.4.tableviewに配列を書き出す
必須の2つのメソッドを丸ごと追記。cellForRowAtIndexPath:の方はファイル内に既に記載されてるはずなので、書き換えても可。普段と違うのは、CustomTableViewCellをインスタンス化するところか。
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { //省略 } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //省略 }
14.5.左スワイプの設定
以下のメソッドを追記するだけ。左スワイプによるeditボタンなどは、以下の2つのメソッドをコードで書くだけで簡単に実装できる。
//UITableViewDelegateに追加された編集・削除メソッドiOS8から - (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath { //省略 } // iOS7で必須。iOS8では不要。 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { //省略 }
14.6.右スワイプの処理
10.で既に設定しておいたswipeアクション時のメソッド内に処理を記載する。
// 右スワイプ時の動作定義 - (IBAction)swipedRight:(id)sender { //省略 }
できあがり。
関連記事
カスタマイズセルの高さを自動調整してみたけど、まぁうまくいかんね。
cocoaのセルの高さ自動調整機能は未完成な気がしたけど、そんなこともなかったぜ - せでぃのブログ