我尝试在动画过程中检测到UIImageView上的点按,但它不起作用。
我的所作所为(快讯4):
通过StoryBoard添加UIImageView:
@IBOutlet weak var myImageView: UIImageView!
做动画:
override func viewWillAppear (_ animated: Bool) {
super.viewWillAppear (animated)
myImageView.center.y + = view.bounds.height
}
override func viewDidAppear (_ animated: Bool) {
super.viewDidAppear (animated)
UIView.animate (withDuration: 10, delay: 0, options: [.repeat, .autoreverse, .allowUserInteraction], animations: {
self.myImageView.center.y - = self.view.bounds.height
})
}
尝试检测水龙头:
override func viewDidLoad () {
super.viewDidLoad ()
let gestureSwift2AndHigher = UITapGestureRecognizer (target: self, action: #selector (self.actionUITapGestureRecognizer))
myImageView.isUserInteractionEnabled = true
myImageView.addGestureRecognizer (gestureSwift2AndHigher)
}
@objc func actionUITapGestureRecognizer () {
print ("actionUITapGestureRecognizer - works!")
}
在投票之前,请确保对这些问题没有正常的答案,初学者可以理解,并且在第2版以上快速写,所以我不能将它们用于我的案例。
研究这个问题,我意识到有必要调整框架!但这对我来说仍然很难。请告诉我,我需要在下面的代码中添加或更改内容。
感谢您的帮助。
class ExampleViewController: UIViewController {
@IBOutlet weak var myImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// action by tap
let gestureSwift2AndHigher = UITapGestureRecognizer(target: self, action: #selector (self.actionUITapGestureRecognizer))
myImageView.isUserInteractionEnabled = true
myImageView.addGestureRecognizer(gestureSwift2AndHigher)
}
// action by tap
@objc func actionUITapGestureRecognizer (){
print("actionUITapGestureRecognizer - works!") // !!! IT IS DOES NOT WORK !!!
}
// hide UIImageView before appear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
myImageView.center.y += view.bounds.height
}
// show UIImageView after appear with animation
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 10, delay: 0, options: [.repeat, .autoreverse, .allowUserInteraction], animations: {
self.myImageView.center.y -= self.view.bounds.height
})
}
}
答案 0 :(得分:0)
您无法使用UITapGestureRecognizer
执行所需操作,因为它使用基于frame
的检测,并通过检查其框架来检测视图内是否有触摸。
问题在于,动画在动画开始之前已经设置了视图的最终帧。然后它会在您再次显示真实视图之前将视图的快照设置为动画。
因此,如果你要点击动画的最终位置,即使你的视图看起来不像它,你也会看到你的点击手势被击中..你可以在下图中看到:< / p>
https://i.imgur.com/Wl9WRfV.png
(左侧是视图层次结构检查器)..(右侧是模拟器动画)。
要解决点击问题,您可以尝试一些粗略的代码(但有效):
import UIKit
protocol AnimationTouchDelegate {
func onViewTapped(view: UIView)
}
protocol AniTouchable {
var animationTouchDelegate: AnimationTouchDelegate? {
get
set
}
}
extension UIView : AniTouchable {
private struct Internal {
static var key: String = "AniTouchable"
}
private class func getAllSubviews<T: UIView>(view: UIView) -> [T] {
return view.subviews.flatMap { subView -> [T] in
var result = getAllSubviews(view: subView) as [T]
if let view = subView as? T {
result.append(view)
}
return result
}
}
private func getAllSubviews<T: UIView>() -> [T] {
return UIView.getAllSubviews(view: self) as [T]
}
var animationTouchDelegate: AnimationTouchDelegate? {
get {
return objc_getAssociatedObject(self, &Internal.key) as? AnimationTouchDelegate
}
set {
objc_setAssociatedObject(self, &Internal.key, newValue, .OBJC_ASSOCIATION_ASSIGN)
}
}
override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let touchLocation = touch.location(in: self)
var didTouch: Bool = false
let views = self.getAllSubviews() as [UIView]
for view in views {
if view.layer.presentation()?.hitTest(touchLocation) != nil {
if let delegate = view.animationTouchDelegate {
didTouch = true
delegate.onViewTapped(view: view)
}
}
}
if !didTouch {
super.touchesBegan(touches, with: event)
}
}
}
class ViewController : UIViewController, AnimationTouchDelegate {
@IBOutlet weak var myImageView: UIImageView!
deinit {
self.myImageView.animationTouchDelegate = nil
}
override func viewDidLoad() {
super.viewDidLoad()
self.myImageView.isUserInteractionEnabled = true
self.myImageView.animationTouchDelegate = self
}
func onViewTapped(view: UIView) {
print("Works!")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
myImageView.center.y += view.bounds.height
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 5, delay: 0, options: [.repeat, .autoreverse, .allowUserInteraction], animations: {
self.myImageView.center.y -= self.view.bounds.height
})
}
}
它通过覆盖UIView
上的touchesBegan,然后检查是否有任何触摸落在该视图内。
更好的方法就是在UIViewController
代替它。
import UIKit
protocol AnimationTouchDelegate : class {
func onViewTapped(view: UIView)
}
extension UIView {
private class func getAllSubviews<T: UIView>(view: UIView) -> [T] {
return view.subviews.flatMap { subView -> [T] in
var result = getAllSubviews(view: subView) as [T]
if let view = subView as? T {
result.append(view)
}
return result
}
}
func getAllSubviews<T: UIView>() -> [T] {
return UIView.getAllSubviews(view: self) as [T]
}
}
class ViewController : UIViewController, AnimationTouchDelegate {
@IBOutlet weak var myImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.myImageView.isUserInteractionEnabled = true
}
func onViewTapped(view: UIView) {
print("Works!")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
myImageView.center.y += view.bounds.height
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 5, delay: 0, options: [.repeat, .autoreverse, .allowUserInteraction], animations: {
self.myImageView.center.y -= self.view.bounds.height
})
}
override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let touchLocation = touch.location(in: self.view)
var didTouch: Bool = false
for view in self.view.getAllSubviews() {
if view.isUserInteractionEnabled && !view.isHidden && view.alpha > 0.0 && view.layer.presentation()?.hitTest(touchLocation) != nil {
didTouch = true
self.onViewTapped(view: view)
}
}
if !didTouch {
super.touchesBegan(touches, with: event)
}
}
}
答案 1 :(得分:0)
hitTest
:override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
return (layer.presentation()!.frame)
.contains(self.convert(point, to: superview!)) ? self : nil
}
在当前示例中
它可与所有手势识别器一起使用
请勿在视图控制器级别
仅将视图本身子类化,在上面添加覆盖
别自然地忘记,如果要在抓取项目后停止动画,请使用yourPropertyAnimator?.stopAnimation(true) , yourPropertyAnimator = nil