一行核心代碼做出類似tableViewHeaderView和AppStore里的ScrollView懸浮條效果

現(xiàn)在主流app里面經(jīng)常需要有tableView上滑出現(xiàn)懸浮條樣式的設(shè)計(jì),寶寶看了下appleStore里面專題推薦用的scrollView 也有類似的懸浮效果,只不過它是下拉懸浮,而主流的是上滑懸??!最終實(shí)現(xiàn)效果如以下gif圖。

上滑懸停條樣式

appStore下拉懸浮條效果

仿appStore效果

其實(shí)一看上去 表以為是兩種不同的方案,其實(shí)兩種思路方式完全一致,本來核心代碼就一行,那么要修改的代碼豈不是半行,確實(shí)如此哦,寶寶已笑瘋??????,好了啦,開個(gè)玩笑,進(jìn)入正題!

先別敲代碼,想想懸浮條實(shí)現(xiàn)思路

  • 上滑懸浮條樣式的思路

當(dāng)你看到本文第一張的動(dòng)圖的時(shí)候你想到了什么,對,沒錯(cuò),上滑的時(shí)候高度在減小最后會(huì)減小到一個(gè)固定值,下滑的時(shí)候高度在增加最后也會(huì)增加到一個(gè)固定值,那么簡單點(diǎn)描述就是懸浮條原點(diǎn)不變,讓其高度減小,在下面代碼里第二種實(shí)現(xiàn)方式就是這樣;其實(shí)我實(shí)現(xiàn)的是讓懸浮條的原點(diǎn)變化,高度不變,也是一樣的效果。

  • appStore下拉懸浮條樣式的思路

有了第一種思路,會(huì)發(fā)現(xiàn)下拉懸浮條的過程與上面驚人的相似,上滑的時(shí)候高度在減小,只不過最后會(huì)減為0,下滑的時(shí)候高度在增加最后也會(huì)增加到一個(gè)固定值。

  • 技術(shù)實(shí)現(xiàn)

    通過KVO監(jiān)聽tableView的contentOffset屬性值或者在scrollView的代理方法中監(jiān)聽contentOffset的值來讓懸浮條的原點(diǎn)變化,高度不變,或者原點(diǎn)不變,高度變化!
    將自定義的headerView放在tabView 的上面,即headerView和tableView為平級關(guān)系,都添加到viewController的view上,然后設(shè)置tableView的contentInset為headerView的值,在tableView滑動(dòng)的時(shí)候,動(dòng)態(tài)改變view的位置或者大小,使這個(gè)headerView看起來就像是有了懸浮功能的tableView.tableHeaderView。
  • 核心代碼

寶寶真的沒有騙你們,真的只要一行,只要你看得懂就行??????,因?yàn)槲野盐逍衖f語句和成一行了,表問我為什么!
_yellowView.frame = offset.y < -64 ? (offset.y <= -200 ? CGRectMake(0, 0, 375, 200) : CGRectMake(0, -offset.y - 200, 375, 200)) : CGRectMake(0, 64 - 200, 375, 200);

代碼實(shí)現(xiàn)

- (void)viewDidLoad {

    [super viewDidLoad];
   //加載tableView到self.view上
    UITableView *tableView = [[UITableView alloc]  initWithFrame:CGRectMake(0, 0, 375, 667) style:UITableViewStylePlain];
    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
    tableView.dataSource = self;
    tableView.contentInset = UIEdgeInsetsMake(200, 0, 0, 0);
    [self.view addSubview:tableView];
  //利用KVO監(jiān)聽tableView的contentOffset的屬性值,從而動(dòng)態(tài)改變懸浮條yellowView的frame值
   [tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];

  //加載yellowView作為懸浮條視圖到self.view上,因此tableView和yellowView是同一級關(guān)系,黃色視圖在tableView的上面
    TouchView *yellowView = [[TouchView alloc] initWithFrame:CGRectMake(0, 0, 375, 200)];
    yellowView.backgroundColor = [UIColor yellowColor];
  //將alpha設(shè)置成為0.7的透明度是為了看得更清楚底下的tableView隨時(shí)滾動(dòng)的位置
    yellowView.alpha = 0.7;
    [self.view addSubview:yellowView];
  //設(shè)置成全局的實(shí)例變量是為了在監(jiān)聽方法中可以改變懸浮條yellowView的frame值
   _yellowView = yellowView;
 }

#pragma mark - KVO監(jiān)聽tableView的contentOffset的屬性值變化
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {

     CGPoint offset = [change[NSKeyValueChangeNewKey] CGPointValue];

    //64為懸浮條最終停留的高度
    if (offset.y < -64) {
    
         //小于-64則有兩種情況,第一種小于-64是當(dāng)懸浮條一進(jìn)來時(shí)候,由于contentInset.top被我們調(diào)成了懸浮條的高度200,
       因此offset.y初始值是-200,當(dāng)用戶上滑懸浮條的時(shí)候,會(huì)在 -200 <= offset.y <= -64 范圍內(nèi)波動(dòng),我們需要
       調(diào)整懸浮條的Y坐標(biāo)為-offset.y - 200,如- (-180) - 200 = -20 ,代表tableView向上偏移了20各點(diǎn),我們改變其原點(diǎn),
       造成懸浮條懸停的假象;第二種小于-64是當(dāng)懸浮條一進(jìn)來時(shí)候,offset.y初始值是-200,當(dāng)用戶下滑懸浮條的時(shí)候,offset.y會(huì)負(fù)的越多,
       在 offset.y < -200 范圍內(nèi)波動(dòng),我們需要調(diào)整懸浮條的Y坐標(biāo)為固定值200,不讓其變大變小即可??!搞定
    
       //第一種方案,改變懸浮條的Y坐標(biāo),而不改變其高度,這也是本文核心代碼?。。。?       _yellowView.frame = offset.y <= -200 ?  CGRectMake(0, 0, 375, 200) : CGRectMake(0, -offset.y - 200, 375, 200);
    
       //第二種方案,改變懸浮條的高度,而不改變其原點(diǎn)
       //_yellowView.frame = offset.y < -200 ?  CGRectMake(0, 0, 375, 200) : CGRectMake(0, 0, 375, -offset.y);
    
       //下面這行代碼沒必要添加,我看到網(wǎng)上很多人加了這句,實(shí)屬?zèng)]必要,tableView滾動(dòng)本來就靠contentOffset,contentInset只是添加額外的滾動(dòng)區(qū)域的
       //_tableView.contentInset = offset.y > -200 ? UIEdgeInsetsMake(-offset.y, 0, 0, 0) :UIEdgeInsetsMake(200, 0, 0, 0);
    }else {
    
       //大于等于-64就只有一種情況了,當(dāng)?shù)竭_(dá)臨界值的時(shí)候就會(huì) 懸停64的最小高度,該高度自己隨便寫啦,然后appStore那個(gè)效果是上滑到臨界值后,高度依然減小,
     那么需要調(diào)整懸浮條的Y坐標(biāo)為-offset.y - 200,offset.y會(huì)越來越 大于-64,導(dǎo)致_yellowView.frame.origin.y負(fù)的越多,越來偏離屏幕原點(diǎn),
     正好滿足需求看不見懸浮條啦!
    
      //appStore下拉懸浮條效果只需要改這行代碼讓上滑的時(shí)候原點(diǎn)超過其高度200,這樣就看不到懸浮條了
      //_yellowView.frame = CGRectMake(0, -offset.y - 200, 375, 200);;
    
      //第一種方案,改變懸浮條的Y坐標(biāo)為懸停最小值64 - 200,這樣在用戶界面上就只顯示64的高度,而不改變其高度
      _yellowView.frame = CGRectMake(0, 64 - 200, 375, 200);
    
      //第二種方案,改變懸浮條的高度為最小值64,而不改變其原點(diǎn)
      //_yellowView.frame = CGRectMake(0, 0, 375, 64);
    
      //下面這行代碼沒必要添加,我看到網(wǎng)上很多人加了這句,實(shí)屬?zèng)]必要,tableView滾動(dòng)本來就靠contentOffset,contentInset只是添加額外的滾動(dòng)區(qū)域的
      //_tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
  }
}

自定義TouchView

如果有另外需求比如要是拖動(dòng)黃色視圖,tableView要是也能滾動(dòng)的話,那么就需要自己攔截點(diǎn)擊事件??!

@implementation TouchView

//這兩個(gè)方法隨便寫一個(gè)即可,為的是攔截響應(yīng)鏈,不讓其捕獲到觸摸事件,這樣用戶手指點(diǎn)擊上面的黃色視圖,window分發(fā)觸摸事件的時(shí)候,會(huì)認(rèn)為用戶點(diǎn)擊的那個(gè)點(diǎn)最遠(yuǎn)的響應(yīng)視圖是 tableView,因?yàn)閠ableView在黃色視圖的下方,這樣,當(dāng)滑動(dòng)黃色視圖的時(shí)候,tableView也跟著一起滾動(dòng)了啦?。?!
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return NO;
}

//先調(diào)用hitTest:withEvent:此方法,再調(diào)用pointInside:withEvent:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

   UIView *view = [super hitTest:point withEvent:event];
   if ([view isKindOfClass:[self class]]) {
    
       return nil;
   }
   return nil;
 }

@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容