edgesForExtendedLayout、contentInsetAdjustmentBehavior等几个属性

3,836 阅读4分钟
  • edgesForExtendedLayout

平常我们开发的界面的大部分时候都是需要导航栏或tabbar的,或者两个都需要,导航栏的高度在iphoneX出来之前的设备上是64pt(状态栏20pt,navigationBar的高度为44pt),tabbar的高度为49pt(暂先不考虑tabbar和iPhoneX之后的底部安全高度的情况下),所以大部分时候我们显示的内容的高度都是屏幕的高度减去导航栏和(或)tabbar的高度。 edgesForExtendedLayout作为控制器UIViewController的属性,可以设置该控制器的view是否在导航栏或者tabbar的下边。edgesForExtendedLayout是枚举类型,上、下、左、右、全没和全有。

@property(nonatomic,assign) UIRectEdge edgesForExtendedLayout NS_AVAILABLE_IOS(7_0); // Defaults to UIRectEdgeAll

typedef NS_OPTIONS(NSUInteger, UIRectEdge) {
    UIRectEdgeNone   = 0,
    UIRectEdgeTop    = 1 << 0,
    UIRectEdgeLeft   = 1 << 1,
    UIRectEdgeBottom = 1 << 2,
    UIRectEdgeRight  = 1 << 3,
    UIRectEdgeAll    = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight
} NS_ENUM_AVAILABLE_IOS(7_0);

window的根控制器是导航栏,导航栏的根控制器是tabbar,tabbar有两个控制器。示例代码如下。

- (void)navTabbar
{
    ViewController *vc = [[ViewController alloc]init];
    SecController *sec = [[SecController alloc]init];
    UITabBarController *tab = [[UITabBarController alloc]init];
    //tab.edgesForExtendedLayout = UIRectEdgeNone;
    tab.viewControllers = @[vc,sec];
    UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:tab];
    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = nav;
    [self.window makeKeyAndVisible];
}

以上代码中,tab.edgesForExtendedLayout = UIRectEdgeNone;vc.edgesForExtendedLayout = UIRectEdgeNone;将两个控制器的edgesForExtendedLayout都设为全无的时候,即tabVC的view的顶部不被导航栏遮挡,vc的view的底部不被tabbar遮挡,这样,最终在我们显示的界面上,vc.view的frame就是frame = (0 0; 375 554);如果两个都设为全有的情况下,即相应的view位于被其容器控制器下边。vc.view的frame就是frame = (0 0; 375 667)

如图: 注:绿色的视图是vc.view.

在iphone6模拟器上的效果:左边为UIRectEdgeAll,右边为 UIRectEdgeNone。对应的vc.view的frame分别为:左边frame = (0 0; 375 667),右边frame = (0 0; 375 554)【屏幕高667-64-49】。

在iphoneX模拟器上的效果:左边为UIRectEdgeNone,右边为 UIRectEdgeAll。对应的vc.view的frame分别为:左边:frame = (0 0; 375 641)【屏幕高812-88-49-34】;右边frame = (0 0; 375 812)。
有一点需要注意的是:如果将navigationBar和tabBar的translucent(半透明)属性都设置为NO的话,即便将控制器的edgesForExtendedLayout都设置为UIRectEdgeAll,最终控制器的view还是不会在navigationBar和tabBar的下边。

vc.navigationController.navigationBar.translucent = NO;
vc.tabBarController.tabBar.translucent = NO;

在storyBoard中的设置如下图:

  • contentInsetAdjustmentBehaviorautomaticallyAdjustsScrollViewInsets
/* Configure the behavior of adjustedContentInset.
 Default is UIScrollViewContentInsetAdjustmentAutomatic.
 */
@property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior API_AVAILABLE(ios(11.0),tvos(11.0));

contentInsetAdjustmentBehavior是iOS11.0之后的UIScrollView及其子类的 属性,默认值是UIScrollViewContentInsetAdjustmentAutomatic。是用来设置scrollView在控制器上的适配内边距。即scrollView的显示的内容是否被导航栏及tabBar遮挡。automaticallyAdjustsScrollViewInsets(默认是YES)是iOS11之前(现在已经废弃)的UIViewController的属性,其作用与contentInsetAdjustmentBehavior相似,设置控制器上的UIScrollView是否被遮挡。

以下示例代码的效果如下边的截图

//window及根控制器的设置
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ViewController *vc = [[ViewController alloc]init];
    SecController *sec = [[SecController alloc]init];
    UITabBarController *tab = [[UITabBarController alloc]init];
    tab.viewControllers = @[vc,sec];
    UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:tab];
    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = nav;
    [self.window makeKeyAndVisible];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    if (@available(iOS 11.0, *)) {
        self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic;
    } else {
        self.automaticallyAdjustsScrollViewInsets =  YES;
    }
}
//tableView的frame的设置
    - (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    self.tableView.frame = self.view.bounds;
}

(1): iOS 10.0的iphone6的模拟器的效果

由上边的效果图可以看出,当设置控制器的automaticallyAdjustsScrollViewInsets的属性是YES的时候,tableView的上部不会被遮挡,从控制台打印结果可以看出,其contentInset的top为64;即顶部留出了64的内边距。但是下边依然被tabBar遮挡,从动图看也是有一行cell被遮盖了,控制台的打印结果也显示下边没有内边距。看来如果想要tableView的下边不被tabBar遮挡,需要设置控制器的edgesForExtendedLayout或者设置计算好的tableView的frame。更方便的是用autolayout

(2): iOS 12.2的iphoneX的模拟器效果

从图上效果看出,在iOS11.0之后,将tableView的contentInsetAdjustmentBehavior设置为UIScrollViewContentInsetAdjustmentAutomatic后,tabelView的上边和下边都不会被遮挡,从控制台打印看出tableView的frame虽然是屏幕的高度,但是偏移量contentOffset是-88,而且在iOS11.0之后,UIScrollView增加了一个属性adjustedContentInset适配后的内边距。看打印结果显示tableView的适配后内边距上下分别是88和83,从而避免上下被遮挡。

/* When contentInsetAdjustmentBehavior allows, UIScrollView may incorporate
 its safeAreaInsets into the adjustedContentInset.
 */
@property(nonatomic, readonly) UIEdgeInsets adjustedContentInset API_AVAILABLE(ios(11.0),tvos(11.0));

如有错误,欢迎指出。 未完待续……