关于iOS 11 部分适配

本文介绍如何针对iPhoneX的特殊屏幕尺寸进行适配,并提供了在iOS11中处理UIScrollView偏移及UINavigationBar自定义按钮点击区域的具体解决方案。

一、关于iPhone X适配

//是否是iPhone X
#define kIsiPhoneX (UIScreen.mainScreen.bounds.size.height == 812 || UIScreen.mainScreen.bounds.size.width == 812)

//状态栏高度
#define kStatusBarHeight (kIsiPhoneX?44:20)

//底部增加高度
#define kBottomBarAddHeight (kIsiPhoneX?kAVMBottomBarAddHeight_iPhoneX:0) 

//底部tabbar iPhoneX 增加高度 34
static CGFloat kBottomBarAddHeight_iPhoneX = 34.f;

//设置iPhone X的scrollView 底部扩展34
#define kUIScrollViewiPhoneX(scrollView) if (kIsiPhoneX) {\
    scrollView.contentInset = UIEdgeInsetsMake(0, 0, kAVMBottomBarAddHeight_iPhoneX, 0);\
}

复制代码

二、关于iOS 11部分适配

1、 UIScrollView 有偏移时解决: 在iOS 11之前ViewController viewDidLoad设置

if (!IsiOS11AndLater) {
   self.automaticallyAdjustsScrollViewInsets = NO;
}
复制代码

在iOS 11 使用分类一步解决,设置 .contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever

@implementation UIScrollView (TTiOS11Adjust)

+ (void)load {
    Method m0_original = class_getInstanceMethod([self class], @selector(initWithFrame:));
    Method m0_new     = class_getInstanceMethod([self class], @selector(tt_iOS11_initWithFrame:));
    method_exchangeImplementations(m0_original, m0_new);
    
    Method m1_original = class_getInstanceMethod([self class], @selector(awakeFromNib));
    Method m1_new      = class_getInstanceMethod([self class], @selector(tt_iOS11_awakeFromNib));
    method_exchangeImplementations(m1_original, m1_new);
}

- (instancetype)tt_iOS11_initWithFrame:(CGRect)frame {
    if (![self isKindOfClass:[UIScrollView class]]) {
        return self;
    }
    [self tt_iOS11_initWithFrame:frame];
#ifdef __IPHONE_11_0
    if ([self respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
    if (@available(iOS 11.0, *)) {
         self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        } else {
            // Fallback on earlier versions
        }
    }
#endif
    return self;
}

- (void)tt_iOS11_awakeFromNib {
    if (![self isKindOfClass:[UIScrollView class]]) {
        return ;
    }
    [self tt_iOS11_awakeFromNib];
    
#ifdef __IPHONE_11_0
    if ([self respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
        if (@available(iOS 11.0, *)) {
            self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        } else {
            // Fallback on earlier versions
        }
    }
#endif
}
复制代码

2、 修改UINavigationBar上自定义按钮的可点击区域 自定义按钮继承UIButton 实现- beginTrackingWithTouch: withEvent: 判断点击范围

@interface TTBaseNavigationItemBarButton : UIButton
@end
@implementation TTBaseNavigationItemBarButton
{
    CFAbsoluteTime _hitTime;
}

///修正bar点击区域太大的问题
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event {
    //不连续点击
    CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
    if ((currentTime - _hitTime) < 1 ) {
        return NO;
    }
    _hitTime = currentTime;
    
    BOOL beginTrack = [super beginTrackingWithTouch:touch withEvent:event];
    CGPoint touchPoint = [touch locationInView:self];
    if (beginTrack) {
        if (IsiOS11AndLater) {
            if ( touchPoint.y > 38 || (!self.isLeft && touchPoint.x < 5) || (self.isLeft && touchPoint.x > (self.frame.size.width -10))) {
                return NO;
            }
        }else {
            if ( touchPoint.y > 38 || (!self.isLeft && touchPoint.x < -1) || (self.isLeft && touchPoint.x > (self.frame.size.width +5))) {
                return NO;
            }
        }
        if (touchPoint.y > 38) {
            return NO;
        }
    }else {
    }
    return beginTrack;
}
@end
复制代码

iOS 11之后UINavigationBar层级结构发生了改变,不会继续直接走UIButton- beginTrackingWithTouch: withEvent:,所以折中处理:当点击UINavigationBar上的按钮时手动调用- beginTrackingWithTouch: withEvent:方法。实现方法如下:

@implementation UIView (TTExtensioniOS11)

+ (void)load {
    Method originalMethod = class_getInstanceMethod([self class], @selector(hitTest:withEvent:));
    Method swizzleMethod = class_getInstanceMethod([self class], @selector(bm_hitTest:withEvent:));
    
    BOOL didAddMethod = class_addMethod([self class], @selector(bm_hitTest:withEvent:), method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    if (didAddMethod) {
        class_replaceMethod([self class], @selector(hitTest:withEvent:), method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzleMethod);
    }
}

- (UIView *)bm_hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    __block UIView *hitView = nil;
    if (IsiOS11AndLater) {
        if ([NSStringFromClass([self class]) isEqualToString: @"_UINavigationBarContentView"]) {
            [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull tobj, NSUInteger tidx, BOOL * _Nonnull tstop) {
                if ([tobj isKindOfClass:NSClassFromString(@"_UIButtonBarStackView")]) {
                    if (CGRectContainsPoint(CGRectInset(tobj.frame, -16, 0), point)) {
                        [tobj.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull ttobj, NSUInteger ttidx, BOOL * _Nonnull ttstop) {
                            if ([ttobj isKindOfClass:NSClassFromString(@"_UITAMICAdaptorView")]) {
                                [ttobj.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull tttobj, NSUInteger tttidx, BOOL * _Nonnull tttstop) {
                                    if ([tttobj isKindOfClass:NSClassFromString(@"TTBaseNavigationItemBarButton")]) {
                                        hitView = tttobj;
                                        *tttstop = YES;
                                    }
                                }];
                            }
                        }];
                    }
                }
            }];
        }
    }
    if (!hitView) {
        hitView = [self bm_hitTest: point withEvent: event];
    }
    return hitView;
}

@end
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值