WKWebView UITableView单元格高度和Instagram嵌入代码

问题描述 投票:0回答:1

我正在尝试将Instagram帖子添加到表格视图中的单元格中,但是尽管尝试了一堆其他方法,但我无法正确计算单元格高度。我为每个单元格创建一个WKWebView,并将loadHTMLString与Instagram提供的嵌入代码一起使用,并对Instagram的HTML进行了少许修改,如下所示:

`<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"></head>`

[当我在模拟器中运行它时,Instagram帖子的大小似乎正确了约半秒钟,然后调整了大小。

下面是一些基本代码,演示了运行时的问题,出于示例目的,在两个不同的单元格中显示了一个硬编码的Instagram帖子。如果我在随机网站而不是loadRequest上使用NSURLRequestloadHTMLString,则单元格的大小可以正常使用,并且一切正常。如何以显示整个帖子的方式使用Instagram在UITableViewCells中嵌入代码?

InstagramViewController.h

#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>

@interface InstagramViewController : UIViewController <WKNavigationDelegate, WKUIDelegate, UITableViewDelegate, UITableViewDataSource>
@property (strong, nonatomic) IBOutlet WKWebView *webView;
@property (strong, nonatomic) IBOutlet UITableView *tableView;

@end

InstagramViewController.m

#import "InstagramViewController.h"

@interface InstagramViewController ()
@property (nonatomic) BOOL loaded;
@property (nonatomic) CGFloat cellHeight;

@end

@implementation InstagramViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.estimatedRowHeight = 150;
    self.tableView.rowHeight = UITableViewAutomaticDimension;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 2;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *simpleTableIdentifier = @"simpleTableIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
    }
    WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
    WKWebView *webView = [[WKWebView alloc] initWithFrame:cell.contentView.frame configuration:theConfiguration];
    webView.navigationDelegate = self;
    [webView.scrollView setScrollEnabled:NO];
    webView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
    webView.tag = indexPath.section;
    NSString *instagramEmbedHTML = @"\
    <!DOCTYPE html>\
    <html>\
    <head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    </head>\
    <body>\
    <blockquote class=\"instagram-media\" data-instgrm-captioned data-instgrm-version=\"7\" style=\" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);\">\
    <div style=\"padding:8px;\">\
    <div style=\" background:#F8F8F8; line-height:0; margin-top:40px; padding:41.91489361702128% 0; text-align:center; width:100%;\">\
    <div style=\" background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAMUExURczMzPf399fX1+bm5mzY9AMAAADiSURBVDjLvZXbEsMgCES5/P8/t9FuRVCRmU73JWlzosgSIIZURCjo/ad+EQJJB4Hv8BFt+IDpQoCx1wjOSBFhh2XssxEIYn3ulI/6MNReE07UIWJEv8UEOWDS88LY97kqyTliJKKtuYBbruAyVh5wOHiXmpi5we58Ek028czwyuQdLKPG1Bkb4NnM+VeAnfHqn1k4+GPT6uGQcvu2h2OVuIf/gWUFyy8OWEpdyZSa3aVCqpVoVvzZZ2VTnn2wU8qzVjDDetO90GSy9mVLqtgYSy231MxrY6I2gGqjrTY0L8fxCxfCBbhWrsYYAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-22px; width:44px;\">\
    </div>\
    </div>\
    <p style=\" margin:8px 0 0 0; padding:0 4px;\">\
    <a href=\"https://www.instagram.com/p/BVR2uajF1Qc/\" style=\" color:#000; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none; word-wrap:break-word;\" target=\"_blank\">I wish for... free cupcakes!! 🎈🎈 First 50 customers at our #Gramercy location get a free #Summer Collection 3-Pack to celebrate 5 beautiful, magical years on 23rd St! 💕 Today only! Open &#39;til 10pm 🎂 #happybirthday</a>\
    </p>\
    <p style=\" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;\">A post shared by Baked by Melissa (@bakedbymelissa) on <time style=\" font-family:Arial,sans-serif; font-size:14px; line-height:17px;\" datetime=\"2017-06-13T12:00:48+00:00\">Jun 13, 2017 at 5:00am PDT</time>\
    </p>\
    </div>\
    </blockquote>\
    <script async defer src=\"http://platform.instagram.com/en_US/embeds.js\"></script>\
    </body></html>";
    [webView loadHTMLString:instagramEmbedHTML baseURL:nil];
    [cell.contentView addSubview:webView];
    return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [self calculateHeightForCellAtIndexPath:indexPath];
}

-(CGFloat)calculateHeightForCellAtIndexPath:(NSIndexPath *)indexP{
    while (!_loaded) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
    NSLog(@"new cell height: %f", _cellHeight);
    return _cellHeight;
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    NSLog(@"I finished");
    [webView evaluateJavaScript:@"document.body.scrollHeight;" completionHandler:^(NSString *result, NSError *error) {
        if (error != NULL) {
            NSLog(@"Error %@",error);
        }
        NSLog(@"new scrollHeight Result %@",result);
        float ht = [result floatValue];
        NSIndexPath* indexOfCell = [NSIndexPath indexPathForRow:0 inSection:webView.tag];
        UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexOfCell];
        cell.frame = CGRectMake(0, 0, cell.frame.size.width, ht);
        _cellHeight = ht;
        self.loaded = YES;
    }];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}
@end

这是运行上面的代码时得到的输出的屏幕截图,在其中您可以看到嵌入的大小超出了计算出的单元格高度的大小,在这种情况下,将整个注释部分切除:

The author's text for each Instagram post is cut off because of the sizing issue

ios objective-c uitableview instagram wkwebview
1个回答
0
投票

我已经为此苦苦了很长时间。此解决方案对我有用。

您将获得适当的高度。从这一点开始,您的任务就是处理它并设置容器的高度。

警告:这并不简单。

注:Instagram嵌入在这里真是太可怕了。他们的脚本计算宽度ot 621(!)的高度,并将其设置为iframe的属性。因此,您“简单”(LOL)必须重新计算大小。请参阅新属性“ modded”,以避免多次设置高度。

这是使用HTML,CSS,Javascript,当然还有Swift的混合解决方案。


func initMyWebView() {

//...

        let contentController = WKUserContentController()

        contentController.add(
            self,
            name: "heightChanged"
        )
        contentController.add(
            self,
            name: "log"
        )
        contentController.removeAllUserScripts()
        contentController.addUserScript(WKUserScript(source: windowSizeWatcherScript(), injectionTime: .atDocumentEnd, forMainFrameOnly: true))
// ...

}

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "log" {
            print("JSLog: " + String(describing: message.body))
            return
        }

        if message.name == "heightChanged" {
            if let messageDict = message.body as? Dictionary<String, CGFloat> {
                if nil != messageDict["height"] {
                    DispatchQueue.main.async { [weak self] in
                        self?.delayedSetSize(height: messageDict["height"]!)
                    }
                }
            }
            return
        }

    }


func style(jsonStyle: JSONTextStyleModel?) -> String {
        let maxHTMLW = bounds.width

        return """
        html, body {
            margin: 0 !important;
            padding: 0 !important;
            width: 100% !important;
            max-width: \(maxHTMLW)px !important;
            min-width: \(maxHTMLW)px !important;
        }
        body {
            font-family: Roboto;
            background-color: \(Theme.shared.generalColors.background);
            color: \((jsonStyle?.color).defaultsTo(value: "#333"));
            font-size: 16px;
            font-weight: 300;
        }

        #\(contentId) {
            margin: 0 2% !important;
            padding: 0 !important;
            height: 100%;
            display: block;
            width: 96%;
        }

        iframe {
            width: 100% !important;
        }

        iframe.instagram-media-rendered {
        }
        """
    }

    func online(html: String, with style: String) -> String {
        return """
        <!DOCTYPE html>
        <html>
            <head>
                <meta name="viewport" content="width=device-width, initial-scale=1">
                <style>
                \(style)
                </style>                
            </head>
            <body>
                <div id="\(contentId)">
                    \(html)
                </div>
            </body>
        </html>
        """
    }

func windowSizeWatcherScript() -> String {
        let maxInstaW = bounds.width * 0.96
        return """
            var prevHeight = 0;
            var prevWidth = 0;
            var contentId = "\(contentId)";
            customLog("windowSizeWatcherScript added")

            var resizeTimeout = setTimeout(function () { resize(); }, 125);


            if (typeof(webkit) !== 'undefined' && typeof(webkit.messageHandlers.log) !== 'undefined') {
                console.log = customLog;
            }

            function resize() {
                clearTimeout(resizeTimeout);

                if (typeof(webkit) == 'undefined' || typeof(webkit.messageHandlers.heightChanged) == 'undefined') {
                    customLog("Cannot send webkit messages");
                    resizeTimeout = setTimeout('resize();', 125);
                    return;
                }


                var width = 0
                var height = 0

                var insta = document.getElementsByClassName("instagram-media-rendered");
                var iframes = document.getElementsByTagName("iframe");
                var content = document.getElementById(contentId);

                var instaWidth = 0
                var instaHeight = 0
                if (typeof(insta) !== "undefined" && insta.length > 0) {
                    insta[0].setAttribute("width", "\(Int(maxInstaW))px");
                    instaWidth = insta[0].offsetWidth
                    instaHeight = Math.max(insta[0].scrollHeight, insta[0].offsetHeight)
                    width = instaWidth;
                    var h = insta[0].getAttribute("height")
                    var modded = insta[0].getAttribute("modded")
                    if (modded == "undefined" && h !== "undefined" && h > 0) {
                        h = h.replace("px", "")
                        let r = \(maxInstaW) / 621;
                        height = h * r;
                        insta[0].setAttribute("height", height + "px");
                        insta[0].setAttribute("modded", "1");
                    } else {
                        height = instaHeight;
                    }
                } else  if (typeof(iframes) !== "undefined" && iframes.length > 0) {
                    var iframeWidth = iframes[0].offsetWidth
                    var iframeHeight = Math.max(iframes[0].scrollHeight, iframes[0].offsetHeight)

                    width = iframeWidth;
                    height = iframeHeight;
                } else if (typeof(content) !== 'undefined') {
                        var contentWidth = content.offsetWidth;
                        var contentHeight = Math.max(content.scrollHeight, content.offsetHeight);
                        width = contentWidth
                        height = contentHeight
                }


                if (height > 0 && prevHeight != height) {
                    customLog("W: " + width + " H: " + height);
                    try { webkit.messageHandlers.heightChanged.postMessage({"height": height});} catch (err) { customLog("No native app context"); }
                    customLog("Detected width " + width + " and height " + height);
                    prevHeight = height;
                    resizeTimeout = setTimeout('resize();', 125);
                } else {
                    resizeTimeout = setTimeout(function () { resize(); }, 500);
                }
            }

            function customLog(message) {
                if (typeof(webkit) == "undefined" || typeof(webkit.messageHandlers.log) == "undefined") {
                    console.log("No native app context");
                    console.log(message)
                    return
                }
                try { webkit.messageHandlers.log.postMessage(message);} catch (err) { console.log("No native app context"); }
            }
"""
    }
© www.soinside.com 2019 - 2024. All rights reserved.