UITableView和UIScrollView分析


解決添加到ScrollView上的UITableView控件自動向下偏移64像素的問題

  • 首先理解1:即使UITableView沒有添加到ScrollView上寥袭,UIableView也會向下偏移20像素

    • 原因: 這是歷史遺留問題忠聚。就是說只要代碼中出現(xiàn)了UIableView,那么他被創(chuàng)建出來時滴须,默認坐標為(0,20)
  • 首先理解2:添加到ScrollView上的UITableView控件在20的基礎(chǔ)之上,還會再向下偏移64像素

    • 原因: 自動向下偏移64是由于系統(tǒng)的automaticallyAdjustsScrollViewInsets屬性默認開啟造成的。開啟之后,就會自動調(diào)整布局氓拼。所以會自動向下偏移xx像素。有時候不一定為64像素抵碟。但是都是這個屬性導致的桃漾。所以我們?nèi)绻胱约盒薷牟季郑仨殞傩栽O(shè)置為NO拟逮。
  • 首先理解3:偏移的這些像素對于UITableView來說都是內(nèi)邊距(ContentInset)撬统,即都是UITableView的ContentSize的內(nèi)邊距。因為UITableView的ContentSize的計算不包括內(nèi)邊距敦迄,所以這些像素不是ContentSize的內(nèi)容

  • 添加到ScrollView上的UITableView控件

    • 如果ScrollView上沒有導航欄恋追,就向下偏移20像素+xxx像素。xxx像素不確定多少罚屋,具體根據(jù)你添加了什么控件決定苦囱。確定的是有導航欄的情況下

    • 如果ScrollView上有導航欄,那么ScrollView上的控件在默認偏移20像素的基礎(chǔ)上脾猛,再向下移動64像素撕彤。即20像素+64像素。這個64像素是確定的猛拴。

    • 不讓控件向下移動64像素的做法如代碼1:(只是解決了偏移64像素的問題,運行時,UITableView仍然會向下偏移20像素)
      //不要控制器去自動調(diào)整scrollView的內(nèi)邊距
      self.automaticallyAdjustsScrollViewInsets = NO;
      官方解釋:automaticallyAdjustsScrollViewInsets根據(jù)按所在界面的status bar喉刘,navigationbar,與tabbar的高度漆弄,自動調(diào)整scrollview的 inset睦裳。
      我們不讓UIViewController調(diào)整整scrollview的inset撼唾,設(shè)置為no,然后我們再自己修改布局即可

    • 由于狀態(tài)欄的存在蛛蒙,控件仍然會向下移動20像素,不讓控件向下移動20像素的做法代碼2:

      //把子控件的y值設(shè)置為0牵祟,UITableView顯示時y坐標距屏幕頂部為0深夯,解決了UITableView向下偏移20像素的問題
      for (NSInteger i = 0; i < 5; i++) {
        UIViewController *childVcView = self.childViewControllers[i];//取控制器
        childVcView.view.frame = CGRectMake(i * scrollView.zb_width,0, scrollView.zb_width, scrollView.zb_height);//設(shè)置控制器的view的frame
        [scrollView addSubview:childVcView.view];//將控制器的view添加到scrollView上面
      
      
  • 總結(jié):僅僅利用代碼2將y坐標設(shè)置為0是不能夠?qū)ableView顯示在屏幕頂部的咕晋。只有代碼1+代碼2結(jié)合起來才能將TableView顯示在頂部掌呜。因為你不將代碼1自動調(diào)整設(shè)置為NO,系統(tǒng)仍然會根據(jù)當前界面上的控件來自動調(diào)整內(nèi)邊距,調(diào)整為64,即TableView向下移動64像素汰蓉。【已驗證】-->代碼1+代碼2在開發(fā)中成對出現(xiàn),缺一不可测秸。


ScrollView的frame和的contentSize的區(qū)別

  • ScrollView的frame的作用:
    • 控制可見范圍,超出可見范圍看不見
  • ScrollView的contentSize的作用:
    • 限制滾動的范圍(contentSize就是他們說的內(nèi)容或者尺寸或者內(nèi)容尺寸)

情況不同決定了UITableView是否需要設(shè)置寬高

  • 不是利用alloc init方式創(chuàng)建出來的UITableView,而從控制器的數(shù)組中取出來的UITableView本身就有寬高缠俺,不需要手動設(shè)置寬高。(注意:取出來的是UITableView唯笙,因為代碼中有.view)
   UIView *childVcView = self.childViewControllers[i].view;
   childVcView.zb_X = i * scrollView.zb_width;
   [scrollView addSubview:childVcView];
        
  • 利用alloc init方式創(chuàng)建出來的UITableView必須自己手動設(shè)置寬高
UITableView *tableView = [[UITableView alloc] init];
 tableView.zb_height = scrollView.zb_height;
 tableView.zb_width = scrollView.zb_width;

思想:一個TableView對應(yīng)一個控制器(本質(zhì)是類)。一個TableView有自己專門的數(shù)據(jù)源抄瑟。

  • 5個TableView對應(yīng)一個類
    • 因為TableView要顯示數(shù)據(jù)鞋拟,必須得執(zhí)行數(shù)據(jù)源方法才能顯示數(shù)據(jù)到UITableView上。
    • 如果5個TableView對應(yīng)1個類(即5個TableView都是在同一個類中創(chuàng)建的),那么5個TableView的數(shù)據(jù)源都是這一個類
  • 那么這個類執(zhí)行數(shù)據(jù)源方法的時候,如果在numberOfRowsInSection中不通過tableView.tag進行判斷是哪個TableView的話澄成,那么默認5個TableView中的行數(shù)都一樣。
  • 如果在numberOfRowsInSection中已經(jīng)通過tag判斷出是哪個TableView的前提下,又執(zhí)行了cellForRowAtIndexPath通今,這個時候如果不再次進行判斷的話,那么5個TableView的cell的內(nèi)容肯定都一樣掺喻。
  • 正常情況下,每個TableView都有自己的特點,顯示怎么樣的cell對于每個TableView來說,肯定都是不一樣的裂允。如果都一樣貌踏,做社交類app逗堵,電商類app,當進行切換標題欄的時候,每個TableView的內(nèi)容都一樣掂骏,這還看什么勁啊级解。
  • 通過tag進行很多的if else來判斷是哪個TableView的做法非常繁瑣掩驱,且代碼界面混亂民逼,所有的代碼都寫在一個類中,這個類會類似的。
  • 1個TableView對應(yīng)1個類
    • 每個TableView都有自己專門的數(shù)據(jù)源,這樣各個TableView顯示的cell就會互不影響早处。也避免了上述利用tag來進行判斷是哪個TableView的問題默责。
    • 優(yōu)點:每個模塊的功能和邏輯讓對應(yīng)的類去管理,后續(xù)開發(fā)的擴展性強

5個TableView對應(yīng)一個類(用于襯托1個TableView對應(yīng)1個類)

#import "ViewController.h"
#import "UIView+Frame.h"

#define ZBColor(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
#define ZBRandomColor ZBColor(arc4random_uniform(255), arc4random_uniform(255), arc4random_uniform(255))


@interface ViewController ()<UITableViewDataSource>
//@property (nonatomic,weak)UIScrollView *scrollView;
@property(nonatomic,strong)UITableViewCell *cell;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //將scrollView添加到控制器的view上
    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.frame = self.view.bounds;
    scrollView.backgroundColor = [UIColor redColor];
    [self.view addSubview:scrollView];
    //將5個TableView添加到scrollView上坟比。scrollView的contentSize為5個TableView的寬度
    for (NSInteger i =0; i < 5 ; i++) {
        UITableView *tableView = [[UITableView alloc] init];
        tableView.backgroundColor = ZBRandomColor;

        tableView.zb_height = scrollView.zb_height;
        tableView.zb_width = scrollView.zb_width;
        tableView.zb_X = i *tableView.zb_width;
        //5個tableView的數(shù)據(jù)源都是1個控制器柠衅,所以5個TableView上都顯示一樣的數(shù)據(jù)
        tableView.dataSource =self;
        tableView.tag=i;
        [scrollView addSubview: tableView];
    }
    scrollView.contentSize = CGSizeMake(5 *self.view.bounds.size.width, 0);
    scrollView.pagingEnabled =YES;
    
}


-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    if (tableView.tag == 0) return 5;
    if (tableView.tag == 1) return 10;
    if (tableView.tag == 2) return 15;
    if (tableView.tag == 3) return 20;
    else
        return 25;
    
}
static NSString * const ID = @"ce";
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
if(tableView.tag == 0){
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell  alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor clearColor];
    }
        cell.textLabel.text = [NSString stringWithFormat:@"第%ld個tableView-第%zd個cell",tableView.tag,indexPath.row];
         return cell;
}else if(tableView.tag == 1){
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell  alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor clearColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"第%ld個tableView-第%zd個cell",tableView.tag,indexPath.row];
    return cell;

}else if(tableView.tag == 2){
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    if (cell == nil) {
        cell = [[UITableViewCell  alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor clearColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"第%ld個tableView-第%zd個cell",tableView.tag,indexPath.row];
    return cell;
}else if(tableView.tag == 3){
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    if (cell == nil) {
        cell = [[UITableViewCell  alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor clearColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"第%ld個tableView-第%zd個cell",tableView.tag,indexPath.row];
    return cell;
}else{

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    if (cell == nil) {
        cell = [[UITableViewCell  alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor clearColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"第%ld個tableView-第%zd個cell",tableView.tag,indexPath.row];
    return cell;


}
}
@end

  • 效果圖:
41-04.gif

1個TableView對應(yīng)1個類

ViewController.h文件

#import "ViewController.h"
#import "UIView+Frame.h"
#import "ZBAllViewController.h"
#import "ZBPictureViewController.h"
#import "ZBVideoViewController.h"
#import "ZBVoiceViewController.h"
#import "ZBWordViewController.h"

#define ZBColor(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
#define ZBRandomColor ZBColor(arc4random_uniform(255), arc4random_uniform(255), arc4random_uniform(255))


@interface ViewController ()<UITableViewDataSource>
//@property (nonatomic,weak)UIScrollView *scrollView;
@property(nonatomic,strong)UITableViewCell *cell;
@end

@implementation ViewController

- (void)viewDidLoad {
   [super viewDidLoad];
   // 初始化子控制器
   [self setupChildVcs];
   
   // scrollView
   [self setupScrollView];
   
}

/**
*  初始化子控制器
*/
- (void)setupChildVcs
{
   [self addChildViewController:[[ZBAllViewController alloc] init]];
   [self addChildViewController:[[ZBVideoViewController alloc] init]];
   [self addChildViewController:[[ZBVoiceViewController alloc] init]];
   [self addChildViewController:[[ZBPictureViewController alloc] init]];
   [self addChildViewController:[[ZBWordViewController alloc] init]];
}

/**
*  scrollView
*/
- (void)setupScrollView
{
   UIScrollView *scrollView = [[UIScrollView alloc] init];
   scrollView.frame = self.view.bounds;
   [self.view addSubview:scrollView];
   
   // 添加5個模塊
   for (NSInteger i = 0; i < 5; i++) {
       /*
        3個方法的總結(jié):前提:控件添加到UIScrollView上。
                    方法1沒有設(shè)置y坐標,所以UITableView顯示時會向下偏移20像素
                    方法2和方法3設(shè)置了y坐標勋颖,并且設(shè)置為0叁执,使UITableView顯示時y距屏幕頂部為0次哈,所以UITableView顯示時會向下偏移20像素
       
        */
       //方法1:僅僅是設(shè)置childVcView的x坐標恢筝,childVcView的y坐標沒有設(shè)置此改。這樣會導致程序運行時暂题,childVcView也就是UITableView不是填充整個屏幕挂滓,而是向下偏移20像素的距離(狀態(tài)欄的原因)
       UIView *childVcView = self.childViewControllers[i].view;
       childVcView.zb_X = i * scrollView.zb_width;
       [scrollView addSubview:childVcView];
       
       
       /*  方法2:
       //注意:childVcView指針存著的是控制器的view,而不是控制器想括,因為等號右側(cè)有.view渣窜,所以childVcView這時候代表的是一個view位迂。.所以后面兩行代碼childVcView都不用加上.view坝橡。
       UIView *childVcView = self.childViewControllers[i].view;//取控制器的view
        
        childVcView.frame = CGRectMake(i * scrollView.zb_width, 0, scrollView.zb_width, scrollView.zb_height);//設(shè)置視圖的frame。
       [scrollView addSubview:childVcView];
       */
       /* 方法3:
       //childViewControllers中的子控制器真實是UITableViewController蹲堂,因為UITableViewController繼承UIViewController播聪,所以childVcView的類型也可以寫成UIViewController
       //childVcView指針存著的是控制器,因為沒有等號右側(cè)沒有.view衅檀。所以childVcView這時候代表的是一個控制器沉眶,后兩行代碼childVcView后面必須加上.view。因為我們最終是要把view添加到scrollView上的。
       UIViewController *childVcView = self.childViewControllers[i];//取控制器
       childVcView.view.frame = CGRectMake(i * scrollView.zb_width, 20, scrollView.zb_width, scrollView.zb_height);//設(shè)置控制器的view的frame
       [scrollView addSubview:childVcView.view];//將控制器的view添加到scrollView上面
        */
   }
   
   // 其他設(shè)置
   scrollView.contentSize = CGSizeMake(5 * scrollView.zb_width, 0);
   scrollView.pagingEnabled = YES;
}

@end

ZBPictureViewController文件,

  • 其余控制器的代碼和以下代碼一樣,就不一一列出了
import "ZBPictureViewController.h"
#define ZBColor(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
#define ZBRandomColor ZBColor(arc4random_uniform(255), arc4random_uniform(255), arc4random_uniform(255))
#import "ZBConst.h"
@interface ZBPictureViewController ()

@end

@implementation ZBPictureViewController

- (void)viewDidLoad {
   [super viewDidLoad];
   
   self.tableView.backgroundColor = ZBRandomColor;
}
#pragma mark - UITableViewDataSource

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
   
   return 30;
   
}
static NSString *ID = @"ce";
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
   
   UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:ID];
   if (cell == nil) {
       cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
       cell.backgroundColor = [UIColor clearColor];
   }
   
   cell.textLabel.text = [NSString stringWithFormat:@"%@ - %zd",self.class,indexPath.row];
   return cell;
}


@end

  • 效果圖
41-03.gif

addChildViewController和addSubview區(qū)分

  • 除了下面的解釋洲胖,還有一個做法來解決讓正確的對象添加到正確的對象身上。
    • addChildViewController是指:后面的參數(shù)是一個子控制器,要添加到前面的對象中
    • addSubview是指:后面的參數(shù)是一個子View库车,要添加到前面的對象中
    • 拓展:給某個對象添加顏色backgroundColor晶乔,一定要在view上添加
精華例子1:
//控制器才能添加到控制器中。因為self代表了控制器川无,如果某個對象要添加到控制器中疹味,那么這個對象必須是控制器】茬裕【蘋果公司規(guī)定】
 ZBAllViewController *vc1 = [[ZBAllViewController alloc] init];
    [self addChildViewController:vc1];
    
//View才能添加到View中铅檩。因為self.scrollView本身就是個View兔沃,它不是控制器,所以如果某個對象要添加到self.scrollView這個view中時额衙,這個而對象必須是View械哟,因為childVC是控制器的對象,所以必須把childVC再進行細化,拿到childVc的view拯爽。即使childVc.view
 UIViewController *childVc = self.childViewControllers[index];
 [self.scrollView addSubview:childVc.view];
精華例子2:
  • 超級經(jīng)典,注意對比
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //以下演示的給對象添加backgroundColor钧忽,frame等等屬性毯炮,這些屬性一定要在view上進行。
    
    UIView *zb  = [[UIView alloc]init];
    //zb是個view桃煎,已經(jīng)精確到了view,所以直接可以訪問backgroundColor大刊,frame屬性
    zb.backgroundColor = [UIColor redColor];
    zb.frame =CGRectMake(80, 80, 100,100);
    //self是控制器为迈,必須精確到控制器的view,才能將zb添加到控制器的view上缺菌,否則報錯葫辐。
    [self.view addSubview:zb];
    
    //雖說下面的顯示不出運行結(jié)果,但是我們的目的達到了
    
    UIViewController *vc = [[UIViewController alloc] init];
    //vc是個控制器,必須精確到vc.view伴郁,才能訪問backgroundColor另患,frame屬性
    vc.view.backgroundColor = [UIColor yellowColor];
    vc.view.frame =CGRectMake(300, 80, 100, 100) ;
    //vc是個控制器,所以可以添加到self上蛾绎。這個時候再用self.view就會報錯
    [self addChildViewController:vc];
}




@end


UIViewController和UITableViewController創(chuàng)建出來時昆箕,y的坐標分別為多少

40-26.png

創(chuàng)建TableView的3中方法

  • 方式1.利用自帶的ViewController類,繼承UIViewController
    • 然后在ViewController.m租冠,遵守協(xié)議<UITableViewDataSource, UITableViewDelegate>
    • 設(shè)置數(shù)據(jù)源和代理 tableView.dataSource = self; tableView.delegate = self;
    • 實現(xiàn)數(shù)據(jù)源方法和代理方法即可
  • 方式2.利用自帶的ViewController類鹏倘,將繼承的UIViewController類改為UITableViewController類
    • 在Storyboard選中名字為View的View,然后將Class改為UITableVIew
    • 然后在ViewController.m顽爹,直接實現(xiàn)數(shù)據(jù)源方法和代理方法纤泵,不要遵守協(xié)議,不需要設(shè)置數(shù)據(jù)源和代理
    • 注意:如果沒有繼承UITableViewController镜粤,而是繼承UIViewController捏题,在執(zhí)行那三個步驟,雖然能顯示TableView的樣子肉渴,但是TableView的cell里面沒有任何內(nèi)容公荧,即使你設(shè)置了cell的內(nèi)容
  • 方式3.利用自帶的ViewController類,將繼承的UIViewController類改為UITableViewController類
    • 在Storyboard中刪除默認的UIViewController控制器同规,增加一個UITableViewController控制器(別忘記加箭頭哦)
    • 然后選中Table View Controller循狰,將class改為ViewController窟社。這就實現(xiàn)了讓ViewController類來管理Table View Controller.
      • 如果UIViewController不繼承UITableViewController,而是繼承UIViewController绪钥,那么無法將將class改為ViewController灿里。
      • 因為只有相同類型才能進行管理,storyboard中的Table View Controller是UITableViewController類型的程腹,怎么能讓UIViewController類型的類來管理它呢
    • 然后在ViewController.m匣吊,直接實現(xiàn)數(shù)據(jù)源方法和代理方法,不要遵守協(xié)議寸潦,不需要設(shè)置數(shù)據(jù)源和代理
方法1代碼+截圖
  • ViewController.h文件
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController


@end


  • ViewController.m文件
#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, weak) UITableView *tableView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITableView *tableView = [[UITableView alloc] init];
    tableView.frame = CGRectMake(80, 100, 200, 300);
    tableView.backgroundColor = [UIColor grayColor];
    //數(shù)據(jù)源
    tableView.dataSource = self;
    //代理
    tableView.delegate = self;
    
    [self.view addSubview:tableView];
    

}
#pragma mark - <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"contentSize.height = %f", tableView.contentSize.height);
}

#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end


  • 截圖
41-05.gif

方法2代碼+截圖
  • ViewController.h文件
#import <UIKit/UIKit.h>

@interface ViewController : UITableViewController


@end

  • ViewController.m文件

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}


#pragma mark -代理方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"contentSize.height = %f", tableView.contentSize.height);
}

#pragma mark - 數(shù)據(jù)源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 20;
}
#pragma mark - 數(shù)據(jù)源方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor yellowColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end

  • 截圖
41-02.png

方法3代碼+截圖
  • ViewController.h文件
#import <UIKit/UIKit.h>

@interface ViewController : UITableViewController


@end

  • ViewController.m文件
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}


#pragma mark -代理方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"contentSize.height = %f", tableView.contentSize.height);
}

#pragma mark - 數(shù)據(jù)源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 20;
}
#pragma mark - 數(shù)據(jù)源方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end


  • 截圖效果和方法2一模一樣

UIScrollView的滾動

  • 詳看第六天 UIScrollView和UITableView滾動都是一樣的色鸳。
  • ContentOffset: UIScrollView控件frame距內(nèi)容尺寸的偏移量. 往左偏移為正數(shù),往右偏移為負數(shù)


    41-26.png

UIScrollView和UITableView的偏移量正負詳解

  • UIScrollView偏移量:scrollView的左上角的值減去contentSize的左上角甸祭,就是contentOffset缕碎,偏移量(有正負)。contentSize(內(nèi)容尺寸)相對于scrollView向左移動池户,那么contentOffset就為正數(shù).向右移動咏雌,那么contentOffset就為負數(shù)。向上移動校焦,為正數(shù)赊抖,向下移動為負數(shù)
  • 計算正負數(shù)技巧:
  • contentSize(內(nèi)容尺寸)向左移動:contentOffset.x = 0 - (-100) = 100.
  • contentSize(內(nèi)容尺寸)向右移動:contentOffset.x = 0 - 200 = -200.
  • contentSize(內(nèi)容尺寸)向上移動:contentOffset.y = 0 - (-300) = 300.
  • contentSize(內(nèi)容尺寸)向上移動:contentOffset.y = 0 - 400 = - 400.
  • UITableView的偏移量:tableView的左上角的值減去contentSize的左上角,就是contentOffset寨典,偏移量(有正負)氛雪。contentSize(內(nèi)容尺寸)相對于tableView向左移動,那么contentOffset就為正數(shù).向右移動耸成,那么contentOffset就為負數(shù)报亩。向上移動,為正數(shù)井氢,向下移動為負數(shù)
  • 計算正負數(shù)技巧:
  • 同上

UIScrollView和UITableView滾動的是內(nèi)容而不是控件


  1.把圖片添加到UIScrollView上.本質(zhì)上是把圖片添加到了UIScrollView的內(nèi)容上弦追。
  我們滾動屏幕時,滾動的不是UIScrollView這個控件(窗口)花竞,滾動的是內(nèi)容.
  我們手動滾動內(nèi)容時(也可以利用代碼控制contentOffset的偏移量實現(xiàn)滾動內(nèi)容)劲件,圖片會經(jīng)過這個UIScrollView(窗口),經(jīng)過窗口的內(nèi)容會被我們看到约急。
  如果你認為圖片添加到了UIScrollView這個控件上零远,假設(shè)圖片添加到了UIScrollView控件的外側(cè)(屏幕的外側(cè)),這樣我們無論怎么滾動厌蔽,也永遠看不到這張圖片牵辣。因為UIScrollView此時就是一個供我們看東西的窗口,超過窗口的東西我們永遠看不到躺枕,你把圖片添加到了這個窗口的外側(cè)服猪,而不是添加到了內(nèi)容上供填,你滾動內(nèi)容時拐云,內(nèi)容里面并沒有圖片罢猪,內(nèi)容經(jīng)過窗口時,怎么會顯示這張圖片(UIScrollView就是窗口叉瘩,通過這個窗口我們才能看到圖片膳帕,超過這個窗口的圖片,我們永遠看不到薇缅。類比井底之蛙)

  2.為什么能滾動危彩?
  contentSize不能滾動,contentSize僅僅是提供了一個供我們滾動的矩形范圍泳桦。scrollView的內(nèi)容能滾動(前提:我們必須用手滾內(nèi)容啊汤徽,只要觸摸到了內(nèi)容,就能滾灸撰,底層幫我們做好了谒府,不要問為什么)。
  
  3. UIScrollView的內(nèi)容是啥浮毯,包括啥完疫? 內(nèi)容是虛擬的,我們看不到债蓝,但是實際存在壳鹤,如果你把2張圖片通過[self.scrollView addSubview:imageV];的形式添加到了內(nèi)容中,那么內(nèi)容就是兩張圖片饰迹。即芳誓,執(zhí)行addSubview:的操作,執(zhí)行addSubview:方法的參數(shù)就是內(nèi)容,

  4.如果你現(xiàn)在仍理解為把圖片添加到UIScrollView上啊鸭,你就無法理解滾動的誰锹淌?為什么能滾動?窗口是誰莉掂?contentSize的深層次含義葛圃?
  
  5.看UITableView動態(tài)截圖+ppt截圖你就理解UIScrollView了:UITableView控件并不能滾動,而是內(nèi)容能滾動憎妙。

UITableView的滾動

  • 前言:不受任何干擾來驗證TableView的ContentSize的范圍的做法是取消彈簧效果库正,這樣能滾動多少范圍就能滾動多少范圍。代碼:self.tableView.bounces =NO;
  • 以后見到任意一款app厘唾,如果里面有滾動的內(nèi)容褥符,你要想到之所以能滾動,是內(nèi)容滾動造成的抚垃,而不是UITableView的滾動喷楣,也不是UIScrollView的滾動趟大,也不是UICollectionView的滾動。他們?nèi)齻€只是提供一個窗口讓你滾動铣焊,超出這個而窗口我們就看不到窗口之外的內(nèi)容了逊朽。就像井底之蛙一樣,井口就是UITableView曲伊,是UIScrollView叽讳,是UICollectionView,是固定不動的坟募,天上的云彩就是內(nèi)容岛蚤,青蛙可以控制云彩的移動,青蛙就是人的手懈糯。內(nèi)容尺寸僅僅是提供了內(nèi)容所能滾動的范圍涤妒,
  • UITableView不設(shè)置ContentSize也能滾動,系統(tǒng)內(nèi)部幫我們算好了.所以開發(fā)中一般不設(shè)置
  • UIScrollView必須設(shè)置ContentSize才能滾動
  • ContentSize:內(nèi)容的 大小/尺寸赚哗,這個尺寸構(gòu)成了矩形她紫。就比如設(shè)置UIView的frame就決定了UIView的尺寸和位置
  • 內(nèi)容尺寸小于UITableView的尺寸(frame)是無法滾動的。你拖動時時能滾動蜂奸,但是松開手又彈回來了犁苏。這不是滾動哦。必須大于UITableView的尺寸才可以滾動的
//本質(zhì):所能滾動的內(nèi)容尺寸就是一個寬為100扩所,高位200的矩形
    tableView.contentSize = CGSizeMake(100, 200);
    
//類比UIScrollView設(shè)置滾動的內(nèi)容尺寸
    scrollView.contentSize = CGSizeMake(100, 200);

  • scrollView添加到控制器的view上.tableView添加到scrollView上
    • 兩個都是可以滾動的围详。
    • 可以實現(xiàn)scrollView負責左右滾動,tableView負責上下滾動祖屏。當移動scrollView時,里面的tableView會被移動到屏幕外助赞,當又移到屏幕內(nèi)時,可以保證這個tableView的內(nèi)容仍是之前的內(nèi)容
    • 為什么tableView添加到scrollView上袁勺?實際上是添加到scrollView的內(nèi)容尺寸上雹食。
      • 只有將5個tableView添加到scrollView上,左右滾動scrollView的內(nèi)容尺寸時期丰,才能顯示加到scrollView的內(nèi)容尺寸中TableView群叶,如果不加到scrollView上兼犯,那么左右滾動scrollView的內(nèi)容尺寸時从诲,因為scrollView中沒有添加任何數(shù)據(jù)大审,所以只會顯示水平指示條奠骄,垂直指示條。你不加到scrollView的內(nèi)容尺寸上维咸,scrollView中憑什么要展示你回懦?闽撤?

UITableView的屬性:frame端辱,ContentOffset梁剔,ContentInset虽画,ContentSize區(qū)分

  • 理解的前提:我們滾動的是內(nèi)容(cell,TableHeadView的高度荣病,TableFooterView高度等等)码撰,滾動的范圍是ContentSize的frame所形成的矩形。

  • frame:UITableView控件自身的尺寸(矩形)

  • ContentOffset: 內(nèi)容尺寸距離UITableView控件frame的偏移量众雷,ContentSize(矩形)往上偏移為正數(shù)灸拍,往下偏移為負數(shù)

  • ContentInset:內(nèi)邊距,即內(nèi)容尺寸周圍的間距做祝,即內(nèi)容尺寸周圍添加的邊距砾省,是無縫粘著內(nèi)容尺寸的邊緣。例如頂部增加100像素混槐,當拖動TableView的時候编兄,頂部可多拖動100像素,并且是永久多出100像素声登。不是拖到不能再拖的時候狠鸳,又彈回來的那種。

  • ContentSize:內(nèi)容尺寸的大小(寬,高)比如高為100,那么最終只能滾動100的范圍,超出滾動的范圍在停止拖拽之后由于彈簧效果會被彈回來(可以通過self.tableView.bounces =NO;禁止彈簧效果來驗證只能滾動100的范圍)悯嗓。UITableView不設(shè)置ContentSize也能滾動

    • 它的內(nèi)容尺寸的高度=所有cell的總高度+TableHeadView的高度+TableFooterView高度+sectionHeader的高度+sectionFooter的高度.記住:就是不包括內(nèi)邊距
    • ContentInset和TableHeadView和TableFooterView都是緊緊粘著內(nèi)容尺寸的邊緣件舵,如果都存在,那么ContentInset緊貼著TableHeadView的上部脯厨,緊貼著TableFooterView的底部铅祸。因為TableHeadView和TableFooterView屬于內(nèi)容尺寸的一部分
    • 在手機上用戶滾動時,我們拿著6s Plus在(414, 736)尺寸的屏幕上滾動合武,滾動的是ContentSize所形成的矩形
    • 注意:ContentSize只是用來設(shè)置矩形的大小的临梗。我們滾動的形成的這個矩形,這個矩形是看不到的稼跳,所以會誤讓我們以為滾動的是UITableView盟庞。
  • UITableView的frame所形成的是個矩形,ContentSize形成的也是個矩形汤善。這兩個矩形的左上角的差值就是偏移量

  • ContentSize和內(nèi)邊距是分開的
    • 之所以讓內(nèi)容尺寸的高度等于內(nèi)容的高度的原因:
      • 內(nèi)容尺寸決定滾動的范圍什猖,只有兩者相等,才能確保內(nèi)容都能全部讓我們滾動到红淡。本質(zhì)上內(nèi)容尺寸和內(nèi)容高度一點關(guān)系都沒有不狮,只是我們手讓他們產(chǎn)生了關(guān)系
    • 計算tableView內(nèi)容尺寸的大小(congtentsize)和內(nèi)邊距一點關(guān)系都沒有,內(nèi)邊距不參與計算tableView內(nèi)容的大小
      • 根據(jù)上面的公式:內(nèi)容的高度=所有cell的總高度+TableHeadView的高度+TableFooterView高度+sectionHeader的高度+sectionFooter的高度.記住:就是不包括內(nèi)邊距锉屈。
      • 通過 內(nèi)容尺寸的高度=所有cell的總高度+TableHeadView的高度+TableFooterView高度+sectionHeader的高度+sectionFooter的高度.記住:就是不包括內(nèi)邊距荤傲。 來確保內(nèi)容都能全部讓我們滾動到
    • 計算偏移量(contentoffset)和內(nèi)邊距(contentInset)沒有關(guān)系,內(nèi)邊距不參與計算偏移量的多少颈渊。
      • 因為偏移量是=內(nèi)容距UITableView控件frame的偏移量遂黍,又因為內(nèi)容不包括內(nèi)邊距终佛,UITableView控件frame只和自己的本身有關(guān)系,所以說偏移量和內(nèi)邊距一點關(guān)系都沒有

沒有cell雾家,沒有contentInset铃彰,沒有TableHeadView、TableHeaderView的情況

  • 內(nèi)容的高度=所有cell的總高度+TableHeadView的高度+TableFooterView高度+sectionHeader的高度+sectionFooter的高度.記住:就是不包括內(nèi)邊距芯咧。
  • 通過 內(nèi)容尺寸的高度=所有cell的總高度+TableHeadView的高度+TableFooterView高度+sectionHeader的高度+sectionFooter的高度.記住:就是不包括內(nèi)邊距牙捉。 來確保內(nèi)容都能全部讓我們滾動到
#import "ViewController.h"

@interface ViewController () <UITableViewDelegate>
@property (nonatomic, weak) UITableView *tableView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITableView *tableView = [[UITableView alloc] init];
    tableView.frame = CGRectMake(100, 100, 200, 300);
    tableView.backgroundColor = [UIColor grayColor];
    tableView.delegate = self;
    tableView.rowHeight = 40;
    [self.view addSubview:tableView];
    self.tableView = tableView;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"contentSize.height = %f", self.tableView.contentSize.height);
}
#pragma mark - UITableViewDelegate
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    return 0;

}
@end

  • 截圖
41-06.gif
  • ppt截圖
41-16.png

有cell,沒有contentInset敬飒,沒有TableHeadView邪铲、TableHeaderView的情況

  • 內(nèi)容的高度=所有cell的總高度+TableHeadView的高度+TableFooterView高度+sectionHeader的高度+sectionFooter的高度.記住:就是不包括內(nèi)邊距。
  • 通過 內(nèi)容尺寸的高度=所有cell的總高度+TableHeadView的高度+TableFooterView高度+sectionHeader的高度+sectionFooter的高度.記住:就是不包括內(nèi)邊距无拗。 來確保內(nèi)容都能全部讓我們滾動到
#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITableView *tableView = [[UITableView alloc] init];
    tableView.frame = CGRectMake(100, 100, 200, 300);
    tableView.backgroundColor = [UIColor grayColor];
    tableView.dataSource = self;
    tableView.delegate = self;
    tableView.rowHeight = 40;
    
    [self.view addSubview:tableView];
    
    
}


#pragma mark - <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"\t內(nèi)容尺寸的偏移量y:contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"\t內(nèi)容尺寸的高度:contentSize.height = %f", tableView.contentSize.height);
}

#pragma mark - 數(shù)據(jù)源
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end

  • 運行結(jié)果
    • 點擊cell带到,提示偏移量為0,內(nèi)容尺寸的高度為800.這個800是20個cell 的總高度
41-07.gif
  • ppt截圖
41-17.png

有cell英染,有contentInset揽惹,沒有TableHeadView、TableHeaderView的情況

#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITableView *tableView = [[UITableView alloc] init];
    tableView.frame = CGRectMake(100, 100, 200, 300);
    tableView.backgroundColor = [UIColor grayColor];
    tableView.dataSource = self;
    tableView.delegate = self;
    tableView.rowHeight = 40;
    [self.view addSubview:tableView];
    
    // 內(nèi)邊距
    //距tableView內(nèi)容尺寸頂部的距離為64四康,距tableView內(nèi)容尺寸底部的距離為49搪搏。即停止拖動時候頂部多出64的距離,底部多出49的距離,永久性的多出這些距離闪金。
    tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);
    


}

#pragma mark - <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"\t內(nèi)容尺寸的偏移量y:contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"\t內(nèi)容尺寸的高度:contentSize.height = %f", tableView.contentSize.height);
}

#pragma mark - 數(shù)據(jù)源
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end





  • 截圖
41-08.gif
  • ppt截圖
41-18.png
詳情分析:
  • tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);//頂部內(nèi)邊距64疯溺,底部內(nèi)邊距49
  • 程序運行時,因為距tableView內(nèi)容尺寸頂部的距離為64毕泌,距tableView內(nèi)容尺寸底部的距離為49喝检。即停止拖動時候頂部多出64的距離,底部多出49的距離(永久多出的距離撼泛,不恢復)挠说。程序初始運行時顯示的控件的狀態(tài)也就相當于停止拖動的時候的狀態(tài)。
  • 先把控件顯示到指定的位置上愿题,然后才計算偏移量和內(nèi)容尺寸的高度
    • 點擊cell 提示800.說明self.tableView.contentSize.height這個內(nèi)容尺寸的高度的計算不包括計算contentInset损俭,
    • 點擊cell,執(zhí)行 NSLog(@"contentOffset.y = %f", tableView.contentOffset.y);打印偏移量為-64.因為contentInse不是contentSize的一部分潘酗。再加上UITableView矩形框的左上角和contentSize矩形框的左上角不重合杆兵,即有差值,所以有偏移量仔夺。

有cell琐脏,沒有contentInset,有TableHeadView、TableHeaderView的情況

#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITableView *tableView = [[UITableView alloc] init];
    tableView.frame = CGRectMake(100, 100, 200, 300);
    tableView.backgroundColor = [UIColor grayColor];
    tableView.dataSource = self;
    tableView.delegate = self;
    tableView.rowHeight = 40;
    [self.view addSubview:tableView];
    
    // header - footer
    UIView *header = [[UIView alloc] init];
    header.frame = CGRectMake(0, 0, tableView.frame.size.width, 64);
    header.backgroundColor = [UIColor yellowColor];
    tableView.tableHeaderView = header;
    
    UIView *footer = [[UIView alloc] init];
    footer.frame = CGRectMake(0, 0, tableView.frame.size.width, 49);
    footer.backgroundColor = [UIColor greenColor];
    tableView.tableFooterView = footer;

}



#pragma mark - <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"\t內(nèi)容尺寸的偏移量y:contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"\t內(nèi)容尺寸的高度:contentSize.height = %f", tableView.contentSize.height);
}

#pragma mark - 數(shù)據(jù)源
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end


  • 截圖
41-09.gif
  • ppt截圖
41-19.png
詳情分析:
  • 點擊cell日裙,提示913吹艇,說明800+64+49=913,說明self.tableView.contentSize.height這個內(nèi)容尺寸的高度的計算包括計算tableHeaderView和tableFooterView的高度
  • 點擊cell昂拂,執(zhí)行 NSLog(@"contentOffset.y = %f", tableView.contentOffset.y);打印偏移量為0.說明因為tableHeaderView和tableFooterView都是contentSize的一部分

有cell受神,有contentInset,有TableHeadView格侯、TableHeaderView的情況

#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITableView *tableView = [[UITableView alloc] init];
    tableView.frame = CGRectMake(100, 100, 200, 300);
    tableView.backgroundColor = [UIColor grayColor];
    tableView.dataSource = self;
    tableView.delegate = self;
    tableView.rowHeight = 40;
    [self.view addSubview:tableView];

    
    // 內(nèi)邊距
    //距tableView內(nèi)容尺寸頂部的距離為64鼻听,距tableView內(nèi)容尺寸底部的距離為49。即停止拖動時候頂部多出64的距離联四,底部多出49的距離撑碴。
    tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);
    
    // header - footer
    UIView *header = [[UIView alloc] init];
    header.frame = CGRectMake(0, 0, tableView.frame.size.width, 64);
    header.backgroundColor = [UIColor yellowColor];
    tableView.tableHeaderView = header;
    
    UIView *footer = [[UIView alloc] init];
    footer.frame = CGRectMake(0, 0, tableView.frame.size.width, 49);
    footer.backgroundColor = [UIColor greenColor];
    tableView.tableFooterView = footer;
    
}


#pragma mark - <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"\t內(nèi)容尺寸的偏移量y:contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"\t內(nèi)容尺寸的高度:contentSize.height = %f", tableView.contentSize.height);
}

#pragma mark - 數(shù)據(jù)源
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end

  • 截圖
41-10.gif
  • ppt截圖
41-20.png
詳情分析:
  • 點擊cell,偏移量為-64碎连,內(nèi)容尺寸的高度為913.只是UIScrollVIew的位置和之前的位置不一樣了灰羽。

有cell,沒有contentInset鱼辙,沒有TableHeadView、TableHeaderView玫镐,有額外添加的子控件{0, -40, 375, 40}

#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITableView *tableView = [[UITableView alloc] init];
    tableView.frame = CGRectMake(100, 100, 200, 300);
    tableView.backgroundColor = [UIColor grayColor];
    tableView.dataSource = self;
    tableView.delegate = self;
    tableView.rowHeight = 40;
    
    [self.view addSubview:tableView];
    
    
    // 額外添加的子控件 會顯示在TableVIew的內(nèi)部
    UIView *zb = [[UIView alloc] init];
    zb.frame = CGRectMake(0, -40, tableView.frame.size.width, 40);
    zb.backgroundColor = [UIColor blueColor];
    [tableView addSubview:zb];
}

#pragma mark - <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"\t內(nèi)容尺寸的偏移量y:contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"\t內(nèi)容尺寸的高度:contentSize.height = %f", tableView.contentSize.height);
}

#pragma mark - 數(shù)據(jù)源
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end

  • 截圖
41-11.gif
  • ppt截圖
41-21.png
詳情分析:
  • zb這個view添加到TableView上倒戏,那么zb的父控件是UITableView還是UITableView的內(nèi)容呢?
  • frame是指:以父控件的內(nèi)容尺寸的左上角為坐標原點恐似。所以zb是添加到UITableView的內(nèi)容上杜跷。即zb是以父控件的內(nèi)容尺寸的左上角為坐標原點
    所以當我們滾動內(nèi)容尺寸的時候,添加的這個zb著滾動矫夷,如果我們認為是添加到UITableView上葛闷,UIableView始終是固定不變的,zb以父控件的坐標原點為原點双藕,因為UITableView一直不變淑趾,所以UITableView的坐標原點也一致不變,那么zb一直不變忧陪。當我們滾動內(nèi)容尺寸的時候扣泊,zb應(yīng)當是不移動的。 但是真實情況是嘶摊,zb會移動延蟹,所以我們認為的是錯的。所zb到內(nèi)容尺寸中
  • 向下拖動+gif動畫超級好演示 可以看到拖出來一個藍色的view叶堆,就是zb阱飘,松手之后又彈回去了,看不見了
  • 偏移量為0,內(nèi)容尺寸為800.所以內(nèi)容尺寸不計算子控件的40沥匈」迹可以看看內(nèi)容尺寸的計算公式,公式中沒有子控件這個變量咐熙,所以不計算弱恒。以后跟著這個公司來就很好理解滾動的TableView了

有cell,有contentInset棋恼,沒有TableHeadView返弹、TableHeaderView,有額外添加的子控件{0, -40, 375, 40}

#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITableView *tableView = [[UITableView alloc] init];
    tableView.frame = CGRectMake(100, 100, 200, 300);
    tableView.backgroundColor = [UIColor grayColor];
    tableView.dataSource = self;
    tableView.delegate = self;
    tableView.rowHeight = 40;
    [self.view addSubview:tableView];
    // 內(nèi)邊距
    //距tableView內(nèi)容尺寸頂部的距離為64爪飘,距tableView內(nèi)容尺寸底部的距離為49义起。即停止拖動時候頂部多出64的距離,底部多出49的距離师崎。
    tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);
  
    // 額外添加的子控件 會顯示在TableVIew的內(nèi)部
    UIView *header = [[UIView alloc] init];
    header.frame = CGRectMake(0, -40, tableView.frame.size.width, 40);
    header.backgroundColor = [UIColor blueColor];
    [tableView addSubview:header];
}

#pragma mark - <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"\t內(nèi)容尺寸的偏移量y:contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"\t內(nèi)容尺寸的高度:contentSize.height = %f", tableView.contentSize.height);
}

#pragma mark - 數(shù)據(jù)源
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end
  • 截圖


    41-12.gif
  • ppt截圖
41-22.png
詳細分析:
  • 運行時默终,頂部內(nèi)邊距我64,有40被藍色的子控件擋住
  • 精華理解:contentInset先占據(jù)64犁罩,把ContentSize擠下去64齐蔽,然后藍色的子控件添加到ContentSize的頂部(被擠下去的頂部)

有cell,沒有contentInset床估,有TableHeadView含滴、TableHeaderView,有額外添加的子控件{0, -40, 375, 40}


#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, weak) UITableView *tableView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITableView *tableView = [[UITableView alloc] init];
    tableView.frame = CGRectMake(100, 100, 200, 300);
    tableView.backgroundColor = [UIColor grayColor];
    tableView.dataSource = self;
    tableView.delegate = self;
    tableView.rowHeight = 40;

    [self.view addSubview:tableView];
    self.tableView = tableView;

    // header - footer
    UIView *header = [[UIView alloc] init];
    header.frame = CGRectMake(0, 0, tableView.frame.size.width, 64);
    header.backgroundColor = [UIColor yellowColor];
    tableView.tableHeaderView = header;
    
    UIView *footer = [[UIView alloc] init];
    footer.frame = CGRectMake(0, 0, tableView.frame.size.width, 49);
    footer.backgroundColor = [UIColor greenColor];
    tableView.tableFooterView = footer;
    
    // 額外添加的子控件 會顯示在TableVIew的內(nèi)部
    UIView *zb = [[UIView alloc] init];
    zb.frame = CGRectMake(0, -40, tableView.frame.size.width, 40);
    zb.backgroundColor = [UIColor blueColor];
    [tableView addSubview:zb];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"\n \n 內(nèi)容尺寸的高度:contentSize.height = %f", self.tableView.contentSize.height);
}

#pragma mark - <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"\t內(nèi)容尺寸的偏移量y:contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"\t內(nèi)容尺寸的高度:contentSize.height = %f", tableView.contentSize.height);
}

#pragma mark - 數(shù)據(jù)源
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end


  • 截圖
41-13.gif
  • ppt截圖
41-23.png

有cell丐巫,有contentInset谈况,有TableHeadView、TableHeaderView递胧,有額外添加的子控件{0, -40, 375, 40}

#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITableView *tableView = [[UITableView alloc] init];
    tableView.frame = CGRectMake(100, 100, 200, 300);
    tableView.backgroundColor = [UIColor grayColor];
    tableView.dataSource = self;
    tableView.delegate = self;
    tableView.rowHeight = 40;
    [self.view addSubview:tableView];

    
    // 內(nèi)邊距
        //距tableView內(nèi)容尺寸頂部的距離為64碑韵,距tableView內(nèi)容尺寸底部的距離為49。即停止拖動時候頂部多出64的距離缎脾,底部多出49的距離祝闻。
    tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);
    
    // header - footer
    UIView *header = [[UIView alloc] init];
    header.frame = CGRectMake(0, 0, tableView.frame.size.width, 64);
    header.backgroundColor = [UIColor yellowColor];
    tableView.tableHeaderView = header;
    
    UIView *footer = [[UIView alloc] init];
    footer.frame = CGRectMake(0, 0, tableView.frame.size.width, 49);
    footer.backgroundColor = [UIColor greenColor];
    tableView.tableFooterView = footer;

    // 額外添加的子控件 會顯示在TableVIew的內(nèi)部
    UIView *zb = [[UIView alloc] init];
    zb.frame = CGRectMake(0, -40, tableView.frame.size.width, 40);
    zb.backgroundColor = [UIColor blueColor];
    [tableView addSubview:zb];
}



#pragma mark - <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"\t內(nèi)容尺寸的偏移量y:contentOffset.y = %f", tableView.contentOffset.y);
    NSLog(@"\t內(nèi)容尺寸的高度:contentSize.height = %f", tableView.contentSize.height);}

#pragma mark - 數(shù)據(jù)源
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
   
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"%@-%zd", self.class, indexPath.row];
    return cell;
}
@end
  • 截圖
41-15.gif
  • ppt截圖
41-24.png

沒有cell,沒有contentInset赊锚,有TableHeadView治筒、TableHeaderView,沒有有額外添加的子控件{0, -40, 375, 40}

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, weak) UITableView *tableView;
@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  
  UITableView *tableView = [[UITableView alloc] init];
  tableView.frame = CGRectMake(100, 100, 200, 300);
  tableView.backgroundColor = [UIColor grayColor];
  tableView.rowHeight = 40;

  [self.view addSubview:tableView];
  self.tableView = tableView;

  // header - footer
  UIView *header = [[UIView alloc] init];
  header.frame = CGRectMake(0, 0, tableView.frame.size.width, 64);
  header.backgroundColor = [UIColor yellowColor];
  tableView.tableHeaderView = header;
  
  UIView *footer = [[UIView alloc] init];
  footer.frame = CGRectMake(0, 0, tableView.frame.size.width, 49);
  footer.backgroundColor = [UIColor greenColor];
  tableView.tableFooterView = footer;

}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
  NSLog(@"\t內(nèi)容尺寸的高度:contentSize.height = %f", self.tableView.contentSize.height);
}

@end

  • 截圖
41-14.gif
  • ppt截圖
41-25.png

詳細分析:

點擊控制器的touchbegan 打印113舷蒲,就是64+49=113. 并且拖動內(nèi)容尺寸耸袜,脫完松手,又會彈回來牲平,因為內(nèi)容尺寸小于UITableView的尺寸


精華截圖動畫

43-01.gif

全屏穿透效果知識點:

  • 讓TableView的frame為窗口的大小堤框。

  • 為每個TableView在頂部添加內(nèi)間距,距離為=狀態(tài)欄+導航欄+標題欄。為每個TableView在底部添加內(nèi)邊距蜈抓,距離為=tabBar的高度(49)
    self.tableView.contentInset = UIEdgeInsetsMake(ZBNavBarMaxY+ZBTitlesViewH, 0, ZBTabBarH, 0);

  • 隱藏滾動條
    self.tableView.scrollIndicatorInsets = self.tableView.contentInset;

  • 既能穿透導航欄启绰,又能讓底部的tabbar不擋住最下面的cell的做法
    給tableView在上下增加內(nèi)邊距,滑動到最下方沟使,由下方的內(nèi)邊距頂著委可,所以最下面的cell不會被擋住

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市腊嗡,隨后出現(xiàn)的幾起案子着倾,更是在濱河造成了極大的恐慌,老刑警劉巖燕少,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卡者,死亡現(xiàn)場離奇詭異,居然都是意外死亡客们,警方通過查閱死者的電腦和手機崇决,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來底挫,“玉大人恒傻,你說我怎么就攤上這事∑喔遥” “怎么了碌冶?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長涝缝。 經(jīng)常有香客問我,道長譬重,這世上最難降的妖魔是什么拒逮? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮臀规,結(jié)果婚禮上滩援,老公的妹妹穿的比我還像新娘。我一直安慰自己塔嬉,他們只是感情好玩徊,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谨究,像睡著了一般恩袱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上胶哲,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天畔塔,我揣著相機與錄音,去河邊找鬼。 笑死澈吨,一個胖子當著我的面吹牛把敢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谅辣,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼修赞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了桑阶?” 一聲冷哼從身側(cè)響起柏副,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎联逻,沒想到半個月后搓扯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡包归,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年锨推,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片公壤。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡换可,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出厦幅,到底是詐尸還是另有隱情沾鳄,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布确憨,位于F島的核電站译荞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏休弃。R本人自食惡果不足惜吞歼,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望塔猾。 院中可真熱鬧篙骡,春花似錦、人聲如沸丈甸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睦擂。三九已至得湘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祈匙,已是汗流浹背忽刽。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工天揖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人跪帝。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓今膊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親伞剑。 傳聞我的和親對象是個殘疾皇子斑唬,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件黎泣、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,022評論 4 62
  • 作者:Olivier Halligon恕刘,原文鏈接,原文日期:2016-02-28譯者:ray16897188抒倚;校對...
    梁杰_numbbbbb閱讀 417評論 0 3
  • 此文章是為了簡單地實現(xiàn)等高的兩欄布局褐着,目標效果如下圖1。下面將介紹3種實現(xiàn)方式(inline-block,tabl...
    faye0907閱讀 2,662評論 1 3
  • 癡緣 青色長空現(xiàn)驚鴻,猶似七仙踏云歸托呕。 凡夫董永癡心等,婉若冰霜不知回含蓉。
    crazy石頭閱讀 156評論 0 0
  • 我在期待著一場雪。不知為什么项郊,我總覺得冬天不下一場雪是無論如何都說不過去的馅扣。媽媽說,大冬都過去了這天還不冷着降,怕是...
    淺淺城府閱讀 277評論 0 0