mixi-inc / iOSTraining-TODO-App

iOS Training で使う教材用TODOアプリのリポジトリです
Apache License 2.0
16 stars 37 forks source link

TODOリストを表示する #1

Open ginrou opened 9 years ago

ginrou commented 9 years ago

TODOアプリを作ってみようシリーズの第一回目の演習課題のTODOです

内容

UITableViewを利用して、TODOリストを表示します。TODOはコード内にハードコードしたものを用いて、追加などは行いません。

目的

UITableViewの使い方を理解する。以下のクラスの関係や基本的な使い方を学習することを目的としています。

また UITableViewCellをサブクラス化してカスタマイズも行います

アプリの仕様

以下のTODOをUITableViewを利用して表示します。 長いTODOも折り返して、全文が表示されるようにしてください。 (一部TODOらしくないTODOもあるのはそのサンプルです)

NSArray *todo = @[@"牛乳を買ってくる",
                  @"ビールを飲む",
                  @"家賃の振り込み",
                  @"洗剤を買い足す",
                  @"Macのアップデート",
                  @"ルンバの充電",
                  @"結婚式の招待状に返信する",
                  @"犬の散歩",
                  @"雨ニモマケズ 風ニモマケズ 雪ニモ夏ノ暑サニモマケヌ 丈夫ナカラダヲモチ 慾ハナク 決シテ瞋ラズ イツモシヅカニワラッテヰル 一日ニ玄米四合ト 味噌ト少シノ野菜ヲタベ アラユルコトヲ ジブンヲカンジョウニ入レズニ ヨクミキキシワカリ ソシテワスレズ",
                  @"ビールを飲む"
                  ];

またTODOを表示するセルは以下のレギュレーションに従ってください. 2015-03-25 1 38 24 pm

動作イメージ

2015-03-19 9 11 07 pm

実装のステップ

tableViewを表示する 6974b40055e868ecd72068cfb39440c61a9fb5bd

UITableViewをメインのViewControllerの上に配置し、Autolayoutを設定します。 Autolayoutのpinの仕方は任意ですが、上下左右のマージンを0にするのがベターです。 さらにViewControllerのプロパティとして追加します。

セルを表示する cac9ebf3ef3cdd98599f5c133d643a69cb0c370e

TodoTableViewCellという名前で新しいクラスを追加(xibも同時に作る) カスタムセルの実装

※ iOS8以降の場合はAutolayoutを正しく設定することで自動的に高さを計算してくれる。iOS7以前もサポートする場合は、この高さの計算を行うメソッドを実装する必要があります。

ViewControllerがUITableViewDelegateに準拠するようにして、tableview.delegate = selfにする

プロパティに高さ計算用のセル(offscreenCell)を追加
@interface 
// 中略
@property (strong, nonatomic) TodoTableViewCell *offscreenCell;
// 中略
@end

// viewDidLoadなどの中で
self.offscreenCell = [nib instantiateWithOwner:nil options:nil][0];
offscreenCellのサイズを決定

tableViewがレイアウトされたタイミング(viewDidLayoutSubviews)でセルの横幅が決まる。 ここでoffscreenCellのサイズを決定する。(xibのサイズのままだと画面サイズが変わったときに対応できない)

この時ラベルに preferredMaxLayoutWidth を設定する。これをしないと複数行の表示が正しく行われない

高さを計算する

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath で各セルの高さを計算して返す

手順としては

start ※ Main.storyboard の initial view controller を指定し忘れたので、指定してください :sweat:

ここまでの完成品のブランチ

show-todo

ginrou commented 9 years ago

Autolayoutのレンダリングを用いない場合は、以下のように表示するコンテンツのサイズを逐一計算します。

NSString *todo = self.todo[indexPath.row];
CGFloat maxWidth = CGRectGetWidth(tableView.bounds) - 8 - 8; // 8はラベルとセルの間の左右のマージン
CGSize maxSize = CGSizeMake(maxWidth, CGFLOAT_MAX);
NSDictionary *attribute = @{NSFontAttributeName: [UIFont systemFontOfSize:17.0]};
CGRect rect = [todo boundingRectWithSize:maxSize
                                 options:NSStringDrawingUsesLineFragmentOrigin
                              attributes:attribute
                                 context:nil];

CGFloat todoHeight = ceil(CGRectGetHeight(rect)); // rectの高さは小数点で返り、切り捨てると描画されない
CGFloat contentViewHeight = todoHeight + 8 + 8; // 8 はラベルとセルの間の上下のマージン
return contentViewHeight + 1; // contentViewとcellの間に1pxのマージンがあるので追加