Search code examples
objective-cuitextviewicarousel

iCarousel and UITextView -- blank text view


I'm using iCarousel to display editable question cards. The cards contain a UITextView for entering the question (or already contain text as you swipe through filled cards). However, when the carousel is presented and scrolled, sometimes text views appear empty.

This is due to a UITextView optimization of not drawing text offscreen. But text views in a UITableView will not suffer from this.

As many know, using setNeedsDisplay will NOT work due to the optimization, so it doesn't redraw the text.

I currently change the text view's frame by adding and then removing 1px. This forces a redraw. However, I can only do this when the item changes. iCarousel does not have a willDisplayCell delegate method. (Nick, can you add one easily? The code baffles me)

Because iCarousel is preloading many views for smoothness (which is necessary, setting iCarouselOptionVisibleItems doesn't fix anything) there doesn't seem to be anything else I can do but know when the view is about to come on screen. Suggestions?

- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
    MIQuestionView *questionView = (MIQuestionView *)view;

    if (questionView == nil)
    {
        MIQuestionType type = [self.testSection.questionType integerValue];
        questionView = [[MIQuestionView alloc] initWithFrame:CGRectNull questionType:type];
        questionView.delegate = self;
    }

    questionView.question = [self.testSection.questions objectAtIndex:index];

    return questionView;
}

The text view is embedded in the MIQuestionView. The text is set in the question setter. There's no way for me to know when it's coming onto the screen. To be clear, I don't want to resize. The text is not drawn offscreen and appear blank when coming on-screen.

Sorry, I didn't look for ambiguous code above:

- (id)initWithFrame:(CGRect)frame questionType:(MIQuestionType)type
{
    if (CGRectEqualToRect(frame, CGRectNull))
        frame = CGRectMake(0, 0, 650, 244);

    self = [super initWithFrame:frame];
    ...

Solution

  • It's an odd bug. I'm not sure if it's an issue with iCarousel or just a quirk of iOS that you need to deal with when dynamically adding and removing UITextViews from the view hierarchy.

    I have a solution that's maybe a bit cleaner than the ones you've found though; Just add this to your MICardView:

    - (void)didMoveToSuperview
    {
        if (self.superview)
        {
            _textView.frame = self.bounds;
        }
    }
    

    This basically forces the textView to re-layout every time the cardView is recycled, and it avoids you having to do anything special in your view controller to work around the issue.