一行核心代碼作出相似tableViewHeaderView和AppStore裏的ScrollView懸浮條效果

如今主流app裏面常常須要有tableView上滑出現懸浮條樣式的設計,寶寶看了下appleStore裏面專題推薦用的scrollView 也有相似的懸浮效果,只不過它是下拉懸浮,而主流的是上滑懸浮!最終實現效果如如下gif圖。 app

上滑懸停條樣式
appStore下拉懸浮條效果
仿appStore效果
其實一看上去 表覺得是兩種不一樣的方案,其實兩種思路方式徹底一致,原本核心代碼就一行,那麼要修改的代碼豈不是半行,確實如此哦,寶寶已笑瘋😂😂😂,好了啦,開個玩笑,進入正題! ##先別敲代碼,想一想懸浮條實現思路

  • ###上滑懸浮條樣式的思路 當你看到本文第一張的動圖的時候你想到了什麼,對,沒錯,上滑的時候高度在減少最後會減少到一個固定值,下滑的時候高度在增長最後也會增長到一個固定值,那麼簡單點描述就是懸浮條原點不變,讓其高度減少,在下面代碼裏第二種實現方式就是這樣;其實我實現的是讓懸浮條的原點變化,高度不變,也是同樣的效果。
  • ###appStore下拉懸浮條樣式的思路 有了第一種思路,會發現下拉懸浮條的過程與上面驚人的類似,上滑的時候高度在減少,只不過最後會減爲0,下滑的時候高度在增長最後也會增長到一個固定值。
  • ###技術實現 經過KVO監聽tableView的contentOffset屬性值或者在scrollView的代理方法中監聽contentOffset的值來讓懸浮條的原點變化,高度不變,或者原點不變,高度變化! 將自定義的headerView放在tabView 的上面,即headerView和tableView爲平級關係,都添加到viewController的view上,而後設置tableView的contentInset爲headerView的值,在tableView滑動的時候,動態改變view的位置或者大小,使這個headerView看起來就像是有了懸浮功能的tableView.tableHeaderView。
  • ###核心代碼 寶寶真的沒有騙大家,真的只要一行,只要你看得懂就行😂😂😂,由於我把五行if語句和成一行了,表問我爲何! _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);

##代碼實現ide

- (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監聽tableView的contentOffset的屬性值,從而動態改變懸浮條yellowView的frame值
   [tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];

  //加載yellowView做爲懸浮條視圖到self.view上,所以tableView和yellowView是同一級關係,黃色視圖在tableView的上面
    TouchView *yellowView = [[TouchView alloc] initWithFrame:CGRectMake(0, 0, 375, 200)];
    yellowView.backgroundColor = [UIColor yellowColor];
  //將alpha設置成爲0.7的透明度是爲了看得更清楚底下的tableView隨時滾動的位置
    yellowView.alpha = 0.7;
    [self.view addSubview:yellowView];
  //設置成全局的實例變量是爲了在監聽方法中能夠改變懸浮條yellowView的frame值
   _yellowView = yellowView;
 }

#pragma mark - KVO監聽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是當懸浮條一進來時候,因爲contentInset.top被咱們調成了懸浮條的高度200,
       所以offset.y初始值是-200,當用戶上滑懸浮條的時候,會在 -200 <= offset.y <= -64 範圍內波動,咱們須要
       調整懸浮條的Y座標爲-offset.y - 200,如- (-180) - 200 = -20 ,表明tableView向上偏移了20各點,咱們改變其原點,
       形成懸浮條懸停的假象;第二種小於-64是當懸浮條一進來時候,offset.y初始值是-200,當用戶下滑懸浮條的時候,offset.y會負的越多,
       在 offset.y < -200 範圍內波動,咱們須要調整懸浮條的Y座標爲固定值200,不讓其變大變小便可!!搞定
    
       //第一種方案,改變懸浮條的Y座標,而不改變其高度,這也是本文核心代碼!!!!
       _yellowView.frame = offset.y <= -200 ?  CGRectMake(0, 0, 375, 200) : CGRectMake(0, -offset.y - 200, 375, 200);
    
       //第二種方案,改變懸浮條的高度,而不改變其原點
       //_yellowView.frame = offset.y < -200 ?  CGRectMake(0, 0, 375, 200) : CGRectMake(0, 0, 375, -offset.y);
    
       //下面這行代碼不必添加,我看到網上不少人加了這句,實屬不必,tableView滾動原本就靠contentOffset,contentInset只是添加額外的滾動區域的
       //_tableView.contentInset = offset.y > -200 ? UIEdgeInsetsMake(-offset.y, 0, 0, 0) :UIEdgeInsetsMake(200, 0, 0, 0);
    }else {
    
       //大於等於-64就只有一種狀況了,當到達臨界值的時候就會 懸停64的最小高度,該高度本身隨便寫啦,而後appStore那個效果是上滑到臨界值後,高度依然減少,
     那麼須要調整懸浮條的Y座標爲-offset.y - 200,offset.y會愈來愈 大於-64,致使_yellowView.frame.origin.y負的越多,越來偏離屏幕原點,
     正好知足需求看不見懸浮條啦!
    
      //appStore下拉懸浮條效果只須要改這行代碼讓上滑的時候原點超過其高度200,這樣就看不到懸浮條了
      //_yellowView.frame = CGRectMake(0, -offset.y - 200, 375, 200);;
    
      //第一種方案,改變懸浮條的Y座標爲懸停最小值64 - 200,這樣在用戶界面上就只顯示64的高度,而不改變其高度
      _yellowView.frame = CGRectMake(0, 64 - 200, 375, 200);
    
      //第二種方案,改變懸浮條的高度爲最小值64,而不改變其原點
      //_yellowView.frame = CGRectMake(0, 0, 375, 64);
    
      //下面這行代碼不必添加,我看到網上不少人加了這句,實屬不必,tableView滾動原本就靠contentOffset,contentInset只是添加額外的滾動區域的
      //_tableView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
  }
}
複製代碼

###自定義TouchView 若是有另外需求好比要是拖動黃色視圖,tableView要是也能滾動的話,那麼就須要本身攔截點擊事件!!spa

@implementation TouchView

//這兩個方法隨便寫一個便可,爲的是攔截響應鏈,不讓其捕獲到觸摸事件,這樣用戶手指點擊上面的黃色視圖,window分發觸摸事件的時候,會認爲用戶點擊的那個點最遠的響應視圖是 tableView,由於tableView在黃色視圖的下方,這樣,當滑動黃色視圖的時候,tableView也跟着一塊兒滾動了啦!!!
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return NO;
}

//先調用hitTest:withEvent:此方法,再調用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
複製代碼
相關文章
相關標籤/搜索