iOS5 + for iPadには非常に奇妙な行間隔のバグがあります。各UITableViewCellがUITextViewを含むカスタムタイプであるUITableViewを使用している場合、アラビア語などの非AZ言語のテキストの複数行を含むセルは次のようにデキューされます。キーボードがモーダルビューで開かれた後の間違った行の高さ。
注:これはiOSのバグのようですが、アプリがiOS5+のバージョンと下位互換性を持つようにするための回避策を探しています。
バグを再現する方法は次のとおりです。
(1)(a)ストーリーボードで、UIToolbarとUITableViewがあるUIViewControllerを作成します(ただし、独自のサブクラスを作成します)。UITableViewで、識別子が「CellIdentifier」の「Dynamic Prototype」セルを1つ作成し、タグが「1」ですべてのAutoResizeプロパティがオンのUITextViewを作成します(セルのフルサイズを使用します)。
(1)(b)ストーリーボードで、UIToolbarを「toolbar」変数にリンクし、UITableViewを「mainTableView」変数にリンクします。UITableViewの「dataSource」と「delegate」をUIViewControllerに設定し、UITextViewの「delegate」をUIViewControllerに設定します。
(1)(c) UIViewControllerサブクラスに次のコードを追加します。
MyViewController.h:
#import <UIKit/UIKit.h>
@interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UITextViewDelegate>
// the toolbar at the top of the screen
@property (weak, nonatomic) IBOutlet UIToolbar *mainToolbar;
// the table view taking up the screen
@property (weak, nonatomic) IBOutlet UITableView *mainTableView;
@end
MyViewController.m:
#import "MyViewController.h"
@interface MyViewController ()
// array to store text for cells
@property (strong, nonatomic) NSMutableArray *data;
// the number of rows to show
@property (nonatomic) NSInteger numberOfRowsToShow;
// when toolbar buttons are pressed
- (void)showModalViewButtonPressed;
- (void)redrawVisibleCellsButtonPressed;
- (void)insertButtonPressed;
- (void)deleteButtonPressed;
@end
@implementation MyViewController
@synthesize mainTableView;
@synthesize mainToolbar;
@synthesize data;
@synthesize numberOfRowsToShow;
- (void)viewDidLoad {
[super viewDidLoad];
// create data array for cell contents
self.data = [[NSMutableArray alloc] initWithObjects:
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
@"سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام سلام",
nil];
self.numberOfRowsToShow = 0;
// set toolbar buttons
[self.mainToolbar setItems:[NSArray arrayWithObjects:
[[UIBarButtonItem alloc] initWithTitle:@"Show Modal View" style:UIBarButtonItemStyleBordered target:self action:@selector(showModalViewButtonPressed)],
[[UIBarButtonItem alloc] initWithTitle:@"Redraw Visible Cells" style:UIBarButtonItemStyleBordered target:self action:@selector(redrawVisibleCellsButtonPressed)],
[[UIBarButtonItem alloc] initWithTitle:@"Insert" style:UIBarButtonItemStyleBordered target:self action:@selector(insertButtonPressed)],
[[UIBarButtonItem alloc] initWithTitle:@"Delete" style:UIBarButtonItemStyleBordered target:self action:@selector(deleteButtonPressed)],
nil] animated:YES];
}
- (void)viewDidUnload {
[super viewDidUnload];
// clean up
self.data = nil;
self.mainTableView = nil;
self.mainToolbar = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// only one section
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// return the number of items in the data array
return self.numberOfRowsToShow;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// dequeue cell from storyboard
UITableViewCell *cell = [self.mainTableView dequeueReusableCellWithIdentifier:@"CellIdentifier"];
// get text view
UITextView *cellText = (UITextView *)[cell viewWithTag:1];
// set text using data array
cellText.text = [self.data objectAtIndex:indexPath.row];
// set large font
cellText.font = [UIFont systemFontOfSize:20.0f];
// set background color based on whether the line spacing is correct
if (cellText.contentSize.height == 100.0f) {
// correct height sets a green background
cellText.backgroundColor = [UIColor greenColor];
} else if (cellText.contentSize.height == 88.0f) {
// wrong height sets a red background
cellText.backgroundColor = [UIColor redColor];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// return constant height
return 150.0f;
}
- (void)textViewDidChange:(UITextView *)textView {
// get parent cell for text view
UITableViewCell *parentCell = (UITableViewCell *)textView.superview.superview;
// get parent cell indent path
NSIndexPath *parentIndexPath = [self.mainTableView indexPathForCell:parentCell];
// save new text to data array
[self.data replaceObjectAtIndex:parentIndexPath.row withObject:textView.text];
}
#pragma mark - Other methods
- (void)showModalViewButtonPressed {
// segue to modal view
[self performSegueWithIdentifier:@"modalSegue" sender:self];
}
- (void)redrawVisibleCellsButtonPressed {
// reload all visible cells in the table view
[self.mainTableView reloadRowsAtIndexPaths:[self.mainTableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
}
- (void)insertButtonPressed {
// insert a cell in the table view (increments number of rows to show first)
[self.mainTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:self.numberOfRowsToShow++ inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
}
- (void)deleteButtonPressed {
// delete a cell in the table view (decrements number of rows to show first)
[self.mainTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:--self.numberOfRowsToShow inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
}
@end
(2)(a)ストーリーボードで、UINavigationControllerとUIViewControllerを作成し(サブクラス化も)、そのプロパティでUIViewControllerをUINavigationControllerのルートビューコントローラーとして設定します。「完了」ボタンのあるUIToolbarをUIViewControllerとUITextFieldに追加します。UINavigationControllerに「modalSegue」と呼ばれるメインビューコントローラーにモーダルセグエを追加します。
(2)(b)ストーリーボードで、[完了]ボタンをIBActionの[closeButtonPressed]にリンクします。
(2)(c)次のコードをモーダルUIViewControllerに追加します。
MyModalViewController.h:
#import <UIKit/UIKit.h>
@interface MyModalViewController : UIViewController
- (IBAction)closeButtonPressed:(id)sender;
@end
MyModalViewController.m:
#import "MyModalViewController.h"
@implementation MyModalViewController
- (IBAction)closeButtonPressed:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
@end
テスト:
(1)アプリケーションを実行します。画面が読み込まれると、UITableViewにはコンテンツがありません。
(2)ツールバーの「挿入」ボタンを数回タップします。2つのセルが緑色で追加されます。ここでの行間隔は、アラビア語と英語のみを含む行の場合、4ピクセル高くなっていることに注意してください(セル内のすべて英語のテキストでこれを試すことができます)。この段階で、アプリの正しい動作を確認できます。
(3)「モーダルビューを表示」ボタンをタップし、モーダルビューが開いたら、UITextField内をタップしてキーボードを開きます。[完了]をタップして、モーダルビューを閉じます。この時点から、バグはUITableViewで発生します(次の手順を参照)。
(4)「挿入」をさらに数回タップします。すべての新しいセルが赤であることに注意してください。これは、新しいセルの行の間隔が間違っているためです。これは、テキストがすべて英語の文字である場合に使用される間隔です。これは、以前のようにアラビア語に余分な4ピクセルが追加されなくなったためです。
(5)いくつかのバグを実際に確認するには、[表示されているセルを再描画]ボタンをタップし、セルが再描画されるときにUITableViewの周囲の色が変化するのを確認します。
ディスカッション:キーボードがモーダルビューで開かれた後にデキューされた新しいセルの行の高さが、アラビア語やその他の英語以外のテキストに対して間違っているようです。これは、UITableViewのキャッシュメカニズムに関連しているようです。課題は、すべての状況で適切な行間隔がロードされるソリューションを見つけることです。