V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
11
V2EX  ›  iDev

怎样计算带有UIWebView的Cell的高度?

  •  1
     
  •   11 · 2013-12-05 21:11:47 +08:00 · 6266 次点击
    这是一个创建于 4001 天前的主题,其中的信息可能已经有所发展或是发生改变。
    UIWebView在每个cell中的内容都不同,在 tableView:cellForRowAtIndexPath: 中 alloc 的,然后需要在 heightForRowAtIndexPath: 中计算高度。

    可是问题是,在创建这个cell之前没法知道UIWebView的高度呀,可是 heightForRowAtIndexPath 是需要在这之前提供高度的。也就说调用 UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 会出错。


    所以应该怎么办?如果在 heightForRowAtIndexPath 中 alloc 一个 UIWebView 再读取 htmlString 得到 height 这样速度会太慢了吧,而且会做两边同样的工作。。

    求解。
    16 条回复    1970-01-01 08:00:00 +08:00
    ultragtx
        1
    ultragtx  
       2013-12-05 21:34:43 +08:00   ❤️ 1
    一般tableview用label都嫌拖动的时候卡 用webview估计你早晚要改实现方式
    如果硬要这么整那只有你说这种 反正要先算出来 或者是你先给个大概的高度 然后等webview加载完了再更新
    11
        2
    11  
    OP
       2013-12-05 21:51:41 +08:00
    @ultragtx 但是如果做图文混排的那种,比如论坛客户端什么的,用UIWebView貌似是最理想的选择了吧。 用 CoreText 太折磨人了。。
    xuan_lengyue
        3
    xuan_lengyue  
       2013-12-05 22:15:11 +08:00
    @11 为什么不整体用UIWebView实现呢,UITableView 里面嵌 UIWebView 这个会很有问题。
    harrymoo
        4
    harrymoo  
       2013-12-05 22:38:02 +08:00   ❤️ 1
    1. heightForRowAtIndexPath:中返回你的uiwebview的height;
    2. uiwebview加载完后,在webViewDidFinishLoad:中计算出实际高度,调用:
    [self.tableView reloadRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationNone];
    [self.tableView beginUpdates];
    [self.tableView endUpdates];
    完毕。
    11
        5
    11  
    OP
       2013-12-05 23:25:17 +08:00
    @harrymoo 所以在 1 中,这里的 height 是随便设的一个值么?不是真正的 height。
    chisj
        6
    chisj  
       2013-12-06 09:28:21 +08:00   ❤️ 1
    @11 不是的,这个就是cell的height,只是你的webView高度在内容load前和load后会变化,所以需要重新设置并reload tableView。
    so898
        7
    so898  
       2013-12-06 13:55:41 +08:00   ❤️ 1
    我曾经做过楼主你正在做的事情……

    首先,UITableView的heightForRowAtIndexPath:函数是在主线程中运行的,而且必须在reload的时候提供一个可以使用的值
    然后,UIWebView的高都计算需要在Web载入完成之后通过JS或者contentViewSize来计算,这个部分中Web载入是在独立的WebCore线程中进行的,载入完成之后通过Delegate回掉通知主线程

    所以说,要做的话就是得在heightForRowAtIndexPath:提供一个大概的高度值,然后在UIWebView载入完成算完高度之后refresh指定的Cell
    但这个实现有个问题,就是Cell不太好复用,而且后续Cell高度计算会导致所有内容全部被加载到UIWebView里面,在面对微博之类的内容的时候会导致内存占用过高
    如果要复用的话,就得建立很好的NSURLCache来缓存主要页面内容,然后祈祷UIWebView快点加载……

    对了,这里还要说一下注意的点,就是UIWebView的webViewDidFinishLoad:会被多次调用的,这里要做好处理
    11
        8
    11  
    OP
       2013-12-06 17:03:11 +08:00
    @so898 所以呢。。后来你还是用这个方案么?我昨天试了 @harrymoo 说的,然后果然就在 webViewDidFinishLoad: 这里卡死了。。这里应该怎么处理?我是用 superview 得到的 cell,然后得到 indexPath,再用的 [self.tableView reloadRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationNone] 。就卡死了。。求个 example。 @chisj
    harrymoo
        9
    harrymoo  
       2013-12-06 19:06:03 +08:00   ❤️ 1
    @11 怎么个卡死? 其实@so898也已经提到了,你不应直接在 webViewDidFinishLoad:里面去refresh tableview,因为是不同的线程,建议Post一个Notification到界面主线程处理。
    chisj
        10
    chisj  
       2013-12-09 20:14:43 +08:00   ❤️ 1
    @11 因为没有看到你的代码,我猜测下看能不能帮你提供一点思路:你的程序卡死的原因可能是死循环?在webViewDidFinishLoad: 你调用了 [self.tableView reloadRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationNone],然后在UITableView Datasource的 tableView:cellForRowAtIndexPath:里,你返回的cell里又重新init或者load了webView,导致了死循环?

    是否可以试试在viewDidLoad里就初始化好UIWebView,然后tableView:cellForRowAtIndexPath:里add到cell的contentView里。

    这样至少不会死循环导致你程序“卡死”。
    11
        11
    11  
    OP
       2013-12-09 22:04:09 +08:00
    @chisj Exactly! 如果在 viewDidLoad 里初始化 UIWebView 的话,也需要得到 cell 才能进行初始化?因为 UIWebView 是在每个 cell 中的。

    我觉得我现在的思路有问题,麻烦请教一下那些图文混排的微博客户端什么的都是怎么做 cell?
    chisj
        12
    chisj  
       2013-12-09 23:30:41 +08:00
    @11 图文混排的微博现在好像都不用UIWebView了,毕竟性能上不好,应该都是使用CoreText了,参考唐巧的博客: http://blog.devtang.com/blog/2013/10/21/the-tech-detail-of-ape-client-3/ 。你说的“得到cell才能进行初始化”我没有理解是什么意思啊~~~
    BB9z
        13
    BB9z  
       2013-12-11 09:54:36 +08:00
    如果 WebView 在顶部的话建议方到 table 的 header view 里。更新高度的话 headerView = headerView 就可以。
    dazuiba
        14
    dazuiba  
       2013-12-24 21:41:36 +08:00
    如果楼主你实在想这么干,我这里有个方案:

    UIWebView load完毕后,执行一段JS,拿到document的Height.再通过WebView的Delegate传递给Objective-C Code.

    然后再传递给TableViewController,告诉它这个Cell的高度已经拿到了,待所有Cell的高度都返回后,TableViewController开始显示TableView.

    貌似没别的好办法。
    CDuXZMAPgHp1q9ew
        15
    CDuXZMAPgHp1q9ew  
       2014-03-01 00:10:30 +08:00
    楼主啊
    富文本两个办法

    coretext
    自己实现起来要求较高
    开源库有 一些 比如说 rtlabel rclabel TTTAttributedLabel FTCoreText SECoreTextView

    webview
    注意哦 不是每个cell一个webview, 一个webview就够你受得了, 会卡死你的

    这里有一个绝佳的tableview里面加了两个webview的实践
    https://github.com/gaosboy/iOSSF/

    或者最好使用一个webview用html5搞得像原生的一样, 在复杂页面时效果最好
    比如说 我现在做的一个论坛的客户端中的帖子页面
    CDuXZMAPgHp1q9ew
        16
    CDuXZMAPgHp1q9ew  
       2014-03-01 00:12:11 +08:00
    另外
    https://github.com/gaosboy/iOSSF/
    里面的检测contentSize获得高是我见过最好最"原生"的方法
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1070 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:30 · PVG 03:30 · LAX 11:30 · JFK 14:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.