如何在超级视图的边界之外启用视图的触摸?



我有一个容器,它clipToBounds设置为 false,并且视图超出其边界。无法识别越界视图的触摸事件。

只需将此类添加到您的视图中

class MyView: UIView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
for subview in subviews as [UIView] {
if !subview.isHidden 
&& subview.alpha > 0 
&& subview.isUserInteractionEnabled 
&& subview.point(inside: convert(point, to: subview), with: event) {
return true
}
}
return false
}
}

在这里我修复了上一个答案的格式和滑动方法

extension UIView {
private enum ExtendedTouchAssociatedKey {
static var outsideOfBounds = "viewExtensionAllowTouchesOutsideOfBounds"
}
/// This propery is set on the parent of the view that first clips the content you want to be touchable outside of the bounds
var allowTouchesOfViewsOutsideBounds: Bool {
get {
objc_getAssociatedObject(self, &ExtendedTouchAssociatedKey.outsideOfBounds) as? Bool ?? false
}
set {
UIView.swizzlePointInsideIfNeeded()
subviews.forEach {
$0.allowTouchesOfViewsOutsideBounds = newValue
}
objc_setAssociatedObject(self, &ExtendedTouchAssociatedKey.outsideOfBounds, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
func hasSubview(at point: CGPoint) -> Bool {
if subviews.isEmpty {
return bounds.contains(point)
}
return subviews.contains { subview in
let converted = self.convert(point, to: subview)
return subview.hasSubview(at: converted)
}
}
private static var swizzledMethods = false
@objc
func _point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if allowTouchesOfViewsOutsideBounds {
return originalPoint(inside: point, with: event) || hasSubview(at: point)
}
return originalPoint(inside: point, with: event)
}
@objc
func originalPoint(inside point: CGPoint, with event: UIEvent?) -> Bool {
fatalError("this should be swizzled")
}
private static func swizzlePointInsideIfNeeded() {
if swizzledMethods {
return
}

swizzledMethods = true

let aClass = UIView.self

let originalSelector = class_getInstanceMethod(
aClass,
#selector(point(inside:with:))
)!

let swizzledSelector = class_getInstanceMethod(
aClass,
#selector(_point(inside:with:))
)!

let backupSelector = class_getInstanceMethod(
aClass,
#selector(originalPoint(inside:with:))
)!

let nativeImplementation = method_getImplementation(originalSelector)
let customImplementation = method_getImplementation(swizzledSelector)

method_setImplementation(originalSelector, customImplementation)
method_setImplementation(backupSelector, nativeImplementation)
}
}

这是一个扩展,使您能够允许在容器中触摸裁剪的子视图。将此文件粘贴到项目中并设置containerView.allowTouchesOfViewsOutsideBounds = true

public extension UIView {
private struct ExtendedTouchAssociatedKey {
static var outsideOfBounds = "viewExtensionAllowTouchesOutsideOfBounds"
}
/// This propery is set on the parent of the view that first clips the content you want to be touchable
/// outside of the bounds
var allowTouchesOfViewsOutsideBounds:Bool {
get {
return objc_getAssociatedObject(self, &ExtendedTouchAssociatedKey.outsideOfBounds) as? Bool ?? false
}
set {
UIView.swizzlePointInsideIfNeeded()
subviews.forEach({$0.allowTouchesOfViewsOutsideBounds = newValue})
objc_setAssociatedObject(self, &ExtendedTouchAssociatedKey.outsideOfBounds, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
func hasSubview(at point:CGPoint) -> Bool {
if subviews.count == 0 {
return self.bounds.contains(point)
}
return subviews.contains(where: { (subview) -> Bool in
let converted = self.convert(point, to: subview)
return subview.hasSubview(at: converted)
})
}
static private var swizzledMethods:Bool = false
@objc func _point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if allowTouchesOfViewsOutsideBounds {
return  _point(inside:point,with:event) || hasSubview(at: point)
}
return _point(inside:point,with:event)
}
static private func swizzlePointInsideIfNeeded() {
if swizzledMethods {
return
}
swizzledMethods = true
let aClass: AnyClass! = UIView.self
let originalSelector = #selector(point(inside:with:))
let swizzledSelector = #selector(_point(inside:with:))
swizzle(forClass: aClass, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}
}

最新更新