0

iPad 的 iOS5+ 中存在一个非常奇怪的行间距错误:如果您使用 UITableView,其中每个 UITableViewCell 都是包含 UITextView 的自定义类型,那么包含来自非 AZ 语言(如阿拉伯语)的多行文本的单元格将与在模态视图中打开键盘后错误的行高。

注意:虽然这似乎是 iOS 中的一个错误,但我正在寻找一种解决方法,以便我的应用程序向后兼容 iOS5+ 的版本。

以下是如何复制错误:

(1)(a)在您的故事板中,创建一个 UIViewController(尽管创建您自己的子类),其中您有一个 UIToolbar 和一个 UITableView。在 UITableView 中,创建一个标识符为“CellIdentifier”的“Dynamic Prototype”单元格和一个标签为“1”且所有 AutoResize 属性打开的 UITextView(因此它占据了单元格的完整大小)。

步骤 1a 的屏幕截图

(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 添加一个模态 segue,主视图控制器称为“modalSegue”。

步骤 2a 的屏幕截图

(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 将没有内容。

步骤 1 的屏幕截图

(2)点击工具栏中的“插入”按钮几次。两个单元格将以绿色添加。请注意,对于仅包含阿拉伯语和英语的行,此处的行间距要高 4 个像素(字体大小为 20)(您可以自己尝试在单元格中使用全英文文本)。在这个阶段,您会看到应用程序的正确行为。

步骤 2 截图

(3)点击“显示模态视图”按钮,当模态视图打开时,点击 UITextField 内部以打开键盘。点击“完成”关闭模式视图。从这一点开始,该错误将发生在 UITableView 中(请参阅下一步)。

第三步截图

(4)再点几次“插入”。请注意,所有新单元格都是红色的。这是因为新单元格中的行间距是错误的——如果文本是全英文字母,它们是使用的间距,因为不再像以前那样为阿拉伯语添加额外的 4 个像素。

步骤 4 的屏幕截图

(5)要真正看到一些错误,请点击“Redraw Visible Cells”按钮,然后在重绘单元格时观察 UITableView 周围的颜色变化。

讨论:在模态视图中打开键盘后出列的新单元格似乎对阿拉伯语和其他非英语文本有错误的行高。这似乎与 UITableView 的缓存机制有关。挑战在于找到在所有情况下都加载适当行距的解决方案。

4

1 回答 1

0

这不是一个完美的解决方案,而是一个黑客/解决方法。真正的解决方案将在 Apple 修复此错误时出现。

请注意:Apple Developer Support 推荐了此答案。

在 UITextField 或 UISearchBar 成为具有样式表的模态视图中的第一响应者之后,在 UITableViewCells 内的所有 UITextView 中都会导致此错误。

解决方法是:

  1. 子类 UITextView 以创建您自己的 UITextField 和 UISearchBar 版本,而不是使用实际的控件。
  2. 不要在 UITableViewCell 中使用 UITextView。相反,使用 Core Text 创建您自己的版本。

选项 1 更快,但在滚动方面有其自身的挑战。选项 2 效果很好,但需要很长时间。研究 EGOTextView 以获得良好的起点。

于 2012-08-29T01:59:23.103 回答