IOS Swift重载preferredScreenEdgesDeferringSystemGestures属性,解决手势触摸延迟问题

自从IOS有了手势之后,在全屏的app中,屏幕的4个边缘都会默认触发系统的手势操作,然后才会把事件传递给app处理。首先触发系统的edge手势,在某些app中没有什么问题,比如返回上一级。但在有些app中,比如全屏游戏,就会带来触摸延迟——非常明显,亦或是误触Home回到了主页。

IOS官方给出的解决方案就是,在UIViewController中重载preferredScreenEdgesDeferringSystemGestures属性。有些文章说是函数,但我在IOS12的SDK中看到的是属性,具体如下:

@interface UIViewController (UIScreenEdgesDeferringSystemGestures)// Override to return a child view controller or nil. If non-nil, that view controller's screen edges deferring system gestures will be used. If nil, self is used. Whenever the return value changes, -setNeedsScreenEdgesDeferringSystemGesturesUpdate should be called.
@property (nonatomic, readonly, nullable) UIViewController *childViewControllerForScreenEdgesDeferringSystemGestures API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(watchos, tvos);// Controls the application's preferred screen edges deferring system gestures when this view controller is shown. Default is UIRectEdgeNone.
@property (nonatomic, readonly) UIRectEdge preferredScreenEdgesDeferringSystemGestures API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(watchos, tvos);// This should be called whenever the return values for the view controller's screen edges deferring system gestures have changed.
- (void)setNeedsUpdateOfScreenEdgesDeferringSystemGestures API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(watchos, tvos);@end

我们可以看到,preferredScreenEdgesDeferringSystemGestures是一个只读属性,返回UIRectEdge对象,其代表屏幕的哪些边缘不需要首先响应系统手势——有上下左右4个边缘可选。

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);

因此,我们只要在UIViewController的子类,重写这个属性,返回不需要首先触发系统边缘手势的UIRectEdge对象即可。如下:

// delay system edge gestures to let app touches can be processed first
override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge {return .all; // 延迟屏幕4个边缘的系统手势触发
}