Detect when user taps the selection indicator in a UIPickerView? - iphone

How can I detect when the user taps the selection indicator in a UIPickerView?
Without this the user has to scroll to some other row and then back again to pick the value which is displayed under the selection indicator when the picker slides up.
Thanks a lot,
Stine
UPDATE: Currently getting it to work by using my own SensitivePickerView (got the idea here Responding to touchesBegan in UIPickerView instead of UIView):
#import <UIKit/UIKit.h>
#protocol SensitivePickerViewDelegate <UIPickerViewDelegate>
- (void) pickerViewWasTouched;
#end
#interface SensitivePickerView : UIPickerView
#property (nonatomic, assign) id<SensitivePickerViewDelegate> delegate;
#end
... and the implementation:
#import "SensitivePickerView.h"
#interface SensitivePickerView ()
- (UIView *) getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event;
#end
#implementation SensitivePickerView
#synthesize delegate;
- (void) setDelegate:(id<SensitivePickerViewDelegate>)aDelegate {
[super setDelegate:aDelegate];
delegate = aDelegate;
}
- (UIView *) hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return self;
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UIView *hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesBegan:touches withEvent:event];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UIView *hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesMoved:touches withEvent:event];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UIView *hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesEnded:touches withEvent:event];
[self.delegate pickerViewWasTouched];
}
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
UIView *hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesCancelled:touches withEvent:event];
}
- (UIView *) getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
UIView *hitTestView = [super hitTest:point withEvent:event];
return (hitTestView == self) ? nil : hitTestView;
}
#end
Not ideal at all but it works :/

If you want some default value to be displayed, call - [picker selectRow:row inComponent:component animated:NO] initializing your picker.
Afraid, you have no way to know if user touches already picked value an doesn't changes it.

Related

UIScrollView touching and listening for events

I have an image inside of a UIScrollView and I have code which draws text as the user drags their finger around. I'd like to be able to control, when the user is touching the screen, if
a) the user should be using their finger to draw OR
b) the user should be moving the scroll view around with their finger
I have a boolean which keeps track of what the user is doing. And I have touches methods:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
if(draw == false) {
printf("calling super");
[scrollView touchesBegan:touches withEvent:event];
}
else
[myPath moveToPoint:[mytouch locationInView:self]];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
if(draw == false)
[scrollView touchesMoved:touches withEvent:event];
else {
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
Why doesn't this work? Basically, if I'm not drawing, I call the touchesBegan and touchesMoved of the scroll view. If I am drawing, I draw using myPath.
However, the scroll view is not moved around or zoomed in, etc, as it should be, when draw is false.
i have met this problem before. And i solve like this:
you should make a mainView . It has 2 property. One is yourScrollView , and One is yourDrawImageView. [yourScrollView addSubviews:yourDrawImageView];[mainView addSubviews:yourScrollView];
and then write your touches method in the mainView.m like this (ignor the scrollView statment)
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
if ([[touches allObjects] isKindOfClass:[yourDrawImageView class]])
{
[myPath moveToPoint:[mytouch locationInView:self]];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
if ([[touches allObjects] isKindOfClass:[yourDrawImageView class]])
{
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
}
The last step , whats you ignor is to code scrollView touches event , its write in yourSceollView.m,like this:
#import "yourScrollView.h"
#implementation yourScrollView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
if(!self.dragging)
[[self nextResponder] touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesMoved:touches withEvent:event];
if(!self.dragging)
[[self nextResponder] touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesEnded:touches withEvent:event];
if(!self.dragging)
[[self nextResponder] touchesEnded:touches withEvent:event];
}
- (void)dealloc {
[super dealloc];
}
#end
I wish it can help you :-)
UIScrollView uses UIGestureRecognizers, which are called by the system separately from touchesBegan:withEvent: and friends. An easier way to do this is to simply disable scrolling on the scroll view when you don't want it to react to touches.

Problems using UIPickerView delegate methods

I have a UIPicker and have setup my delegate methods.
I want something to happen when the user TAPS on the selected picker item. Handling it in:
- (void)pickerView:(UIPickerView *)aPickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
Triggers the event to occur when the picker item is selected not tapped.
How can I trigger an event when the selected picker item is tapped?
You have to sub class UIPickerView and detect the touches there manually. Yes, it looks messy. But that seems to be the only way to do this. The below code may help,
#interface TouchDetectionView : UIPickerView {
}
- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event;
#end
#implementation TouchDetectionView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
[hitTestView touchesCancelled:touches withEvent:event];
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return self;
}
- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
UIView * hitTestView = [super hitTest:point withEvent:event];
return ( hitTestView == self ) ? nil : hitTestView;
}
Ref: Responding to touchesBegan in UIPickerView instead of UIView

Re-issuing a touch event

I'm trying to create an overlay view that monitors for touches and then disappears, but also forwards touch events to whatever is underneath the view.
My test app has a view with a button inside. I add the overlay view as another subview (sibling to the button, essentially), which takes up the entire screen.
For both solutions I tried, the overlay keeps state to determine how it responds to a touch. When a touchesBegan event is received, the overlay will stop responding to hitTest or pointInside until it receives a touchesCancelled or touchesEnded.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if(_respondToTouch)
{
NSLog(#"Responding to hit test");
return [super hitTest:point withEvent:event];
}
NSLog(#"Ignoring hit test");
return nil;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if(_respondToTouch)
{
NSLog(#"Responding to point inside");
return [super pointInside:point withEvent:event];
}
NSLog(#"Ignoring point inside");
return NO;
}
For my first approach, I tried re-issuing the event:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if(!_respondToTouch)
{
NSLog(#"Ignoring touches began");
return;
}
NSLog(#"Responding to touches began");
_respondToTouch = NO;
[[UIApplication sharedApplication] sendEvent:event];
}
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches cancelled");
_respondToTouch = YES;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches ended");
_respondToTouch = YES;
}
However, the button didn't respond to the re-issued event.
My second approach was to use hitTest to discover the view (my button) underneath the overlay, and then send a touchesXXX message directly to it:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches began");
_respondToTouch = NO;
UITouch* touch = [touches anyObject];
_touchDelegate = [[UIApplication sharedApplication].keyWindow hitTest:[touch locationInView:self.superview] withEvent:event];
CGPoint locationInView = [touch locationInView:_touchDelegate];
NSLog(#"Sending touch %# to view %#. location in view = %f, %f", touch, _touchDelegate, locationInView.x, locationInView.y);
[_touchDelegate touchesBegan:touches withEvent:event];
}
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches cancelled");
[_touchDelegate touchesCancelled:touches withEvent:event];
_respondToTouch = YES;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches ended");
[_touchDelegate touchesEnded:touches withEvent:event];
_respondToTouch = YES;
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touches moved");
[_touchDelegate touchesMoved:touches withEvent:event];
}
It finds the button (according to the logs), but the button doesn't react at all when I invoke touchesXXX on it.
I'm not sure what else to try since the button won't respond to a direct invocation of touchesBegan =/

Successful Swipe in UITextView?

Has anyone been able to implement a successful swipe gesture on a UITableView? By default this is not possible due to the scrolling nature of the control. I've tried subclassing UITextView and implementing the swipe function in the instance methods, but no dice.
My UITextView has scrolling disabled - Unless there is another way to implement multiline text?
[Edit] What I should say is input multiline text[/Edit]
Here is a subclass of a UITextView that will detect a swipes gesture...
Is this what you are looking for?
#import <UIKit/UIKit.h>
#define kMinimumGestureLength 25
#define kMaximumVariance 5
#interface SwipeableTextView : UITextView {
CGPoint gestureStartPoint;
}
#end
#implementation SwipeableTextView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch =[touches anyObject];
gestureStartPoint = [touch locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self];
CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x);
CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y);
if (deltaX >= kMinimumGestureLength && deltaY <= kMaximumVariance) {
NSLog(#"Horizontal swipe detected");
}
}
#end
An even better solution, I have found, is to simply pass touches back to the superview:
#interface SwipeableTextView : UITextView {
}
#end
#implementation SwipeableTextView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self.superview touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
[self.superview touchesMoved:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
[self.superview touchesEnded:touches withEvent:event];
}
#end
Add a transparent UIView on top of the UITextView and use it to handle the swipe, and send the touchesBegan/Moved/Ended/Canceled: messages to the text view to preserve normal interaction.
I took Ross's code and added a few things that helped me. In particular, this code won't respond to the swipe until it stops. It also prevents a swipe from reversing direction partway through.
#import <UIKit/UIKit.h>
#define kMinimumGestureLength 25
#define kMaximumVariance 5
typedef enum swipeDirection {
kSwipeNone,
kSwipeLeft,
kSwipeRight
} tSwipeDirection;
#interface SwipeableTextView : UITextView {
CGPoint gestureStartPoint;
tSwipeDirection swipeDirection;
}
#end
#implementation SwipeableTextView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
swipeDirection = kSwipeNone;
UITouch *touch =[touches anyObject];
gestureStartPoint = [touch locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self];
CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x);
CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y);
// Check if we already started a swipe in a particular direction
// Don't let the user reverse once they get going
if (deltaX >= kMinimumGestureLength && deltaY <= kMaximumVariance &&
swipeDirection == kSwipeNone) {
if (gestureStartPoint.x < currentPosition.x) {
swipeDirection = kSwipeRight;
}
else {
swipeDirection = kSwipeLeft;
}
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (swipeDirection == kSwipeRight) {
NSLog(#"Swipe right");
}
else if (swipeDirection == kSwipeLeft) {
NSLog(#"Swipe left");
}
[super touchesEnded:touches withEvent:event];
}
#end
Usually you implement the touch responding events in a UITableViewCell, which can recognize the swipe and do something. UITableViews inherit from UIScrollView which does not like having touch events overridden.
You could also use a two finger swipe. When I get home I can elaborate with some code but that was what I have used

Detect 2 fingers on screen on mapView MapKit

I try to detect the event on a mapview. I just need to detect zoom (double tap or 2 fingers on screen). I try to add a UIview layer that detect event, but if I add a layer, I lose the control on the map (How to intercept touches events on a MKMapView or UIWebView objects?)
Thanks for help!
Tony
Show us some code. You should be able to pass any events you are not interested in back to the parent view. For example, after you detect a two finger tap, and do whatever you want, pass that same event back to mapview and have it zoom itself.
Here is what you call once you are done with your event detection:
[self.nextResponder touchesBegan:touches withEvent:event];
According this: link text
The Mkmapview has to be the default receiver of the events.
So I change the class of my main window to MyMainWindow:
MyMainWindow.h
#import <Foundation/Foundation.h>
#class TouchListener;
#interface MyMainWindow : UIWindow {
TouchListener *Touch;
}
#end
MyMainWindow.m
#import "MyMainWindow.h"
#implementation MyMainWindow
- (void)sendEvent:(UIEvent*)event {
[super sendEvent:event];
[Touch sendEvent:event];
}
#end
TouchListener.h
#import <Foundation/Foundation.h>
#interface TouchListener : UIView {
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
#end
TouchListeners.m
#import "TouchListener.h"
#implementation TouchListener
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return self;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Moved");
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Touch Began");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Touch Ended");
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Touch Cancel");
}
#end
Did I miss something?
Thanks for help