pass scroll event from uibutton to uiscrollview - iphone

i have horizontal UIScrollView which is extended from UIScrollView and i added UIButtons horizontally. i can only scroll out of the buttons area, but if i want to scroll over any buttons is fires UIControlEventTouchUpInside event. I don't want this. i want to fire UIControlEventTouchUpInside action if i click and i want to scroll if i scroll.
so how can i pass scroll event from UIButton to UIScrollView?

Subclass UIScrollView, return YES in the - touchesShouldCancelInContentView: method.

that functionality is already built in. When you have a UIControl element as a subview of a scroll view and a touch event is detected, it is initially passed to the UIScrollView. IF, after a moment or two there hasn't been sufficient movement in the touch event, it gets passed on to the button.

If you subclass NSButton and make your button of that type and override the following in your subclass you can pass the events back to the parent view, in your case the scroll view
The following would make the button never trigger an event and instead all would be dealt with by the parent view:
- (void)touchesBegan: (NSSet *)touches withEvent:(UIEvent *)event {
[self.nextResponder touchesBegan:touches withEvent:event];
}
- (void)touchesMoved: (NSSet *)touches withEvent:(UIEvent *)event {
[self.nextResponder touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent*)event
{
[self.nextResponder touchesEnded:touches withEvent:event];
}
If you want to have the button deal with one of those events instead use
[super touchesEnded:touches withEvent:event];

Try this:
self.button.exclusiveTouch = YES
Worked like a charm for me!

Related

How to send UIButton's dragging event

I have a UIButton, and its superView has touch events.
When the button started dragging i want pass the button and keep go from its superView's touchesMoved function, thats what my problem is.
i tried customize the button, and use its touch events like below;
#implementation MyButton
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.nextResponder touchesMoved:touches withEvent:event];
}
#end
but it doesnt work, touches didnt go to its superView's touchesMoved function..
can anyone please help me?

UIScrollView prevents touchesBegan, touchesMoved, touchesEnded on view controller

I am handling touches for a couple of my UI components in my view controller (custom subclass of UIViewController). It has methods touchesBegan:withEvent:, touchesMoved:withEvent:, and touchesEnded:withEvent:. It was working fine. Then I added a scroll view (UIScrollView) as the top view in the hierarchy.
Now my touch handlers on the view controller don't work. They don't get called. The interesting thing is, I have various other UI components within the scroll view that do work. Some are buttons, some are custom views that define their own touchesBegan:withEvent:, etc. The only thing that doesn't work is the touch handlers on the view controller.
I thought maybe it's because the scroll view is intercepting those touches for its own purposes, but I subclassed UIScrollView and just to see if I could get it to work I am returning YES always from touchesShouldBegin:withEvent:inContentView: and NO always from touchesShouldCancelInContentView:. Still doesn't work.
If it makes a difference my view controller is within a tab bar controller, but I don't think it's relevant.
Has anyone had this problem and have a ready solution? My guess is the scroll view monkeys up the responder chain. Can I monkey it back? I guess if I can't figure anything else out I'll make the top level view under my scroll view be a custom view and forward the messages on to the view controller, but seems kludgy.
create a subclass of UIScrollView class and override the touchesBegan: and other touch methods as follows:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// If not dragging, send event to next responder
if (!self.dragging){
[self.nextResponder touchesBegan: touches withEvent:event];
}
else{
[super touchesBegan: touches withEvent: event];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
// If not dragging, send event to next responder
if (!self.dragging){
[self.nextResponder touchesMoved: touches withEvent:event];
}
else{
[super touchesMoved: touches withEvent: event];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
// If not dragging, send event to next responder
if (!self.dragging){
[self.nextResponder touchesEnded: touches withEvent:event];
}
else{
[super touchesEnded: touches withEvent: event];
}
}
Well this worked, but I'm not sure I can "get away with it", since nextResponder is not one of the UIView methods you're "encouraged" to override in a subclass.
#interface ResponderRedirectingView : UIView {
IBOutlet UIResponder *newNextResponder;
}
#property (nonatomic, assign) IBOutlet UIResponder *newNextResponder;
#end
#implementation ResponderRedirectingView
#synthesize newNextResponder;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (UIResponder *)nextResponder {
return self.newNextResponder;
}
- (void)dealloc
{
[super dealloc];
}
#end
Then in Interface Builder I made the direct subview of the scroll view one of these, and hooked up its newNextResponder to skip the scrollview and point directly to the view controller.
This works too, replacing the override of nextResponder with these overrides:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.newNextResponder touchesBegan:touches withEvent:event];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self.newNextResponder touchesMoved:touches withEvent:event];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self.newNextResponder touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self.newNextResponder touchesCancelled:touches withEvent:event];
}
"It was working fine. Then I added a scroll view (UIScrollView) as the top view in the hierarchy."
is your scrollview on top of your contentview that contains items?
all your components should be in the scrollview and not the view behind the scrollview
user1085093's answer worked for me. Once you move the touch more than a small amount, however, it then gets interpreted as a Pan Gesture.
I overcame this by altering the behaviour of the Pan Gesture recogniser so it requires two fingers:
-(void)awakeFromNib
{
NSArray *gestureRecognizers = self.gestureRecognizers;
UIGestureRecognizer *gestureRecognizer;
for (gestureRecognizer in gestureRecognizers) {
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
UIPanGestureRecognizer *pgRecognizer = (UIPanGestureRecognizer*)gestureRecognizer;
pgRecognizer.minimumNumberOfTouches = 2;
}
}
}
The touchesBegan: etc methods will NEVER be called in a UIScrollView because it is a subclass of UIView and overrides these methods. check out the different UIScrollView methods available here. The work-around will depend on what you want to implement.

Passing scroll gesture to UIScrollView from another view

I do have a view that has a UIScrollView and over it there is a view that display some text.
When the user swipes over this view that contains text the UIScrollView won't scroll. How to make this view transparent in a way it relays the swipe gesture to UIScrollView.
Thanks
You can just set
myTextView.userInteractionEnabled = NO;
Or, if you're creating your view with Interface Builder, there's a check box there called 'User interaction enabled', just uncheck that.
Check out the UIView hitTest Method
Returns the farthest descendant of the receiver in the view hierarchy (including itself) that contains a specified point.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
Inside the -touchesXXXX:withEvent: methods of your custom view, call their super methods to forward touch events.
For example:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// forward touchesBegan to super class
[super touchesBegan:touches withEvent:event];
...
// process touchesBegan for this view
}
Do the same things for touchesMoved, touchesEnded, and touchesCancelled.

iPhone - how to track touches and allow button taps at the same time?

I'm wondering how to track touches anywhere on the iPhone screen and still have UIButtons respond to taps.
I subclassed a UIView, made it full screen and the highest view in the hierarchy, and overrode its pointInside:withEvent method. If I return YES, I'm able to track touches anywhere on the screen but the buttons don't respond (likely because the view is instructed to handle and terminate the touch). If I return NO, the touch passes through the view and the buttons respond, but I'm not able to track touches.
Do I need to subclass UIButton or is this possible through the responder chain? What am I doing wrong?
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
return NO;
}
//only works if pointInside:withEvent: returns YES.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"began");
[self.nextResponder touchesBegan:touches withEvent:event];
}
//only works if pointInside:withEvent: returns YES.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"end");
[self.nextResponder touchesEnded:touches withEvent:event];
}
Rather then having extra view you can subclass your applications main window and track touches (and other events in it)
#interface MyAppWindow : UIWindow
...
#implementation MyAppWindow
- (void)sendEvent:(UIEvent*)event {
[super sendEvent:event];
if (event.type == UIEventTypeTouches){
// Do something here
}
return;
}
Then set your application window type to MyAppWindow (I did that in MainWindow.xib in IB)

UIScrollview+UItextview touch event

i am using a scroll view and that scroll view i have UIIMageview and UITextview.My Question is -i want the Touchevent of Textview.
I think UIScrollView becomes the first responder of touch events, and it doesn't pass the touch events to other view as a default.So, why don't you create a subclass of the UIScrollView? Then, pass the all touch events which are received by the subclass to the UIIMageview or UITextview like as follows.
#implementation SubclassOfScrollView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.nextResponder touchesBegan:touches withEvent:event];
}
#end