Using UISwipeGestureRecognizer and drawing code - iphone

I need a control that allows user to
1) draw on it
2) swipe to go to next screen (through an event or a delegate)
I've tried to add UISwipeGestureRecognizer to the view but it didn't work the way I wanted. My UI setup is like this:
Main Controller:
view (with UISwipeGestureRecognizer)
subview (owned by another controller that captures touch events and draws the graphics)
Whenever I try to draw a horizontal line on the canvas, the UISwipeGestureRecognizer takes over and fires the "go to next screen" event.
How can I prevent UISwipeGestureRecognizer from doing that? I am thinking about differentiating horizontal line vs swipe based on the duration/length but UISwipeGestureRecognizer does not support anything like that.

It sounds to me like a pretty confusing user experience, but if you're determined to do this, you'll probably need to subclass UIGestureRecognizer and tune it to recognize exactly the type of swipes you care about.

Related

Swipe gesture recognizer not working in vertical directions

guys, I'm totally new to Objective C and XCode, so don't be too harsh on me for such a question. In fact, this is my first question on StackOverflow ever. The problem is the following:
I need functionality for closing the keyboard when tapping or scrolling anywhere outside the textField that is currently first responder.
I managed to implement it for tap and horizontal swipes with the following code (right swipe example):
UISwipeGestureRecognizer *swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(closeKeyboard:)];
swipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[self.tableView addGestureRecognizer:swipeGestureRecognizer];
swipeGestureRecognizer.cancelsTouchesInView = NO;
And in fact, later I figured out how to do it using solely interface builder. But vertical swipes just would not work, neither when I do them programmatically, nor through the IB. I suspect that the problem is that my tableView scrolls vertically on the screen, thereby preventing the call of the swipe, but I still have no idea on how to overcome this issue.
I would greatly appreciate your help! Thanks.
I saw, that you are trying to add this vertical gesture to a tableView. So you don't need to add a vertical swipe gesture . You have to implement UIScrollViewDelegate protocol, and implement the -scrollViewDidScroll: or -scrollViewWillBeginDragging: methods. In these methods you can catch if your tableview scrolling, and if your tableView is scrolling, call your closeKeyboard method
the UITableView basically uses UIScrollView & when you implement the UITableView delegate, you also implement the UIScrollView delegate (because behind the scenes, the UITableViewDelegate has implemented the UIScrollViewDelegate)
You do not have to manually implement the UIScrollViewDelegate & you can simply start using any UIScrollView delegates you want such as the -(void)scrollViewDidScroll:
But if you want vertical swipes to work on the tableview then it can be done in the following dirty & totally buggy technique. (Basically this is how NOT to do it)
MAIN property is setDelaysContentTouches on your tableView object to NO.
setDirection on your UISwipeGestureRecognizer object to detect vertical up & vertical down swipes.
Set the swipe gesture onto the tableView object.
example:
[self.tableView setDelaysContentTouches:NO];
UISwipeGestureRecognizer *mySwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:#selector(closeKeyboard:)];
[mySwipe setDirection: UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown];
[self.tableView addGestureRecognizer:mySwipe];
Finally, you'll get it to work but it works real bad.
Most of the times, the swipe is ignored since you need to swipe
really really fast and cover a decent distance within the swipe action.
When the swipe works, the table does not scroll.
So, as you see, it's really sad and dirty thing to do.
The reason is that the scrollView handles the content touches in a very specific way.
To decide if the touch is to be handled or to be forwarded, the
UIScrollView starts a timer when you first touch it:
If you haven't moved your finger significantly within 150ms, it passes the event on to the inner view.
If you have moved your finger significantly within 150ms, it starts scrolling (and never passes the event to the inner view). Note:
how when you touch a table (which is a subclass of scroll view) and
start scrolling immediately, the row that you touched is never
highlighted.
If you have not moved your finger significantly within 150ms and UIScrollView started passing the events to the inner view, but then
you have moved the finger far enough for the scrolling to begin,
UIScrollView calls touchesCancelled on the inner view and starts
scrolling. Note: how when you touch a table, hold your finger a
bit and then start scrolling, the row that you touched is highlighted
first, but de-highlighted afterwards.
These sequence of events can be altered by configuration of
UIScrollView:
If delaysContentTouches is NO, then no timer is used — the events immediately go to the inner control (but then are canceled if you move
your finger far enough)
If cancelsTouches is NO, then once the events are sent to a control, scrolling will never happen.
Note that it is UIScrollView that receives all touchesBegin,
touchesMoved, touchesEnded and touchesCanceled events from CocoaTouch
(because its hitTest tells it to do so). It then forwards them to the
inner view if it wants to, as long as it wants to.
source: https://stackoverflow.com/a/844627/2857130

How to create iOS UiView that combines multiple buttons next to each other and enables swiping to selecting all of them

Right now i have a few buttons next to each other like this:
User has to press all of them to select the whole row (i have a few rows).
It would be natural to enable them to swipe over them to select them all.
I also need to get information about how many buttons were selected.
Could you please help me how to achieve this? Do i have to create my own view or implement some gesture listeners?
Depending on what you exactly trying to achieve there are 2 easy ways :
Simplest : add a UISwipeGestureRecognizer to your view (or to a view with only the 4 buttons on it) and implement delegate interface within your view controller.
When a swipe (in the good direction) is done, you receive an event and you perform your "unlock".
UISwipeGestureRecognizer extends UIGestureRecognizer (doc here) :
Clients of gesture recognizers can also ask for the location of a
gesture by calling locationInView: or locationOfTouch:inView:.
So with that + implementing UIGestureRecognizerDelegate (doc here) you should be able to check exactly what you want.
If you want to manually track the user finger you can just extend UIView and implement :
touchBegan
touchMoved
touchEnded
You can here have the full control (CGRectContainsPoint() will be useful).
Edit :
Something important you have to keep in mind to make your choice is speed. If the user can select the row even with a slow and non-linear gesture (put the finger on the first button then > slowly go to second > go to third > back to second > go to last for instance), you should extends UIView and on the touch began make the first image highlight and then follow the finger until the touchEnd on the last button. It should be more user friendly (depending on what you are trying to achieve of course).
Check out this open source project Swipe-to-Select Gridview

Confining a swipe gesture to a certain area (iPhone)

I have just managed to implement detection of a swipe gesture for my app. However I would like to confine the area where the gesture is valid. Thinking about this I came up with a possible solution which would be to check whether the start & finish coordinates are within some area. I was just wondering if there's a better or preferred method of doing something like this.
Simply create an invisible UIView (= with transparent background) and set its frame so it encloses the region you want to detect the gesture into.
Then, simply add a UISwipeGestureRecognizer to that view, and you are done.
Read the generic UIGestureRecognizer Class Reference and the part of the Event Handling Guide for iOS that talks about UIGestureRecognizers for more info.
Of course you could also manage the detection of the swipe gesture by yourself using custom code like explained here in the very same guide but why bother when UIGestureRecognizers can manage everything for you?

Alternative to UIScrollVIew

I have a quick question. I am trying to implement an application where the user can navigate between the screens via swipe gestures. So I am using gesture recognisers to push and pop views, the problem with that is that I don't want the transition animation to apply to the entire screen as there are certain similar components and it looks weird.
I considered using a scroll view, however I don't want to load all the controllers at the same time.
Any suggestions?
I'd suggest looking into UIGestureRecognizer and setting the UIScrollView property delaysContentTouches to NO to prevent the scroll view from consuming touch events before your gesture recognizer has the change to process the input, if you'd prefer that approach.
Don't forget that UIGestureRecognizer offers you quite a lot of information when the gesture fires.
I would suggest using a scroll view and load only the visible controller. You can then look for this delegate method, and load the other controller lazily
- (void)scrollViewDidScroll:(UIScrollView *)scrollView

Drag & sweep with Cocoa on iPhone

I'm about to start a new iPhone app that requires a certain functionality but I'm not sure if it's doable. I'm willing to research but first I just wanted to know if I should at least consider it or not.
I haven't seen this in an app before (which is my main concern, even though I haven't seen too many apps since I don't own an iPhone), but an example would be the iPhone shortcuts panels: you can hold on an app, and then drag it to another panel, sweeping while still dragging it. But this is the core app, is it possible to reproduce something similar within a normal app?
I only need to be sure it can be done before I start digging, I don't need code examples or anything, but if you have some exact resources that you consider helpful, that would be appreciated.
Thanks!
Yes. If you have your custom UIView subclass instance inside a UIScrollView, your view controller just needs to set the UIScrollView to delay content touches and not allow it to cancel touch events.
[scrollView setCanCancelContentTouches:NO];
[scrollView setDelaysContentTouches:YES];
When the user taps and holds in the custom view, the event goes to that custom view, which can process the touch events to drag an item around, but if the user quickly swipes, it scrolls the view.
The "panel" view that you're referring to appears to be a UIPageControl view — although, perhaps, the specific incarnation of this view that Apple uses for the iPhone's home page may be customized.
Instances of generic UIView views that you might touch-and-drag will receive touch events. By overriding methods in the view, these events can be processed and passed to the page control, in order to tell it to "sweep" between pages.
If I wanted to do what you're asking about, that's how I might approach it. It seems doable to me, in any case.
Start with this: Swip from one view to the next view
Try using a UIButton that tracks the time since the state of the button changed to "highlighted". You may need to do this in order to track the dragging and move the button around:
Observing pinch multi-touch gestures in a UITableView
Check to see if the button starts overlapping one side of the screen while being dragged. If s certain amount of time elapses since the button first started overlapping the edge and then manipulate the UIScrollView so that it switches to the next page on the corresponding side of the screen
You may need to use NSTimer to keep track of how long the button is held down, etc.
In any case there's no reason why this couldn't work.
If UIButton doesn't work then perhaps try a custom subclass of UIControl (which tracks the same touch down actions etc.). If that doesn't work then use the window event intercept thing to track everything.