我正在通过创建UITouch
扩展名来搅乱UIResponder
生命周期事件。以下摘录描述了touchesBegan
的实现。
public extension UIResponder {
private enum TouchPhase: String {
case begin
case move
case end
case cancel
//computed property
var phase: String {
return self.rawValue
}
}
@objc func swizztouchesBegan(_ touches: Set<UITouch>, with event:
UIEvent?) {
print("swizztouchesBegan event called!")
let touch = touches.first! as UITouch
self.createTouchesDict(for: touch, event: event, phase: .begin)
self.swizztouchesBegan(touches, with: event)
}
static func swizzleTouchesBegan() {
let _: () = {
let originalSelector =
#selector(UIResponder.touchesBegan(_:with:))
let swizzledSelector =
#selector(UIResponder.swizztouchesBegan(_:with:))
let originalMethod = class_getInstanceMethod(UIResponder.self, originalSelector)
let swizzledMethod = class_getInstanceMethod(UIResponder.self, swizzledSelector)
method_exchangeImplementations(originalMethod!, swizzledMethod!)
}()
}
}
然后我像这样在我的应用中调用它-
[UIResponder swizzleTouchesBegan]; //my app is a mix of Objective-C and Swift
我看到的是-“名为“ swizztouchesBegan事件!”得到打印,然后创建触摸元数据字典。但是,看起来它没有调用原始实现,例如假设在代码的某个地方,在表视图控制器内,我写了以下内容-
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
print("AM I GETTING CALLED?")
}
这种被覆盖的接触开始没有被呼叫-可能是什么问题?我已经通过再次调用swizzled的一个内部而从swizzed的内部调用了原始实现(从而确保调用了原始实现。)
PS /附录:我已经可以通过覆盖UIView
扩展名中的touch方法来使其工作,如下所示。有人可以指出使用这种方法比冒充的方法有什么缺点吗?
public extension UIView {
private enum TouchPhase: String {
case begin
case move
case end
case cancel
//computed property
var phase: String {
return self.rawValue
}
}
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("overriding touches began event!")
let touch = touches.first! as UITouch
self.createTouchesDict(for: touch, event: event, phase: .begin)
super.touchesBegan(touches, with: event)
}
open override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print("overriding touches moved event!")
let touch = touches.first! as UITouch
self.createTouchesDict(for: touch, event: event, phase: .move)
super.touchesMoved(touches, with: event)
}
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print("overriding touches ended event!")
let touch = touches.first! as UITouch
self.createTouchesDict(for: touch, event: event, phase: .end)
super.touchesEnded(touches, with: event)
}
open override func touchesCancelled(_ touches: Set<UITouch>, with
event: UIEvent?) {
print("overriding touches canceled event!")
let touch = touches.first! as UITouch
self.createTouchesDict(for: touch, event: event, phase: .cancel)
super.touchesCancelled(touches, with: event)
}
}
答案 0 :(得分:0)
在我看来,您总是在不停地选择选择器,而不检查是否已完成。
这是一个有关如何实现的示例。
extension UIResponder {
static let swizzleIfNeeded: () = {
swizzle(originalSelector: #selector(touchesBegan(_:with:)), to: #selector(swizztouchesBegan(_:with:)))
}()
static func swizzle(originalSelector: Selector, to swizzledSelector: Selector) {
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
if didAddMethod {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
} else {
method_exchangeImplementations(originalMethod!, swizzledMethod!);
}
}
@objc func swizztouchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("swizztouchesBegan event called!")
let touch = touches.first! as UITouch
self.createTouchesDict(for: touch, event: event, phase: .begin)
self.swizztouchesBegan(touches, with: event)
}
}
然后您的应用程序委托确实完成了(例如)
UIResponder.swizzleIfNeeded
答案 1 :(得分:0)
似乎有方法swizzle不需要快速,因为有扩展名。
因此,如果您想在任何课程上轻触触摸,则只需覆盖触摸即可。像下面一样,我想对所有弹跳赋予弹跳效果
extension UIView {
func highlight(color: UIColor) {
let anim = CABasicAnimation.init(keyPath: #keyPath(CALayer.backgroundColor))
anim.fromValue = UIColor.clear.cgColor
anim.toValue = color.cgColor
anim.duration = 0.5
anim.autoreverses = true
anim.repeatCount = 0
anim.fillMode = kCAFillModeForwards
anim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
self.layer.add(anim, forKey: "blink")
}
func bounce() {
let endTransform = CGAffineTransform(scaleX: 1.0, y: 1.0)
let prepareTransform = CGAffineTransform(scaleX: 0.95, y: 0.95)
UIView.animateKeyframes(
withDuration: 0.2, delay: 0.0, options: UIView.KeyframeAnimationOptions.calculationModeLinear, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.1) {
self.transform = prepareTransform
}
UIView.addKeyframe(withRelativeStartTime: 0.1, relativeDuration: 0.1) {
self.transform = endTransform
}
}, completion: nil)
}
}
extension BounceButton {
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.bounce()
super.touchesBegan(touches, with: event)
}
}
但是在您的情况下,您可以对所有UIView扩展进行操作,因此所有内容都可以反弹。