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];
}
}
Related
I have a parent viewcontroller , and there have a subview(UIView).
The subview(named xibSubView) is called other custom class(xib) file.
When I click on the parent Viewcontroller, the subview(UIView) will motion to touch began position on the parent viewcontroller.
The parent viewcontroller have
// UIViewcontroller.h file
.....
#property (weak, nonatomic) IBOutlet XibSubView *xibSubView;
.....
The below code is in the parent viewcontroller .m
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.subViewConstraint.constant = touchLeftScreenPoint.x ;
self.subViewConstraint.constant = touchLeftScreenPoint.y ;
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
And the xib(subview-xibSubView) code have the same delegate method.
// The code is in the parent viewcontroller .m
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
In the xibSubView have much elements.
One of the elements will motion to the click position in the subview(xibSubView).
So I want to pass the parent viewcontroller touches into xibSubView.
And manual call the touchBegan in the xibSubView let the element motion.
So I should transform the parent viewcontroller touches position to subview touches position.
The subview touches x position and y position will subtract the viewcontroller width and height and manual call the touchbegan method.
But I don't know how to changed the touches x, y values restore to touches.
Then call the code:
[self.xibSubView touchesBegan:touches withEvent:event];
How can I change the NSSet touches x,y variable and restore to touches.
Thank you very much.
NSMutableArray *touchArray = [NSMutableArray new];
[touchArray addObject:[UITouch new]];
NSSet *touches = [[NSSet alloc] init];
[touches setByAddingObjectsFromArray:touchArray];
[self touchesBegan:touches withEvent:UIEventTypeTouches];
Swift
let tArr = NSMutableArray()
tArr.add(UITouch())
let touch = NSSet()
touch.adding(tArr)
touchesBegan(touch as! Set<UITouch>, with: nil)
ViewController.m
#import "ViewController.h"
#import "view.h"
#interface ViewController ()
{
view *v;
}
#end
#implementation ViewController
- (void)viewDidLoad {
v=[[view alloc]initWithFrame:CGRectMake(10, 10, 100, 100)];
[self.view addSubview:v];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[v touchesBegan:touches withEvent:event];
}
#end
view.h
#import <UIKit/UIKit.h>
#interface view : UIView
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
#end
view.m
#import "view.h"
#implementation view
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"%#",touches);
}
#end
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
I am using the UICollectionView to display some products. In the custom UICollectionViewCell, there is a custom UIScrollView, where there are some images which allow the users to do a quick preview.
To forward tap gesture from the UIScrollView to the UICollectionViewCell, i override the touches related methods as below:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.dragging) {
NSLog(#"Began ==>");
[self.nextResponder touchesBegan:touches withEvent:event];
}
else {
[super touchesBegan:touches withEvent:event];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.dragging) {
NSLog(#"Moved ==>");
[self.nextResponder touchesMoved:touches withEvent:event];
}
else {
[super touchesMoved:touches withEvent:event];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.dragging) {
NSLog(#"Ended ==>");
[self.nextResponder touchesEnded:touches withEvent:event];
}
else {
[super touchesEnded:touches withEvent:event];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.dragging) {
NSLog(#"Cancelled ==>");
[self.nextResponder touchesCancelled:touches withEvent:event];
}
else {
[super touchesCancelled:touches withEvent:event];
}
}
sometimes it doesn't work in some cases. For example, when the UICollectionView is loaded first time, didSelectItemAtIndexPath method can be called when you tap, but after some scrolls or taps, the method is not called anymore, even if you try to reload the UICollectionView, it's still not working.
I try to log the message in the touch methods of UICollectionViewCell, the touches & event is forwarded. But why the didSelectItemAtIndexPath of UICollectionView is called if the cell get the gesture?
Any advice would be much appreciated.
UPDATE:
1.the UICollectionViewCell is loaded from nib file.
It's not a good idea to use nextResponder if you're targeting a specific object. As you've just witnessed, the responder chain can change and you may not always get the object you expect. Why this is happening here can be any number of reasons, but you should use a more reliable means in this situation anyways.
Since UIScrollView is a subview of the UICollectionViewCell you can just pass the event directly to your superview [self.superview touchesMoved:touched withEvent:event]; You need to keep view hierarchy in mind when you're doing this and may have to call the superview's superview to reach the cell.
Also I wouldn't recommend using touches to intercept user interactions. I would highly recommend using UIGestureRecognizers as that will provide better more consistent functionality.
You should always call the super methods.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
NSLog(#"Began ==>");
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
NSLog(#"Moved ==>");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
NSLog(#"Ended ==>");
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
NSLog(#"Cancelled ==>");
}
Actually it's because of self.dragging understanding.
The correct way to forward the tap gesture is as below:
- (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
{
if (!self.dragging) {
[self.nextResponder touchesEnded:touches withEvent:event];
}
else {
[super touchesEnded:touches withEvent:event];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.nextResponder touchesCancelled:touches withEvent:event];
}
I need to use touch events but i am trying to detect it from another class, so i will call back to my main class if touched or moved etc.
I am calling init method in "classTouchEvents" firstly from my main class like that
objectTouchEvents=[[classTouchEvents alloc]initWith:self.view];
here is initWith method of "classTouchEvents"
- (id)initWith:(UIView *)selfView
{
self = [super init];
if (self) {
NSLog(#"here");
view=[[UIView alloc]init];
view=selfView;
// Custom initialization
}
return self;
}
and i get "here" log so i guess it is working but i cant detect if view get touch or anything. Here is my touch events in classTouchEvents
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchBegan");
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchMoved");
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchEnded");
}
But i cant get any log about touches. I need some help.
Thanks in advance.
I'd use delegation:
TouchDelegate.h:
#import <UIKit/UIKit.h>
#protocol TouchDelegate <NSObject>
#optional
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
#end
And then in your view (that actually receives the touch event), create a touchDelegate property (or just delegate if there is unlikely to be others):
#import "TouchDelegate.h"
#interface MyView : UIView
#property (weak, nonatomic) id<TouchDelegate> touchDelegate;
...
#end
and then delegate as normal:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([_touchDelegate respondsToSelector:#selector(touchesBegan:withEvent:)]) {
[_touchDelegate touchesBegain:touches withEvent:event];
}
}
// etc.
I would implement a custom subclass of UIView with a delegate.
#protocol TouchEventsDelegate <NSObject>
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event inView:(UIView *)view;
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event inView:(UIView *)view;
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event inView:(UIView *)view;
#end
#property (weak, nonatomic) id<TouchEventsDelegate> delegate;
Implement these delegate methods in your ClassTouchEvents.
Implement the touch events method in your custom view and call the delegate.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.delegate && [self.delegate respondsToSelector:#selector(touchesBegan:withEventinView)]) {
[self.delegate touchesBegan:touches withEvent:event inView:self];
}
}
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);
}