dellgg
dellgg

Reputation: 464

Display multiple uiwebviews in uitablview

I encountered a problem of webview and I thin many people had met that.

In my app, I have an UITableview and each cell of the tableview is self-defined. In each cell a UIWebview is embedded. I need to display each cell's content when I scroll my tableview. (webview's loadsHTML and image_url is from an local array)

Problem is that the UIWebview in each cell loads a remote image url and when user scrolls so fast the table, the webview in the cell can not reac fast enough so the webview may display the repeated image for less than 1 second. (Since I use reusable cell and webview loads from image_url array, so that

image_url = [array_image_url objectAtIndex:[index row]];

For user experience, that is terrible to see the repeated images. I tries to figue it out but still can't. Can anyone help me on this issue?

PS: If possible, I don't want to cache image on disk

Upvotes: 2

Views: 1336

Answers (2)

CashLee李秉骏
CashLee李秉骏

Reputation: 1048

Multiple UIWebViews in UITableView is not a good practice.But sometimes we wanna build an app in a short time,UIWebView is a very convenient class for us.

In my case,I set a custom UITableViewCell

CustomTableViewCell.h

#import <UIKit/UIKit.h>

@interface VerticalTableViewCell : UITableViewCell

@property (nonatomic,retain) UIWebView * webView;

-(void)setWebViewContent:(NSString *)htmlContent andIndex:(NSString *)row;

@end

CustomTableViewCell.m

#import "CustomTableViewCell.h"

@interface CustomTableViewCell()

@end

@implementation VerticalTableViewCell

@synthesize webView;

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
    if (self) {

        self.webView = [[UIWebView alloc]init];
        [self.webView setFrame:self.contentView.frame];
        [self.webView setUserInteractionEnabled:NO];
        [self.contentView addSubview:self.webView];

    }

    return self;
}

-(void)setWebViewContent:(NSString *)htmlContent andIndex:(NSString *)row
{
    [self.webView loadHTMLString:[NSString stringWithFormat:@"<html><head></head><body><div style='width:414px;height:414px;background-image:url(%@);background-size:414px 414px;'></div><p>现在是第%@排</p></body></html>",htmlContent,row] baseURL:nil];

}

- (void) layoutSubviews
{
    [super layoutSubviews];

    CGRect contentViewFrame = self.contentView.frame;
    contentViewFrame.size.width = [[UIScreen mainScreen] bounds].size.width;
    contentViewFrame.size.height = 586.0f;
    self.contentView.frame = contentViewFrame;
    self.webView.frame = contentViewFrame;
}


-(void)dealloc
{
    [self.webView loadHTMLString:nil baseURL:nil];
    self.webView = nil;
}


@end

CustomTableView.m

...


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CMainCell = @"CMainCell";

    CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CMainCell];
    if (cell == nil) {
        cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleValue1  reuseIdentifier: CMainCell];
        //自定义cell的内容
    }
    if (self.whiteData!=nil) {
        NSString * row = [NSString stringWithFormat:@"%ld",indexPath.row];
        [cell setWebViewContent:self.whiteData[indexPath.row] andIndex:row];
        //[cell setCustomImage:self.whiteData[indexPath.row]];
    }

    return cell;
}

-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomTableViewCell * customCell = (CustomTableViewCell *)cell;
    [customCell.webView loadHTMLString:nil baseURL:nil];
}

...

You can see I used the method :

-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;

In this method,when the cell invisible in tableView,cells will set webViews empty.

In our cases,because of the UITableView Reuse feature,cells won't clean up the contentViews.Therefore users scroll tableView in a very fast way,the cells would be reused and the HTML content is still there.If we clean up the contentView,works well.

But another problem is still here.Because cells should render HTML content when they come into visible area.Rendering speed of UIWebView is not quite fast,so we should write some code for optimizing the rendering process.

Hope this would help you.Cheers.

Upvotes: 0

LJ Wilson
LJ Wilson

Reputation: 14427

I have had a similar problem (I was displaying remote images) and used the UIScrollView delegate methods (UITableView inherits from UIScrollView) to handle when to update my images or not. You can do something similar to load content when the scrolling is stopped:

// UIScrollView Delegate Methods
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    if (!decelerate) {
        [self loadImagesForOnscreenRows];
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [self loadImagesForOnscreenRows];
}

EDIT - Forgot the method that actually loads the rows. This might help :) Note - Some of this code is specific to my app, you will need to adapt to suit your data and web location of the image. Also - the setImageWithURL method is part of the AFNetworking library. If you haven't checked out AFNetworking, it rocks. If you aren't already using AFN and don't need to, then I also added a class I wrote that uses blocks to async load web images.

- (void)loadImagesForOnscreenRows
{
    if ([self.phonebookData count] > 0)
    {
        NSArray *visiblePaths = [self.myTableView indexPathsForVisibleRows];
        for (NSIndexPath *indexPath in visiblePaths)
        {
            NSDictionary *selRow = [[self.persons valueForKey:[[[self.persons allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];

            PBCell *cell = (PBCell *)[self.myTableView cellForRowAtIndexPath:indexPath];

            if ([[selRow objectForKey:@"picFileName"] length] > 0) {           
                [cell.thumbnailImage setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"YourURLHere/%@",[selRow objectForKey:@"picFileName"]]] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

            } else {
                cell.thumbnailImage.image = [UIImage imageNamed:@"defaultImage.png"];
            }
        }
    }
}

Alternative method instead of AFNetworking:

WebImageOperations.h:

//
//  WebImageOperations.h
//
//  Created by Larry Wilson on 11/11/11.
//  Copyright (c) 2011 Larry Wilson. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface WebImageOperations : NSObject {
}

+ (void)processImageDataWithURLString:(NSString *)urlString andBlock:(void (^)(NSData *imageData))processImage;

@end

WebImageOperations.m:

//
//  WebImageOperations.m
//
//  Created by Larry Wilson on 11/11/11.
//  Copyright (c) 2011 Larry Wilson. All rights reserved.
//

#import "WebImageOperations.h"
#import <QuartzCore/QuartzCore.h>

@implementation WebImageOperations

+ (void)processImageDataWithURLString:(NSString *)urlString andBlock:(void (^)(NSData *imageData))processImage
{
    NSURL *url = [NSURL URLWithString:urlString];

    dispatch_queue_t callerQueue = dispatch_get_current_queue();
    dispatch_queue_t downloadQueue = dispatch_queue_create("com.myappname.processimagedataqueue", NULL);
    dispatch_async(downloadQueue, ^{
        NSData * imageData = [NSData dataWithContentsOfURL:url];

        dispatch_async(callerQueue, ^{
            processImage(imageData);
        });
    });
    dispatch_release(downloadQueue);
}

@end

Upvotes: 2

Related Questions