如何在表格单元格中使用UIWebView?

时间:2009-03-14 21:54:08

标签: iphone cocoa-touch uitableview uiwebview

我正在构建一个包含一些HTML文本的表,所以我使用UIWebView作为自定义表格单元格的子视图。我已经遇到了一个问题 - 当我在表格中向下滚动时,UIWebViews需要更新一次。例如,我将在编号为1,2和3的行中查看单元格。我向下滚动到8,9和10.有一会儿,在单元格#8中可见的UIWebView的内容是来自单元#1的内容,单元#9中的内容是来自单元#2的内容,依此类推。

我了解到问题是UIWebViews只是缓慢地渲染文本。有人建议我尽快将内容预先加载到UIWebView中,而不是等到表收到cellForRowAtIndexPath。所以现在,我有一个Domain Object,它之前只有WebView的文本内容 - 但现在它实际上有一个UIWebView本身的引用。

但是现在UIWebView中的一些内容呈现,当我滚动表格时,UIWebView仅显示为灰色框。如果我触摸灰色框,它将实际接收触摸并更新WebView - 例如,如果我触摸链接(我可能会或可能不会,因为该框是灰色的,这将是一个运气),链接到的页面将被请求并正确显示。

- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) {
            // I suppose this isn't necessary since I am just getting it from the
            // Domain Object anyway
    content = [[UIWebView alloc] initWithFrame:CGRectZero];
    content.backgroundColor = [UIColor blackColor];
    [self addSubview:content];
    [content release];
}
return self;
}

// called by cellForRowAtIndexPath 
- (void)setMyDomainObject:(MyDomainObject*)anObject {
UIWebView *contentWebView = anObject.contentWebView;
int contentIndex = [self.subviews indexOfObject:content];
[self insertSubview:contentWebView atIndex:contentIndex];
}

7 个答案:

答案 0 :(得分:9)

解决这个问题的一种方法是使用几个UILabel,每个UILabel都有不同的字体。然后战略性地将它们放在单元格中,使它们看起来像连续的文本。我已经在UITableView中看到了这一点,效果非常好。

另一个性能问题可能是您覆盖了UItableViewCell及其init方法。这几乎总是导致UITableView中的性能不佳。而只是使用常规的UITableViewCell实例并将子视图添加到它的contentView。

Matt Gallagher的Easy Custom UITableView Drawing广泛报道了这一点。

描述的另一种方法是使用Three20,它也可以为您提供样式文本。

使用UIWebview无法完成您当前的尝试。

预加载无效:当UIWebviews在屏幕外呈现时,这会降低用户界面的速度;你应该总是在iPhone上练习延迟加载。

将UIWebviews置于UITableView中会带来潜在的不可接受的性能影响。您需要使用其他方法来实现目标。

不幸的是,NSAttributedString在UIKit中不可用,这可以轻松解决您的问题。

答案 1 :(得分:6)

所以这是我更新的答案:我使用一个大的UIWebView实现了一个表,将样式化的文本放在我自己的Twitter客户端应用程序HelTweetica中的表格单元格中(可用源代码)。只要您了解如何在HTML和CSS中进行布局,它就能很好地工作。

您只需创建NSMutableString并添加构成文档的HTML行。您可以引用外部文件,例如应用程序沙箱中的CSS文件。您可以设置自定义URL操作,例如“youraction://file.txt”,您的Web视图委托可以拦截这些操作并作为替换IBAction进行处理:

- (void) refreshWebView {
    TwitterAccount *account = [twitter currentAccount];
    NSMutableString *html = [[NSMutableString alloc] init];
    // Open html and head tags
    [html appendString:@"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"];
    [html appendString:@"<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"];
    [html appendString:@"<head>\n"];
    [html appendString:@"<meta name='viewport' content='width=device-width' />"];
    [html appendString:@"<link href='style-ipad.css' rel='styleSheet' type='text/css' />"];
    [html appendString:@"<script language='JavaScript' src='functions.js'></script>"];

    // Body
    [html appendString:@"</head><body><div class='artboard'>"];

    // [...]

    // Close artboard div, body. and html tags
    [html appendString:@"</div></body></html>\n"];

    NSURL *baseURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] bundlePath]];
    [self.webView loadHTMLString:html baseURL:baseURL];
    [html release];
}

您可以使用javascript:

重新加载部分页面
- (void) refreshTabArea {
    NSString *html = [self stringByEscapingQuotes: [self tabAreaHTML]];
    NSString *js = [NSString stringWithFormat: @"document.getElementById(\"tab_area\").innerHTML = \"%@\";", html];
    [self.webView stringByEvaluatingJavaScriptFromString:js];
}

答案 2 :(得分:4)

如果Web视图中的内容仅限于样式文本或超链接,您可能需要查看Three20项目:http://github.com/joehewitt/three20/tree/master

TTStyledText课程支持内容中的<b>, <i>, <img>, and <a>代码。可能比webviews更轻量级。

答案 3 :(得分:2)

这不是回答问题的原始问题,而是退一步看大图,如果你试图在表格单元格中显示超链接,这是否意味着当你点击它时会打开一个网页浏览器?如果您在表格单元格中显示看起来像或提示链接的样式文本,但打开一个单独的屏幕,使用全屏网页视图,让您点击链接,它会是相同的吗?

答案 4 :(得分:1)

你说'由setRowAtIndexPath调用',你可能意味着'cellForRowAtIndexPath',这是一个UITableView方法,当一行变得可见并需要创建一个单元格时调用。确保在此方法中正确初始化和更新单元格内容。

答案 5 :(得分:0)

您是否考虑过覆盖表格单元子类上的-prepareForReuse方法?如果滚动时单元格似乎没有更新,则可能无法清除和重置可重用单元格的内容。

答案 6 :(得分:0)

我的理解是,除非你在viewDidLoad()发生之后启动加载,否则WebView不会呈现。