Subview receiving touches outside its frame in parent view - ios

I can't figure out why this is happening, but I have a subclass of UIView that is added to my view controller's view.
productView = [[SKUProductView alloc]initWithFrame:CGRectMake(60,768, 700, 550)];
[self.view addSubview:productView];
The view starts offscreen and will animate onscreen on a pan gesture event.While the view is offscreen, it is receiving touch events outside its own frame. I have developed a work around by overriding the hitTest method in the subview to return a hitTest call to the superview if the touch event is outside its frame.
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
//Test to determine if view is offscreen or if touch is outside its frame
if (self.frame.origin.y >= 768 || point.x > self.frame.size.width)
{
return [super hitTest:point withEvent:event];
}
else if (point.y < kSKU_SCROLLVIEW_Y_OFFSET)
{
return [_productTabBar hitTest:point withEvent:event];
}
return _productScrollView;
}
but I'm wondering why would my subview receive touch events outside its own frame in the first place?

Why not using
CGRectContainsPoint(rect, point);
to determine if the touch point is inside the frame of view ?
To be sure, print on console the view frame with NSStringFromCGRect() function so you can understand what's happening.

Related

UITapGestureRecognizer not recognized because view is nested in multiple views

I have a custom view that I present by tapping on either a button on the view controller or by tapping on a button on tableview cell (table view is a child of the view controller)
To dismiss the custom view I want the user to be able to tap anywhere on the screen to dismiss it. However due to the many hierarchies of the view in view controllers. A simple UITapGuestureRecognizer isn't working. Is there any workaround for a case like this?
Create a subclass of UIView, call it MyTapView. Assign this class your parent view, which holds all your subviews.
Override in your class the following to intercept any touches made to your view instance.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (!self.clipsToBounds && !self.hidden && self.alpha > 0) {
for (UIView *subview in self.subviews.reverseObjectEnumerator) {
CGPoint subPoint = [subview convertPoint:point fromView:self];
UIView *result = [subview hitTest:subPoint withEvent:event];
if (result != nil) {
return result;
}
}
}
// use this to pass the 'touch' onward in case no subviews trigger the touch
return [super hitTest:point withEvent:event];
}
This method ignores view objects that are hidden, that have disabled user interactions, or have an alpha level less than 0.01. This method does not take the view’s content into account when determining a hit (feel free to modify this). Thus, a view can still be returned even if the specified point is in a transparent portion of that view’s content and now, after it has been overridden, receives touches outside the bounds.

forwarding UISwipeGestureRecognizer to underlying UIScrollView

in my viewController I have an imageSlider which is above a UITableView.
I want to forward vertical swipeGesture from imageSlider to the underlying tableview. so when I swipe vertically on imageSlider, underlying tableView begins to scrolling. (tableview can scroll below imageSlider)
what I did:
I have created a custom view for my viewController View and have override hitTest:WithEvent: method:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *targetView = self.flexibleHeader;
// Convert the point to the target view's coordinate system.
// The target view isn't necessarily the immediate subview
CGPoint pointForTargetView = [targetView convertPoint:point fromView:self];
if (CGRectContainsPoint(targetView.bounds, pointForTargetView)) {
// The target view may have its view hierarchy,
// so call its hitTest method to return the right hit-test view
UIView *finalView = [targetView hitTest:pointForTargetView withEvent:event];
//final view should be UIButton or other UIControl element in RestaurantFlexibleHeader view
if (![finalView isKindOfClass:[targetView class]]) {
return finalView;
}
}
return [super hitTest:point withEvent:event];
}
but the problem is that I can't detect swipe gesture from UIEvent. because allTouches property is empty!
I can put imageSlider below tableView, so When I start to scroll vertically on imageSlider tableView begins to start scrolling. but how can I forward horizontal swipe and tap event to imageSlider?
so whats your idea? how do you handle this dilemma?

Hit Testing a UIButton located outside bounds of SuperView

I am trying to animate this view ControlsView up by touchUpInside in the UIButton which is the carrot character inside the white square in the image attached. When the button is hit, a delegate method is fired an the controlsView is animated up. The problem is that because the UIButton is outside of the bounds of controlsView it does not receive touch info.
I have thought about this a lot and read up on some potential candidate solutions. Such as detecting the touch event on a super view by overriding hitTest:withEvent:. However, the UIButton is actually a subview of CockPitView which is a subview of ControlsView which is a subview of MainView. MainView, it seems, is the rectangle whose coordinates the UIButton would truly lie in. So would I override hitTest there and pass the touch info to CockPitView, where I could then have my Button trigger its action callback?
Has anyone encountered this or a similar problem and have any advice on how to proceed?
You should override hitTest in your custom view CockPitView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (!self.clipsToBounds && !self.hidden && self.alpha > 0) {
for (UIView *subview in self.subviews.reverseObjectEnumerator) {
CGPoint subPoint = [subview convertPoint:point fromView:self];
UIView *result = [subview hitTest:subPoint withEvent:event];
if (result != nil) {
return result;
}
}
}
return nil;
}
CockPitView has to be a subclass of UIView
You may want to use -pointInside:withEvent:. In your button's superview, i.e., ControlsView, override the method like this:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
// self.button is the button outside the bounds of your ControlsView
if (CGRectContainsPoint(self.button.bounds, [self convertPoint:point toView:self.button])) {
return YES;
}
return [super pointInside:point withEvent:event];
}
By doing this, your ControlsView claims that the points inside the bounds of your button should be treated like the points inside your ControlsView.

iOS How to make UIButton below UICollectionView receive touch?

I have next structure
UView -
- UIView2 with Button
- CollectionView - which overlap UIView2 and has contentInset
I can't make to Button receive touch events.
I try pointInside with check clear color (collectionView has backgroundColor is set to clear color)
But i need to scroll work event on blue part (UIView2)
So, i need then i touch collectionView touch also receive a UIButton
Is it possible?
Why does your collection view need to overlap the button? Anyway, you can try overriding HitTest in UIView like this:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
CGPoint pointInUIView2 = [UIView2 convertPoint:point fromView:self];
if ([UIView2 pointInside:pointInUIView2 withEvent:event])
{
return UIView2;
}
else
{
return [super hitTest:point withEvent:event];
}
}

How to make the subview outside the bounds recognize the touches

I have a view with a subview. When a button in the subview is tapped, the subview expands outside the bounds of a view, presenting couple of other buttons. However, I cannot find a way to interact with them.
I found a code at Apple's site:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// Convert the point to the target view's coordinate system.
// The target view isn't necessarily the immediate subview
CGPoint pointForTargetView = [self.targetView convertPoint:point fromView:self];
if (CGRectContainsPoint(self.targetView.bounds, pointForTargetView)) {
// The target view may have its view hierarchy,
// so call its hitTest method to return the right hit-test view
return [self.targetView hitTest:pointForTargetView withEvent:event];
}
return [super hitTest:point withEvent:event];
}
However, I cannot understand how should I use it, so that my subview will recognize the touches.
Any help would be greately appreciated.
You need to subclass the UIView or which ever class you need and override that method. Then create an object of that subclass and use it. It will then recognize the touches.

Resources