我正在尝试将Instagram帖子添加到表格视图中的单元格中,但是尽管尝试了一堆其他方法,但我无法正确计算单元格高度。我为每个单元格创建一个WKWebView
,并将loadHTMLString
与Instagram提供的嵌入代码一起使用,并对Instagram的HTML进行了少许修改,如下所示:
`<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"></head>`
[当我在模拟器中运行它时,Instagram帖子的大小似乎正确了约半秒钟,然后调整了大小。
下面是一些基本代码,演示了运行时的问题,出于示例目的,在两个不同的单元格中显示了一个硬编码的Instagram帖子。如果我在随机网站而不是loadRequest
上使用NSURLRequest
和loadHTMLString
,则单元格的大小可以正常使用,并且一切正常。如何以显示整个帖子的方式使用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 '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
这是运行上面的代码时得到的输出的屏幕截图,在其中您可以看到嵌入的大小超出了计算出的单元格高度的大小,在这种情况下,将整个注释部分切除:
我已经为此苦苦了很长时间。此解决方案对我有用。
您将获得适当的高度。从这一点开始,您的任务就是处理它并设置容器的高度。
警告:这并不简单。
注: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"); }
}
"""
}