简体   繁体   中英

UITextViews in a UITableView link detection bug in iOS 7

I have custom UITableViewCells that contain a UITextView. I have link detection in the UITextView turned on in Interface Builder. When I first load the table view, everything seems to be working, but as I scroll up and down the table view, the link detection gets messed up. Specifically, cells that just have regular text (which are presented normally initially) are being shown as links (all the text in the text view is coloured blue and is an active link), and the links point to objects that are in some of the other table view cells. For example a link might point to a website that was in a different table view cell, or launch an email to an address that was in a different table view cell.

It seems like when the table view cells are being reused, even though the text view text is being updated, the links are somehow getting saved.

This only happens in iOS 7, not iOS 6. It happens in the simulator and on my device.

Here is the code:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *sectionKey = [self.orderedSectionKeys objectAtIndex:indexPath.section];
    NSDictionary *infoDictionary = [[self.tableViewData objectForKey:sectionKey] objectAtIndex:indexPath.row];

    static NSString *cellIdentifier = @"InfoDefaultTableViewCell";
    InfoDefaultTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {        
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"InfoTableViewCells" owner:self options:nil];
        cell = [topLevelObjects objectAtIndex:0];
    }

    cell.bodyTextView.text = [infoDictionary objectForKey:@"description"];

    return cell;
}

Does anyone know what is happening here, and how to solve it?


I tried adding this code after setting the text view text, to try to reset the links:

cell.bodyTextView.dataDetectorTypes = UIDataDetectorTypeNone;
cell.bodyTextView.dataDetectorTypes = UIDataDetectorTypeAddress | UIDataDetectorTypeLink | UIDataDetectorTypePhoneNumber;

but it didn't change the behaviour that I'm seeing.

This appears to be a bug in iOS 7.0's UITextView s. A similar question has a workaround which seems to help: set the text view's text to nil before setting it to the new text string.

Several suggestions here and through links provided did not help me with this bug.

I tried setting attributed text, setting text to nil, setting text to @"".

In the end forcing the text view in an out of editable mode did the trick. In prepare for reuse

- (void)prepareForReuse
{
  ...
    textView.editable = YES;
    textView.editable = NO;
  ...
}

None of these answers worked for me (iOS8, Swift), the only thing that worked for me was to first set the text to nil and then prepend the new text with a non-visibile whitespace unicode character (I chose \​ , which is the ZERO WIDTH SPACE character but any character works):

textView.text = nil
textView.text = "​\u{200B}\(newText)"

Found a better way to solve this problem. This requires an extra step every single time you set text. But this definitely fixes the problem.

_textView.selectable = NO; // set it to NO clears all possible data detection work so far.
_textView.selectable = YES; // set it to YES so that actual links are detected.

Basically data detection requires the selectable field to be set to YES to work. When you set it to NO, its completely removed.

Note: This is only for ios7.

Setting the text to nil did not work for me in a very similar problem, but setting scrollEnabled to NO , like suggested here , did the trick for me.

Edit: In addition there was still a very special case, that caused problems: When a box began with a link and the new text was set to empty text (@"" - not nil!) the box somehow "broke" and from then on any new text became a link. My solution was to override setText to set [super text] to @"x" first and then to the actual new text. Setting it to nil instead did not solve this problem either.

As any of the above solutions worked for me, a workaround I've found is to create your UITextView when you are supposed to update the text for each cell instead of reusing in the reusable cell.

Your code in the UITableViewCellDataSource would be :

- (void)updateDescriptionWithText:(NSString *)descriptionText
{
    UITextView *descriptionTV = [[UITextView alloc] initWithFrame:aFrame];
    [descriptionTV setScrollEnabled:NO]; 
    [descriptionTV setEditable:NO]; 
    [descriptionTV setDataDetectorTypes:UIDataDetectorTypeLink]; 
    if ([descriptionV respondsToSelector:@selector(setSelectable:)]) 
     [descriptionTV  setSelectable:YES];
    [descriptionTV setText:descriptionText];
    [self addSubview:descriptionTV];
}

And in the UITableViewCell :

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   ***your init code***

   [cell updateDescriptionWithText:description];
}   

您可以使用NSAttributedString解决此问题。

cell.textview.attributedText = [[NSAttributedString alloc] initWithString:message.message];

It seems that setting the text to nil before setting the new text doesn't work. You also might need to be able to scroll the text view, so setting the scrollEnabled might not be an option.

However, it works when you create and set an attributed string to the cell's text view. I used a collection view , but it should be the same with table views . I wrote the following lines in the collectionView:cellForItemAtIndexPath:

//get the color and other properties from your UITextView
UIColor *textColor = cell.textView.textColor;
UIFont *messageFont = cell.textView.font;

//create your attributed string
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:yourStringForTheTextView attributes:@{NSForegroundColorAttributeName:textColor, NSFontAttributeName:messageFont}];

//set it to your UITextView
cell.textView.attributedText = attributedString;

Hope this helps :).

Non of the suggested workarounds work for me. So I decided to create a new UITextView and replace it with the old one, every time the cell is reused. It is not ideal for performance, but at least it works.

This one works reliably for me:

// fix url detection bug
cell.textView.dataDetectorTypes = UIDataDetectorTypeNone;
cell.textView.dataDetectorTypes = UIDataDetectorTypeLink;

Changing the Tint color to other color actually works. However if selectable enable the tint will also be the same color.

I also face this problem and I found out to solve this is to set textview properties in the following order,

[textview setDataDetectorTypes:UIDataDetectorTypeNone ];
textView.editable = NO;
[textView setDataDetectorTypes:UIDataDetectorTypeLink];
textView.text=@"The text you need to show with link";

Hope this help you.....

textView.text = nil;
textView.attributedText = nil;

textView.attributedText = [[NSAttributedString alloc] initWithString:@"your new string"];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM