iOS WKWebView+UITableView混排

WKWebView+UITableView混排

目錄

做內(nèi)容展示頁(yè)的時(shí)候,經(jīng)常會(huì)用到WKWebView+UITableView的混排功能窜锯,現(xiàn)在此做一個(gè)總結(jié),該功能的實(shí)現(xiàn)我采用了四種方法作岖。

  • 1各吨、 tableView.tableHeaderView = webView 撐開(kāi)webView
  • 2、[webView.scrollView addSubview:tableView] + 占位Div
  • 3层宫、tableView.tableHeaderView = webView 不撐開(kāi)webView (推薦)
  • 4、scrollView addSubView: webView & tableView (推薦)
  • 5其监、結(jié)尾

方案1:

webView作為tableViewHeader, 撐開(kāi)webView萌腿,顯示渲染全部?jī)?nèi)容,當(dāng)內(nèi)容過(guò)多時(shí)抖苦,比如大量高清圖片時(shí)毁菱,容易造成內(nèi)存暴漲(不建議使用)米死,此方案簡(jiǎn)單粗暴 , 僅適用于內(nèi)容少的場(chǎng)景,具體實(shí)現(xiàn)不在此贅述贮庞,直接看代碼峦筒。

方案2:

簡(jiǎn)書(shū)的內(nèi)容頁(yè)實(shí)現(xiàn)方案 : UIWebView與UITableView的嵌套方案

tableView 加到 webView.scrollView 上, webView 加載的HTML最后留一個(gè)空白占位div,用于確定 tableView 的位置窗慎,在監(jiān)聽(tīng)到webView.scrollView.contentSize變化后物喷,不斷調(diào)整tableView的位置,同時(shí)將該div的尺寸設(shè)置為tableView的尺寸捉邢。禁用tableViewwebView.scrollViescrollEnabled = NO脯丝,通過(guò)添加pan手勢(shì),手動(dòng)調(diào)整 contentOffset商膊。tableView的最大高度為屏幕高度伏伐,當(dāng)內(nèi)容不足一屏?xí)r,高度為內(nèi)容高度晕拆。

方案3(推薦):

webView作為tableView的Header, 但不撐開(kāi)webView藐翎。禁用tableViewwebView.scrollVie的scrollEnabled = NO,通過(guò)添加pan手勢(shì),手動(dòng)調(diào)整contentOffset实幕。webView的最大高度為屏幕高度吝镣,當(dāng)內(nèi)容不足一屏?xí)r,高度為內(nèi)容高度昆庇。和方案2類(lèi)似末贾,但是不需要插入占位Div。主要代碼如下:

  • 步驟1:初始化配置
//禁用自帶的滑動(dòng)功能
 _webView.scrollView.scrollEnabled = NO;
 _tableView.scrollEnabled = NO;
// 給父視圖添加拖動(dòng)手勢(shì)
 [self.view addGestureRecognizer:self.panRecognizer];
  • 步驟2:手動(dòng)調(diào)整contentOffset
/// 拖拽手勢(shì)整吆,模擬UIScrollView滑動(dòng)
- (void)handlePanGestureRecognizer:(UIPanGestureRecognizer *)recognizer {
    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan: {
            //開(kāi)始拖動(dòng)拱撵,移除之前所有的動(dòng)力行為
            [self.dynamicAnimator removeAllBehaviors];
        }
            break;
        case UIGestureRecognizerStateChanged: {
            CGPoint translation = [recognizer translationInView:self.view];
            //拖動(dòng)過(guò)程中調(diào)整scrollView.contentOffset
            [self scrollViewsSetContentOffsetY:translation.y];
            [recognizer setTranslation:CGPointZero inView:self.view];
        }
            break;
        case UIGestureRecognizerStateEnded: {
            // 這個(gè)if是為了避免在拉到邊緣時(shí),以一個(gè)非常小的初速度松手不回彈的問(wèn)題
            if (fabs([recognizer velocityInView:self.view].y) < 120) {
                if ([self.tableView sl_isTop] &&
                    [self.webView.scrollView sl_isTop]) {
                    //頂部
                    [self performBounceForScrollView:self.webView.scrollView isAtTop:YES];
                } else if ([self.tableView sl_isBottom] &&
                           [self.webView.scrollView sl_isBottom]) {
                    //底部
                    if (self.tableView.frame.size.height < self.view.sl_height) { //tableView不足一屏表蝙,webView bounce
                        [self performBounceForScrollView:self.webView.scrollView isAtTop:NO];
                    } else {
                        [self performBounceForScrollView:self.tableView isAtTop:NO];
                    }
                }
                return;
   }
  • 步驟3:模擬慣性和邊緣反彈效果
   //動(dòng)力元素 力的操作對(duì)象
 SLDynamicItem *item = [[SLDynamicItem alloc] init];
 item.center = CGPointZero;
  __block CGFloat lastCenterY = 0;
//慣性力
 UIDynamicItemBehavior *inertialBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[item]];
 //給item添加初始線(xiàn)速度 手指松開(kāi)時(shí)的速度
 [inertialBehavior addLinearVelocity:CGPointMake(0, -[recognizer velocityInView:self.view].y) forItem:item];
       //減速度  無(wú)速度阻尼
     inertialBehavior.resistance = 2;
       __weak typeof(self) weakSelf = self;
      inertialBehavior.action = ^{
        //慣性力 移動(dòng)的距離
     [weakSelf scrollViewsSetContentOffsetY:lastCenterY - item.center.y];
     lastCenterY = item.center.y;
 };
  //注意拴测,self.inertialBehavior 的修飾符是weak,慣性力結(jié)束停止之后府蛇,會(huì)釋放inertialBehavior對(duì)象集索,self.inertialBehavior = nil
  self.inertialBehavior = inertialBehavior;
     [self.dynamicAnimator addBehavior:inertialBehavior];
 }

//反彈力
- (void)performBounceForScrollView:(UIScrollView *)scrollView isAtTop:(BOOL)isTop {
    if (!self.bounceBehavior) {
        //移除慣性力
        [self.dynamicAnimator removeBehavior:self.inertialBehavior];           //吸附力操作元素
        SLDynamicItem *item = [[SLDynamicItem alloc] init];
        item.center = scrollView.contentOffset;
        //吸附力的錨點(diǎn)Y
        CGFloat attachedToAnchorY = 0;
        if (scrollView == self.tableView) {
            //頂部時(shí)吸附力的Y軸錨點(diǎn)是0  底部時(shí)的錨點(diǎn)是Y軸最大偏移量
            attachedToAnchorY = isTop ? 0 : [self.tableView sl_maxContentOffsetY];
        }else {
            attachedToAnchorY = 0;
        }
        //吸附力
        UIAttachmentBehavior *bounceBehavior = [[UIAttachmentBehavior alloc] initWithItem:item attachedToAnchor:CGPointMake(0, attachedToAnchorY)];
        //吸附點(diǎn)的距離
        bounceBehavior.length = 0;
        //阻尼/緩沖
        bounceBehavior.damping = 1;
        //頻率
        bounceBehavior.frequency = 2;
        bounceBehavior.action = ^{
            scrollView.contentOffset = CGPointMake(0, item.center.y);
        };
        self.bounceBehavior = bounceBehavior;
        [self.dynamicAnimator addBehavior:bounceBehavior];
    }
}


方案2和3依賴(lài)于 UIKit 中的動(dòng)力學(xué)/仿真物理學(xué)模塊,去實(shí)現(xiàn)松手后的慣性滑動(dòng)和邊緣反彈效果汇跨,涉及的類(lèi)主要包括 UIDynamicAnimator务荆、UIDynamicItemBehaviorUIAttachmentBehavior穷遂、UIDynamicItem蛹含,我也利用這些類(lèi)自定義繼承于UIView的類(lèi)實(shí)現(xiàn)UIScrollView的效果,詳情可以去看代碼塞颁。

方案4(推薦):

[scrollView addSubView: webView & tableView]; scrollView.contenSize = webView.contenSize + tableView.contenSize; webViewtableView的最大高度為一屏高浦箱,并禁用scrollEnabled=NO吸耿,然后根據(jù)scrollView的滑動(dòng)偏移量調(diào)整webViewtableView的展示區(qū)域contenOffset

  • 步驟1:確定webView和tableView的高度
//添加觀(guān)察者 監(jiān)聽(tīng)webView 和tableView 的contentSize
- (void)addKVO{
    [self.webView addObserver:self
                   forKeyPath:NSStringFromSelector(@selector(estimatedProgress))
                      options:NSKeyValueObservingOptionNew
                      context:nil];
    [self.webView addObserver:self forKeyPath:@"scrollView.contentSize" options:NSKeyValueObservingOptionNew context:nil];
    [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
}
/// 根據(jù)WebView和tableView的ContentSize變化酷窥,調(diào)整父scrollView.contentSize咽安、WebView和tableView的高度位置、展示區(qū)域
- (void)updateContainerScrollViewContentSize{
    
    self.containerScrollView.contentSize = CGSizeMake(self.view.sl_width, _webViewContentHeight + _tableViewContentHeight);
    
    //如果內(nèi)容不滿(mǎn)一屏蓬推,則webView妆棒、tableView高度為內(nèi)容高,超過(guò)一屏則最大高為一屏高
    CGFloat webViewHeight = (_webViewContentHeight < self.view.sl_height) ? _webViewContentHeight : self.view.sl_height ;
    CGFloat tableViewHeight = _tableViewContentHeight < self.view.sl_height ? _tableViewContentHeight : self.view.sl_height;
    
    self.contentView.sl_height = webViewHeight + tableViewHeight;
    self.webView.sl_height = webViewHeight <= 0.1 ?0.1 :webViewHeight;
    self.tableView.sl_height = tableViewHeight;
    self.tableView.sl_y = self.webView.sl_height;
    
    //更新展示區(qū)域
    [self scrollViewDidScroll:self.containerScrollView];
}

  • 步驟2:根據(jù)scrollView的偏移量調(diào)整webView和tableView的的位置和偏移量

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    if (_containerScrollView != scrollView) {
        return;
    }
    CGFloat offsetY = scrollView.contentOffset.y;
    CGFloat webViewHeight = self.webView.sl_height;
    CGFloat tableViewHeight = self.tableView.sl_height;
     if (offsetY <= 0) {
        //頂部下拉
        self.contentView.sl_y = 0;
        self.webView.scrollView.contentOffset = CGPointZero;
        self.tableView.contentOffset = CGPointZero;
    }else if(offsetY < _webViewContentHeight - webViewHeight){
        //父scrollView偏移量的展示范圍在webView的最大偏移量?jī)?nèi)容區(qū)域
        //contentView相對(duì)位置保持不動(dòng)沸伏,調(diào)整webView的contentOffset
        self.contentView.sl_y = offsetY;
        self.webView.scrollView.contentOffset = CGPointMake(0, offsetY);
        self.tableView.contentOffset = CGPointZero;
    }else if(offsetY < _webViewContentHeight){
        //webView滑到了底部
        self.contentView.sl_y = _webViewContentHeight - webViewHeight;
        self.webView.scrollView.contentOffset = CGPointMake(0, _webViewContentHeight - webViewHeight);
        self.tableView.contentOffset = CGPointZero;
    }else if(offsetY < _webViewContentHeight + _tableViewContentHeight - tableViewHeight){
        //父scrollView偏移量的展示范圍到達(dá)tableView的最大偏移量?jī)?nèi)容區(qū)域
        //調(diào)整tableView的contentOffset
        self.contentView.sl_y = offsetY - webViewHeight;
        self.tableView.contentOffset = CGPointMake(0, offsetY - _webViewContentHeight);
        self.webView.scrollView.contentOffset = CGPointMake(0, _webViewContentHeight - webViewHeight);
    }else if(offsetY <= _webViewContentHeight + _tableViewContentHeight ){
        //tableView滑到了底部
        self.contentView.sl_y = self.containerScrollView.contentSize.height - self.contentView.sl_height;
        self.webView.scrollView.contentOffset = CGPointMake(0, _webViewContentHeight - webViewHeight);
        self.tableView.contentOffset = CGPointMake(0, _tableViewContentHeight - tableViewHeight);
    }else {
    }
}

5糕珊、結(jié)尾

涉及 WKWebView的使用、WKWebView+UITableView混排毅糟、UIScrollView實(shí)現(xiàn)原理红选、WKWebView離線(xiàn)緩存功能 等更多內(nèi)容都在 https://github.com/wsl2ls/iOS_Tips

iOS_Tips集合簡(jiǎn)介:
1、暗黑模式
2姆另、AppleID登錄應(yīng)用
3喇肋、AVFoundation 高仿微信相機(jī)拍攝和編輯
4、AVFoundation 人臉檢測(cè)
5迹辐、AVFoundation 實(shí)時(shí)濾鏡
6蝶防、GPUImage框架的使用
7、VideoToolBox和AudioToolBox音視頻編解碼
8明吩、OpenGL ES學(xué)習(xí)
9间学、LeetCode算法練習(xí)
10、鍵盤(pán)和UIMenuController的并存問(wèn)題
11印荔、iOS Crash防護(hù)
12低葫、WKWebView相關(guān)

如果需要跟我交流的話(huà):
※ Github: https://github.com/wsl2ls
※ 掘金:https://juejin.im/user/5c00d97b6fb9a049fb436288
※ 簡(jiǎn)書(shū):http://www.reibang.com/u/e15d1f644bea

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市躏鱼,隨后出現(xiàn)的幾起案子氮采,更是在濱河造成了極大的恐慌,老刑警劉巖染苛,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹊漠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡茶行,警方通過(guò)查閱死者的電腦和手機(jī)躯概,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)畔师,“玉大人娶靡,你說(shuō)我怎么就攤上這事】达保” “怎么了姿锭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵塔鳍,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我呻此,道長(zhǎng)轮纫,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任焚鲜,我火速辦了婚禮掌唾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忿磅。我一直安慰自己糯彬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布葱她。 她就那樣靜靜地躺著撩扒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪览效。 梳的紋絲不亂的頭發(fā)上却舀,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天虫几,我揣著相機(jī)與錄音锤灿,去河邊找鬼。 笑死辆脸,一個(gè)胖子當(dāng)著我的面吹牛但校,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播啡氢,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼状囱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了倘是?” 一聲冷哼從身側(cè)響起亭枷,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎搀崭,沒(méi)想到半個(gè)月后叨粘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瘤睹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年升敲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片轰传。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驴党,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出获茬,到底是詐尸還是另有隱情港庄,我是刑警寧澤倔既,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站鹏氧,受9級(jí)特大地震影響叉存,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜度帮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一歼捏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧笨篷,春花似錦瞳秽、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至冕臭,卻和暖如春腺晾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辜贵。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工悯蝉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人托慨。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓鼻由,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親厚棵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蕉世,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355