前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS小技能:适配安全区域距离(safeAreaInsets)

iOS小技能:适配安全区域距离(safeAreaInsets)

作者头像
公众号iOS逆向
发布2022-08-22 12:36:51
4.1K0
发布2022-08-22 12:36:51
举报
文章被收录于专栏:iOS逆向与安全

引言

应用场景1:自定义导航栏内容,导航栏显示公告和标题

应用场景2:自定义视图底部工具栏

应用场景3: 适配上拉加载更多控件 _vcView.tableView.mj_footer.ignoredScrollViewContentInsetBottom = k_ignoredScrollViewContentInsetBottom;

代码语言:javascript
复制
//推荐使用API获取高度
#define k_safeAreaInsetsBottom [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom
#define isIphoneX isHasSafeAreaInsets
#define k_ignoredScrollViewContentInsetBottom (isIphoneX?k_safeAreaInsetsBottom:0)
static inline BOOL isIPhoneXSeries() {
    if (@available(iOS 11.0, *)) {
        UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
        if (mainWindow.safeAreaInsets.bottom > 0.0) {
            return YES;
        }
    }
    return NO;
}


I 适配安全区域距离

The safe area of a view reflects the area not covered by navigation bars, tab bars, toolbars, and other ancestors that obscure a view controller's view. (In tvOS, the safe area reflects the area not covered by the screen's bezel.) You obtain the safe area for a view by applying the insets in this property to the view's bounds rectangle. If the view is not currently installed in a view hierarchy, or is not yet visible onscreen, the edge insets in this property are 0. safeArea是指没有被导航栏, tabbar栏, toolbars, 或其他视图遮盖的区域。 通过safeAreaInsets属性可以获取到视图的安全距离. 但是如果一个view没有在视图层次结构中或未在屏幕上显示, 则safeAreaInsets为0;

1.1 问题

视图底部工具栏显示到安全区域之外

1.2 判断安全区域距离

代码语言:javascript
复制
#define isIphoneX [QCT_Common isiPhoneX]

+ (BOOL)isiPhoneX {
    

        if (@available(iOS 11.0, *)) {
            if ([UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom > 0) {//iphoneX横屏
                 return  YES;
                
            } else {
                return  NO;
                
            }
            
        } else {
            
            return NO;
        }
    
    

}


定义相应宏

代码语言:javascript
复制

///*状态栏和导航栏总高度*/
#define kStatusBarHeight (CGFloat)(isIphoneX?(88.0):(64.0))
/*iPhoneX的状态栏高度差值*/
#define kPtatusBarHeight (CGFloat)(isIphoneX?(24.0):(0))
/*底部安全区域远离高度*/
#define kDtatusBarHeight (CGFloat)(isIphoneX?(34.0):(0))
//推荐使用API获取高度
#define k_safeAreaInsetsBottom [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom
#define isIphoneX isHasSafeAreaInsets
#define k_ignoredScrollViewContentInsetBottom (isIphoneX?k_safeAreaInsetsBottom:0)


推荐使用API获取高度

代码语言:javascript
复制

#define kstatusBarH [[UIApplication sharedApplication] statusBarFrame].size.height


#define knavHeight  self.navigationController.navigationBar.frame.size.height


//获取状态栏的高度
CGFloat statusHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
NSLog(@"状态栏高度:%f",statusHeight);

//获取导航栏的高度
CGFloat navHeight = self.navigationController.navigationBar.frame.size.height;
NSLog(@"导航栏高度:%f",navHeight);

//获取tabBar的高度
//1.在tabBarController中使用(你的继承自UITabBarController的VC)
CGFloat tabBarHeight = self.tabBar.frame.size.height;
NSLog(@"tabBar高度:%f",tabBarHeight);
//2.在非tabBarController中使用
UITabBarController *tabBarVC = [[UITabBarController alloc] init];//(这儿取你当前tabBarVC的实例)
CGFloat tabBarHeight = tabBarVC.tabBar.frame.size.height;
NSLog(@"tabBar高度:%f",tabBarHeight);

1.3 使用static inline方式编译函数,防止静态分析

使用inline方式将函数在调用处强制展开,防止被hook和追踪符号。

代码语言:javascript
复制
static __attribute__((always_inline)) void anti_debug()
//一般的函数调用都会通过call的方式来调用,hacker很容易对一个函数做手脚,如果是以inline的方式编译的,会把该函数的code拷贝到每次调用该函数的地方;而static会让生成的二进制文件中没有清晰的符号表,让逆向的人很难弄清楚代码逻辑

查看汇编文件:选中xx.m文件-->Xcode 菜单 --> Product --> Perform Action --> Assemble "xx.m"

与#define的区别:

  1. 使用#define宏定义的代码,编译器不会对其进行参数有效性检查,仅仅只是对符号表进行替换。
  2. #define宏定义的代码,其返回值不能被强制转换成可转换的适合的类型。

应用到本文案例

代码语言:javascript
复制
static inline BOOL isIPhoneXSeries() {
    if (@available(iOS 11.0, *)) {
        UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
        if (mainWindow.safeAreaInsets.bottom > 0.0) {
            return YES;
        }
    }
    return NO;
}

II 应用场景

2.1 应用场景1:自定义导航栏

代码语言:javascript
复制
///*状态栏和导航栏总高度*/
#define kStatusBarHeight (CGFloat)(isIphoneX?(88.0):(64.0))
    navView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, kWidth, kStatusBarHeight)];

2.2 应用场景2:自定义视图底部工具栏

自定义视图底部工具栏显示到安全区域之外

如果有安全区域距离,则视图距离底部的高度进行相应调整

代码语言:javascript
复制
        [_vcView mas_makeConstraints:^(MASConstraintMaker *make) {
            
            make.top.left.right.offset(0);
            
            if(isHasSafeAreaInsets()){
                UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
                CGFloat bottom = mainWindow.safeAreaInsets.bottom;
                
                
                make.bottom.equalTo(weakSelf.view).offset(-bottom);

            }else{
                make.bottom.equalTo(weakSelf.view);

            }
            
            
        }];

2.3 应用场景3: 适配上拉加载更多控件

问题:没有上拉的时候加载更多控件的文案也显示出来了

修复方式1:修改视图距离底部的高度

代码语言:javascript
复制
    [self.vcView mas_makeConstraints:^(MASConstraintMaker *make) {
        
        make.left.equalTo(weakSelf.view).offset(0);
        make.right.equalTo(weakSelf.view).offset(- 0);
        make.top.equalTo(weakSelf.view).offset(0);
        if(isHasSafeAreaInsets()){// 避免没有上拉的时候加载更多控件的文案也显示出来了
            UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
            CGFloat bottom = mainWindow.safeAreaInsets.bottom;
            make.bottom.equalTo(weakSelf.view).offset(bottom);

        }else{
            make.bottom.equalTo(weakSelf.view);
        }
        
        
    }];
    

修复方式2:修改上拉加载控件距离底部的高度 【推荐】

代码语言:javascript
复制

/** 忽略多少scrollView的contentInset的bottom */
//@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetBottom;

            UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
            CGFloat bottom = mainWindow.safeAreaInsets.bottom;//34
_tableView.mj_footer.ignoredScrollViewContentInsetBottom = isIphoneX ? bottom : 0;

适配之后的效果

如果是第三方库建议升级最新版本,比如我把MJRefresh3.1.16升级至3.7.5

代码语言:javascript
复制
  pod 'MJRefresh' , '3.7.5'
  -> Installing MJRefresh 3.7.5 (was 3.1.16)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOS逆向 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • I 适配安全区域距离
    • 1.1 问题
      • 1.2 判断安全区域距离
        • 1.3 使用static inline方式编译函数,防止静态分析
        • II 应用场景
          • 2.1 应用场景1:自定义导航栏
            • 2.2 应用场景2:自定义视图底部工具栏
              • 2.3 应用场景3: 适配上拉加载更多控件
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档