Swift UIScrollView scroll gesture does not call touchesMoved - ios

I really need touchesMoved(...) method in UIScrollView. I know that there is a method scrollViewDidScroll(...), but I really need the other method.
So I create subclass of UIScrollView and implement those methods.
class MyScrollView: UIScrollView {
...
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
print("Move")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
print("Touch")
}
}
If I click on the scroll view I get (let say I click two times) :
Touch
Touch
If I click on scroll view and wait a second and then move my finger I get :
Touch
Move
Move
But then scroller start to scroll and I don't receive anything anymore.
Why scroll gesture doesn't call those methods?
How do I persuade scroll view to call those methods on scroll?

Related

touchesMoved touches.first!.view remains the same, if I move a finger out of view

I have a problem with touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) function. More specifically - touches.first!.view property.
I need to know the tag of view that user is pointing at. But when I drag finger out of view bounds, touches.first!.view value does not change.
This is what I am doing:
I have this code to print out selected view's tag and background color:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print("\(touches.first!.view!.backgroundColor), View tag: " + String(touches.first!.view!.tag))
}
But I expect to get printed out is UIExtendedGrayColorSpace 1 1, View tag: 0, but instead of this I get <UIDynamicSystemColor: 0x600000820b40; name = systemGroupedBackgroundColor>, View tag: 5. This means, that even if I drag my cursor from one view, I still get the first clicked view from touches.first!.view.
How can I get the current selected view?
Answer based on Rob's comment above
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
if let touch = touches.first {
if ( !self.grayUIView.frame.contains(touch.location(in: self.grayUIView)) ){
return
}else {
//still in current view - process with your logic
}
}
}

Determine whether there is any touch in view hierarchy

What's the best way to determine whether there is any active touch happening in a view hierarchy? Something like:
view.hasTouches
returns true if view or any of its descendant has active touches.
To those who would suggest using UIResponder's touch event handling API like touchesBegan, notice that view doesn't receive these calls if one of its descendant is handling the touch events.
You can use touchesBegan and touchesEnded methods in UIViewController as follows:
class ViewController: UIViewController {
var isTouching = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
isTouching = true
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
isTouching = false
}
}

Close iOS Keyboard by touching outside ( a smarter way)

I have UIViewController with UITextfield and several other elements (several subviews and buttons). I want to close the keyboard when tapped somewhere outside of the UITextfield.
I know there is an answer Close iOS Keyboard by touching anywhere using Swift, but this way doesn't work if user taps on viewController's subviews or buttons.
I can add the similar UITapGestureRecognizer for each subViews and buttons, but is there a smarter way to resolve this?
extension UIViewController{
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
}
Also if you have elements in a UIScrollView, add this method too:
extension UIScrollView {
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.next?.touchesBegan(touches, with: event)
}
}

How to hide keyboard by touch in the screen if all my main view is cover by another views?

I cant touch in my main view, I have few other views on him.
this func :
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
dose'nt help me..
is there any func?
If you know which View is focused you can call resignFirstResponder() on it

3D Touch force gesture activates cell tap on touch end

I have subclassed a UITableView in my app so that I can intercept touch events. I am using this to allow me to provide 3D Touch gestures on the entire view (including on top of the table view).
This works great, however the problem is that using 3D Touch on one of the cells and then releasing your finger activates the cell tap.
I need to only activate the cell tap if there is no force exerted. I should explain that I am fading an image in gradually over the entire screen as you apply pressure.
Here is my subclass:
protocol PassTouchesTableViewDelegate {
func touchMoved(touches: Set<UITouch>)
func touchEnded(touches: Set<UITouch>)
}
class PassTouchesTableView: UITableView {
var delegatePass: PassTouchesTableViewDelegate?
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesMoved(touches, withEvent: event)
self.delegatePass?.touchMoved(touches)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
self.delegatePass?.touchEnded(touches)
}
}
And here are the methods I'm calling from my view controller when the touches end and move:
internal func touchMoved(touches: Set<UITouch>) {
let touch = touches.first
self.pressureImageView.alpha = (touch!.force / 2) - 1.0
}
internal func touchEnded(touches: Set<UITouch>) {
UIView.animateWithDuration(0.2, animations: {
self.pressureImageView.alpha = 0.0
})
}
You could create a boolean named isForceTouch which is set to false in touchesBegan, and then once force touch is detected, set it to true. Then in didSelectRowAtIndexPath just return false if isForceTouch is true. It may need tweaking but that should work.

Resources