duplicate/mirror touch events from uiview to uiscrollview - ios

i have a uiwebview and an uiview next to each other everone taking 50% of the screen width.
i can smoothly scroll the uiwebview - and i want to be able that if i scroll up/down on the uiview - that the uiwebview scrolls in the given direction.
already subclassed uiview - and trie'd to send the touchesEnded... events to the webview.scrollview.
.h
#interface UIViewScrollDispatcher : UIView
#property(nonatomic, assign) id scroller;
.m
#implementation UIViewScrollDispatcher
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self.scroller touchesCancelled:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self.scroller touchesEnded:touches withEvent:event];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.scroller touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"TOUCHHHH %#", self.scroller);
[self.scroller touchesMoved:touches withEvent:event];
}
using it like this:
UIViewScrollDispatcher * rightarea = [[UIViewScrollDispatcher alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
rightarea.backgroundColor=[UIColor redColor];
rightarea.scroller=self.webView.scrollView;
tried it with self.webView and self.webView.scrollView
doesn't work - any help?
btw: the NSLog inside the touchesMoved gets called
regards

ok - did it with uiscrollview subclass and sync the .contentOffset and .contentSize

Related

Can I call - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event on subview

I recognize touches in my view - if certain conditions happen I would like to call my subview with this method but it isn't working - (if I don't override hittestWithEvent - this view would have been returned)
How can I do it?
Edit:
I want the original SUBVIEW to get the "tap" so I tried to do this:
-(void)didTap:(MyTapGesture *)tap
{
// the original view that would have been returned by hit test. could be any arbitrary view
UIView *theView = [super hitTest:[tap locationInView:self] withEvent:nil];
NSSet *touchesBegan = tap.touchesBegan;
NSSet *touchesEnded = tap.touchesEnded;
UIEvent *eventBegan = tap.eventBegan;
UIEvent *eventEnd = tap.eventEnd;
NSSet *tbegan = [eventBegan touchesForView:theView];
NSSet *tend = [eventEnd touchesForView:theView];
// try to simulate the touch in the subview - not working
[theView touchesBegan:tbegan withEvent:eventBegan];
[theView touchesEnded:tend withEvent:eventEnd];
}
#interface MyTapGesture : UITapGestureRecognizer
#property (nonatomic,strong) NSSet *touchesBegan;
#property (nonatomic,strong) NSSet *touchesEnded;
#property (nonatomic,strong) UIEvent *eventBegan;
#property (nonatomic,strong) UIEvent *eventEnd;
#end
#implementation MyTapGesture
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.touchesBegan = touches;
self.eventBegan = event;
[super touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
self.touchesEnded = touches;
self.eventEnd = event;
[super touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
}
#end
You can overwrite touchesBegan:withEvent on your main view and it the condition happen call it on your subview:
//In your view
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (CONDITION)
{
//call your subview
[yourSubview touchesBegan:touches withEvent:event];
}
}
Hope this is what you are after.
//Extended
You can try add a method to your subview which is called when the condition is meet:
//In your subview
-(void)myMethod:(NSSet *)touches
{
//Your code
}
And call it in your view:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (CONDITION)
{
//call your subview
[yourSubview myMethod:touches];
}
}

How to know which view the user touches on screen

If there is a uiscrollview and and multiple sub view on the uiscrollview. how to know where the user touches i.e on specific view or scrollview(blank space)
Use this approach:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSLog(#"View touched: %#", touch.view);
}
This method is called every time your finger touches the screen, and the touch knows which view it touched.
Edit: It won't work on a UIScrollView because the scroll view gets the touch itself, check this:
touchesBegan method not called when scrolling in UIScrollView
How to enable touch began in UIScrollView?
You have 2 possibilities for detect the touch with - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; in a scrollView:
first, implement this method in your viewController, and add the scrollview on this viewController.
second, which I recommend: make a custom class which is inherited from UIScrollView like this:
.h:
#interface CustomScrollView : UIScrollView
#end
.m:
#import "CustomScrollView.h"
#implementation CustomScrollView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.nextResponder touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if(!self.dragging){
[self.nextResponder touchesMoved:touches withEvent:event];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[self.nextResponder touchesEnded:touches withEvent:event];
}
#end
in your vc make:
...
CustomScrollView* customScrollView = [[CustomScrollView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
...
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSLog(#"View touched: %#", touch.view);
}

UILabel not triggering touchesBegan

i'm currently struggling to make touchesBegan work.
I currently have this setup
[UIView(UIViewController) -> UIScrollView -> UIView[holderView] -> UILabels[]]
I add programmatically my UILabels this way
//UIViewController method
UILabel *etiquetaCantidad = [[UILabel alloc] initWithFrame:CGRectMake(350, idx * 35, 50, 30)];
[etiquetaCantidad setTextAlignment:NSTextAlignmentCenter];
[etiquetaCantidad setBackgroundColor:[UIColor azulBase]];
[etiquetaCantidad setTextColor:[UIColor whiteColor]];
[etiquetaCantidad.layer setCornerRadius:5];
[etiquetaCantidad setText:#"0"];
[etiquetaCantidad setUserInteractionEnabled:YES];
[etiquetaCantidad setTag:idx + 100];
[holderView addSubview:etiquetaCantidad];
But when i try
// UIViewController
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"Touch realizado: %#", touches);
}
It's not being triggered, what i've missed here???
Well, after struggling with my problem, the issue was caused by the UIScrollView that lies between my UILabels and my UIViewController
So i've implemented a category for UIScrollView that passes touches to it's super or nextResponder
#import "UIScrollView+TouchesBeganPropagable.h"
#implementation UIScrollView (TouchesBeganPropagable)
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
if(!self.dragging){
[self.nextResponder touchesBegan:touches withEvent:event];
}else{
[super touchesBegan:touches withEvent:event];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if (!self.dragging){
[self.nextResponder touchesMoved: touches withEvent:event];
}
else{
[super touchesMoved: touches withEvent: event];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
if (!self.dragging){
[self.nextResponder touchesEnded: touches withEvent:event];
}
else{
[super touchesEnded: touches withEvent: event];
}
}
#end
That way, i can use touchesXXXX methods on my UIViewController that interact with any UIView no matter if an UIScrollView is in the middle

Passing touch info to UIScrollView under another UIView

I have a UIScrollView under a transparant UIView. I need to transfer all pans and taps to the scroll view (which only scrolls horizontally). The regular UIView uses a subclass of UIPanGestureRecognizer to track vertical pans (Subclass found here). In the overlay view, I override the touch event methods to pass them to the UIScrollView.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[self.scrollView.panGestureRecognizer touchesBegan:touches withEvent:event];
[self.scrollView.singleTapGesture touchesBegan:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
[self.scrollView.panGestureRecognizer touchesCancelled:touches withEvent:event];
[self.scrollView.singleTapGesture touchesCancelled:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
[self.scrollView.panGestureRecognizer touchesEnded:touches withEvent:event];
[self.scrollView.singleTapGesture touchesEnded:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
[self.scrollView.panGestureRecognizer touchesMoved:touches withEvent:event];
[self.scrollView.singleTapGesture touchesMoved:touches withEvent:event];
}
The overlay view, the vertical pan works perfectly. In the UIScrollView, the taps also work perfectly. The scrolling though, not so much. The scroll view scrolls about three points, then stops (as I continue with the horizontal pan.) If I let go with a velocity, the scroll view then picks up that velocity and finishes scrolling.
What would be the possible issues causing the scroll view to stop scrolling then pick up the velocity?
From the code you posted, I assume you are not doing anything with the transparent UIView.. then why don't you just set userInteractionEnabled = NO; ??
Here's an easier solutions that worked well for me:
In the transparent UIView (let's call it OverlayView) make the width and height both 0 (so that the view is no longer technically on top of the UIScrollView) and set clipsToBounds = NO (so that the contents of OverlayView still show up on top of the UIScrollView).
self.OverlayView.clipsToBounds = NO;
CGRect frame = self.OverlayView.frame;
self.OverlayView.frame = CGRectMake(frame.origin.x, frame.origin.y, 0, 0);
Note that if OverlayView contains interactive controls (like the button above) then they will no longer work. You'll need to move it into it's own view above the UIScrollView.
#import "CustomUiView.h"
#implementation CustomUiView.h
-(BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event{
return NO;
}
#end
The view you do not want to interact.
create custom UIView class and use this custom view as your top view that return NO in pointInside method. Then the touch will go automatically underearth. In your case Your Transparent UIView will be CustomUiView subclass of UIView.

UIbutton taking time to receive down event in a UISCrollView on iOS5

I have the following hierarchy:
- UIView 1
- UIScrollView 2
- UIView 3
- UIView 4
- UIButton 5
My problem is that the touch down on the UIButton requires me to press for what seems a long time (like a second) to be registered by the UIButton.
The way this hierarchy is created : UIView1 is loaded from a nib file with 2 and 3 embedded but 4 is created from another nib file, first placed in one view not depicted here and then brought in 3 using addsubview. (I don't know if this is relevant).
Does somebody have any idea on how to fix this delay ? The problem appears on my 4s with ios5.1 and not in the simulator with iOS 6.
Try to set UIScrollView delaysContentTouches property to NO.
OR
Try using [button performSelector:#selector(buttonClickMethod:) afterDelay:0.0];
#interface CustomScrollView : UIScrollView {
}
#end
#implementation CustomScrollView
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
}
return self;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self superview] touchesEnded:touches withEvent:event];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[[self superview] touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[[self superview] touchesMoved:touches withEvent:event];
}
- (void)dealloc {
[super dealloc];
}
#end
Use customscrollview Instead of uiscrollview

Resources