Is possible to turn off the backswipe for certain part of the screen? In particular, I was thinking of using this method:
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer!) -> Bool {
return false;
}
I was thinking to recognize what part of the screen the user has pressed on, if it is within a certain interval, I would return true, else false. Not sure how to pickup where the user has pressed.
I assume you are talking about the functionality provided by the UINavigationController.
First your class should conform to the UIGestureRecognizerProtocol something like this:
class MyController: UIViewController, UIGestureRecognizerProtocol
Then you need to register to become the delegate for the navigation controller so probably in your viewDidLoad or viewWillAppear (depending on needs) you have this:
self.navigationController?.interactivePopGestureRecognizer?.delegate = self
Then you can use the following to check where in the view the gesture start:
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let location = gestureRecognizer.location(in: self.view)
if location.y > 500 {
return false
}
return true
}
Obviously this is just a test case where it ignores the gesture when it starts above 500 in the vertical and you can change that to whatever you want.
Related
I want to implement a shake to undo on my iPhone App, in Swift.
For now it works, but it didn't display an Alert asking to validate the undo gesture (with buttons "Cancel" and "Undo"). I can add this alert in the right place myself, but I'm not certain I should. Some articles make me think that the alert should appear automatically, in the undo/redo process, so there's something I missed, perhaps...
Here are the relevant bits of code
In the viewController
override func becomeFirstResponder() -> Bool {
return true
}
and
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
if motion == .motionShake {
snowflake.undoLastAction()
}
}
and in my snowflake class, the action is inserting or modifying point in an array, so I store the value before the change in oldPathPoints, then
// Action du undo
undoManager?.registerUndo(withTarget: self, handler: { (targetSelf) in
snowflake.pathPoints = oldPathPoints
})
and finally the undo method
func undoLastAction() {
undoManager?.undo()
createPath()
}
So,
I succeeded to do it (with the help of a 5-years Book from Matt Neuburg!)
So, there's nothing to make in the viewController, I deleted becomeFirstResponder and motionEnded.
All is in the SnowFlake class: I added
let undoer = UndoManager()
override var undoManager : UndoManager? {
return self.undoer
}
override var canBecomeFirstResponder: Bool { return true }
So I communicate the undoManager I use and the class (a view here) can become firstResponder
after the manipulation of the view that can be undone (in my case in touchesEnded)
, I call
self.becomeFirstResponder()
I deleted the undoLastAction function (useless now), and
changed the undo action to a fonction
changePathUndoable(newPathPoints: finalPathPoints)
the function is like that
func changePathUndoable(newPathPoints: [CGPoint]) {
let oldPathPoints = Snowflake.sharedInstance.pathPoints
Snowflake.sharedInstance.pathPoints = newPathPoints
// Action du undo
undoer.setActionName("cutting")
undoer.registerUndo(withTarget: self, handler: { (targetSelf) in
targetSelf.changePathUndoable(newPathPoints: oldPathPoints)
})
Snowflake.sharedInstance.createPath()
self.setNeedsDisplay()
}
I had to create the function changePathUndoable instead of calling undoer.registerUndo directly just for having the redo action to work (I didn't test redo before).
I think that all the steps are necessary to do what I wanted: make the view receive the shake event, displays this dialog
and be able to undo/redo the modifications.
everyone knows that when you drag outside a button it don't cancel the highlight state right away by UIButton's default. UIControlEventTouchDragExit triggers when 70 pixels away. I want that distance to be 0. So after searching the solution of it, I tried to create a subclass like this:
import UIKit
class UINewButton: UIButton {
override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
print("here")
let touchOutside = !CGRectContainsPoint(self.bounds, touch.locationInView(self))
if touchOutside {
let previousTochInside = CGRectContainsPoint(self.bounds, touch.previousLocationInView(self))
if previousTochInside {
print("Sending UIControlEventTouchDragExit")
self.sendActionsForControlEvents(.TouchDragExit)
self.highlighted = false
self.selected = false
}else{
print("Sending UIControlEventTouchDragOutside")
self.sendActionsForControlEvents(.TouchDragOutside)
}
}else{
let previousTouchOutside = !CGRectContainsPoint(self.bounds, touch.previousLocationInView(self))
if previousTouchOutside{
print("Sending UIControlEventTouchDragEnter")
self.sendActionsForControlEvents(.TouchDragEnter)
}else{
print("Sending UIControlEventTouchDragInside")
self.sendActionsForControlEvents(.TouchUpInside)
}
}
return super.continueTrackingWithTouch(touch, withEvent: event)
}
}
and create a button like this in a UIViewController
#IBOutlet var confirmButton: UINewButton!
I assumed when a UIButton being touched and dragged. It would call the function in this sequence:
beginTrackingWithTouch(when touched) -> continueTrackingWithTouch(when dragged) -> endTrackingWithTouch(when left)
But here is the weird part. Even though I override the function continueTrackingWithTouch, it still not been called. Cause the console window didn't show "here" where I put there in it. And the result remain the default distance 70. how come is that?
I tried to call the three functions mentioned above and return true if it needs one.
What did I missed?
After reading this article: UIControlEventTouchDragExit triggers when 100 pixels away from UIButton
Still not helping :( (plus it written in objective-C...)
Isn't the distance of 70px a property of the function so I can just changed?(How can I see the original function by the way? There is no detail in Apple Developer Documentation...)
Should I use button.addtarget in the UIViewController? But it seems like another way to do it.
Here is another question:
If I want to cancel the highlight state when dragged outside the button, is this right?
self.highlighted = false
self.selected = false
I don't know which one is the right one so I used it all.
please help! Just a newbie in swift but I have been stuck in this problem for 3 days. QQ
In Swift 3 the function signature has changed. It's now:
func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool
API Reference
Having some issues getting this to override its superclass - keep getting the error "method does not override any method from its superclass". The collection view and the pan is all set-up, I just want to disable sideways panning (if that's a word).
I'm sticking this right at the bottom of my class:
override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer {
let translation = panGestureRecognizer.translationInView(collectionView!)
if fabs(translation.y) > fabs(translation.x) {
return true
}
return false
}
return false
}
Any ideas? I'll post my jazzy collectionview and it's panning-abilities as a rewards for those that contribute.
You can't override that method because it's not part of your superclass (UICollectionView). You need to adopt the UIGestureRecognizerDelegate protocol in your class and remove the override.
Assuming you've created a UIPanGestureRecognizer, either in storyboard or programatically, you need to set the delegate of that UIPanGestureRecognizer to self whenever your view loads.
Also, don't forget to add the panRecognizer to your collection view.
panGesture.delegate = self
collectionView.addGestureRecognizer(panGesture)
I have an issue with UITextview in iOS9, when i do a longpress on textview it shows the magnifying glass. I tried to disable through UILongPressGestureRecognizer, it completely disables the Link and phone touch events also.
How to Disable only Magnifing glass.
override func addGestureRecognizer(gestureRecognizer: UIGestureRecognizer) {
if gestureRecognizer .isKindOfClass(UILongPressGestureRecognizer){
gestureRecognizer.enabled = false
}
super.addGestureRecognizer(gestureRecognizer)
}
the textview will be in a collectionview cell.
There is a way to achieve that. Just override the gestureRecognizerShouldBegin for the UITextView. This gesture-recognizer object is about to begin processing touches to determine if its gesture is occurring.
The only tricky part is to properly recognize delegate which is assigned to the magnifier activation.
I've successfully tested with: UITextGestureClusterLoupe. Here is the working example (Swift 4):
override public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
{
if let gestureDelegate = gestureRecognizer.delegate {
if(gestureDelegate.description.localizedCaseInsensitiveContains("UITextGestureClusterLoupe"))
{
return false;
}
}
return true;
}
The code seems right but you need to override the gestureRecognizer for the textView, not the superclass. Change super.addGestureRecognizer(gestureRecognizer) to yourTextView.addGestureRecognizer(gestureRecognizer) and place it in the view controller containing an outlet to your text view(if it's not there already).
According to Vlada's anwser, for my code I found the delegate assigned to the magnifier activation is "UITextLoupeInteraction"
Here is my code:
open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if let gestureDelegate = gestureRecognizer.delegate {
print(gestureDelegate.description)
if(gestureDelegate.description.localizedCaseInsensitiveContains("_UIKeyboardBasedTextSelectionInteraction")){
return false
}
if(gestureDelegate.description.localizedCaseInsensitiveContains("UITextLoupeInteraction")){
return false
}
}
return true
}
My development environment: swift4, Xcode10.1, iOS 12.1
I have a uipageviewcontroller and the pages have an area on the screen where there is a uitableview. I want the user to only be able to swipe through pages outside of that uitableview.
I can't seem to find where these gesture recognizers are hiding. I am setting them up as delegates like this:
self.view.gestureRecognizers = self.pageViewController?.gestureRecognizers
for gesture in self.view.gestureRecognizers!{
// get the good one, i discover there are 2
if(gesture is UIPanGestureRecognizer)
{
println("ispan")
// replace delegate by yours (Do not forget to implement the gesture protocol)
(gesture as! UIPanGestureRecognizer).delegate = self
}
}
I am seeing ispan in the logs so it seems to find some uipangesturerecognizer but when I override the function like this:
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
println("gesture should begin")
var point = gestureRecognizer.locationInView(self.view)
return true
}
it doesn't print out "gesture should begin" at all... I have the class set as a UIGestureRecognizerDelegate what am I doing wrong? I'm guessing I have the wrong gesture recognizers set as delegates how can I set the correct ones as delegates?
Could something like this work?
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if(touch.view == <your tableView>){
return false
}else{
return true
}
}
You might need to also test which gestureRecognizer it is (the one from the pageView or the one from the tableView).