Pinterest風の表示にしたいと思って色々ライブラリをあさって見たところ、PSCollectionViewという便利そうなライブラリを発見した。
iOS6以上であれば、UICollectionViewというそのものズバリのものがあるようだ。
heightForRowAtIndexメソッドの戻り値に個々の高さを指定してやることで、高さを個別に設定することも可能だった。
戻り値にCGFloatで値を返すのだけど、小数部の桁数が増えると誤差が生じて、上手くタップを認識しなくなることがあるみたい。
調べてみると、セルの大きさをNSStringFromCGRectでNSString化して管理しているようだ。
// Calculate index to rect mapping self.colWidth = floorf((self.width - kMargin * (self.numCols + 1)) / self.numCols); for (NSInteger i = 0; i < numViews; i++) { NSString *key = PSCollectionKeyForIndex(i); // Find the shortest column NSInteger col = 0; CGFloat minHeight = [[colOffsets objectAtIndex:col] floatValue]; for (int i = 1; i < [colOffsets count]; i++) { CGFloat colHeight = [[colOffsets objectAtIndex:i] floatValue]; if (colHeight < minHeight) { col = i; minHeight = colHeight; } } CGFloat left = kMargin + (col * kMargin) + (col * self.colWidth); CGFloat top = [[colOffsets objectAtIndex:col] floatValue]; CGFloat colHeight = [self.collectionViewDataSource collectionView:self heightForRowAtIndex:i]; CGRect viewRect = CGRectMake(left, top, self.colWidth, colHeight); // Add to index rect map [self.indexToRectMap setObject:NSStringFromCGRect(viewRect) forKey:key]; // Update the last height offset for this column CGFloat heightOffset = colHeight > 0 ? top + colHeight + kMargin : top; [colOffsets replaceObjectAtIndex:col withObject:[NSNumber numberWithFloat:heightOffset]]; }
セルのタップは、UITapGestureRecognizerを使っているようで、shouldReceiveTouchメソッドで、どのセルがタップされたか判定して、didSelectメソッドが呼びされるようだ。
heightForRowAtIndexで返される高さの小数部が増えてくると、下記のrectStringと値が一致しなくなり、タップを認識しなくなる。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if (![gestureRecognizer isMemberOfClass:[PSCollectionViewTapGestureRecognizer class]]) return YES; NSString *rectString = NSStringFromCGRect(gestureRecognizer.view.frame); NSArray *matchingKeys = [self.indexToRectMap allKeysForObject:rectString]; NSString *key = [matchingKeys lastObject]; if ([touch.view isMemberOfClass:[[self.visibleViews objectForKey:key] class]]) { return YES; } else { return NO; } }
解決方法は簡単で、heightForRowAtIndexで値を返す際に、小数部が増えないようにしたり、丸めてやればいい。
- (CGFloat)collectionView:(PSCollectionView *)collectionView heightForRowAtIndex:(NSInteger)index { return floorf(100.123456789f); }
投稿しようとして気づいたのだけど、Objective-C(Cocoa)ネタ書いたの初めてだった。
iPhoneアプリを作っていると、ブログに書くようなネタがなかなか見つからない…
ちょっとググれば情報がたくさん見つかるし書くまでもないかなーとか思っちゃうせいだろうか。