I have a UITableView within a UIView where the UIView is acting as a pullup view. I would like to drag the view up and down the screen and for the view to move up with my drag.
If I am touching the UITableView part then I would like to just drag up until the UIView reaches some top limit and then for my dragging to start dragging up the UITableView.
If the UIView is at its top limit and I drag down on the UITableView then I would like the UITableView to drag down until it reaches its beginning then for the drag to transfer to the UIView, dragging that down the screen with the UITableView along with it.
Furthermore, the UITableVIew has buttons that need to continue reacting to presses so I cannot simply turn off the user interactivity of the tableview when I want.
Currently I am setting a flag when the UIView is at its top parking position and then using the following methods in an extended UITableView class
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint then = [[touches anyObject] previousLocationInView: self];
CGPoint now = [[touches anyObject] locationInView: self];
//CGFloat deltaY = fabs(then.y - now.y);
if(self.contentOffset.y == 0 && now.y > then.y)
inSlideMode_ = YES;
if(inSlideMode_)
{
[self.nextResponder touchesMoved:touches withEvent:event];
}
else
{
[super touchesMoved:touches withEvent:event];
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint then = [[touches anyObject] previousLocationInView: self];
CGPoint now = [[touches anyObject] locationInView: self];
//CGFloat deltaY = fabs(then.y - now.y);
if(self.contentOffset.y == 0 && now.y > then.y)
inSlideMode_ = YES;
if (inSlideMode_)
{
//forwarding action:
[self.nextResponder touchesBegan:touches withEvent:event];
}
else
{
[super touchesBegan:touches withEvent:event];
}
}
-( void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if(inSlideMode_)
{
[self.nextResponder touchesEnded:touches withEvent:event];
}
else
{
[super touchesEnded:touches withEvent:event];
}
previousTouchY_ =UNTOUCHED_Y_POSITION;
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
if (scrollView.contentOffset.y <= 0)
{
self.scrollEnabled = NO; // if we reach the top of scrolling then should switch tableview into the pullup interactor
self.inSlideMode = YES;
}
}
In the UIView extended class, I am overriding the same methods to handle the dragging and also looking to see whether it is docked to top.
Currently it nearly works but when dragging the UITableView, once it reaches the bottom I need to lift finger and start dragging on it again to get the UIView to be dragged down. Any suggestions??? Thanks
Related
no matter how much I tried I couldn't have access (Handle scrolling/Touchevents) to the overlapping area (right triangle) between two square shaped views A and B (A in on top of B)as shown in this image
I want the right part (triangle B) with is defined by UIbezierpath to handle the scrolling for the view beneath it(which is B). I couldn't have access to it by pointInside: withEvent: since its a bezierpath.
Even touchesBegan:withEvent: didn't work at all
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
if ([leftPath containsPoint:touchPoint])
{ //Do something
}
}
Please help.
You have to implement hitTest method of UIView to detect touch on particular view. Simply subclass your View and implement hitTest method.
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
if ([path containsPoint:point]){
return [super hitTest:point withEvent:event];
}
else{
return nil;
}
}
In my app I have an UIView on top of UISplitViewController (used "addSubView"). What I wanna do is to let the UIView handle the touch and then redirect it to the parent view so it could also handle it.
I think i have a work around for what you try to do. You'll have to subclass your topView and implement the following two methods:
The first method will handle your touch for the buttomView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
CGPoint bottomViewHit = [bottomView convertPoint:point fromView:self];
if ([topView pointInside:topViewHit withEvent:event]) {
//manage your bottomView touch here..
return bottomView;
}
return [super hitTest:point withEvent:event];
}
The second method will handle the topView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:touch.view];
// manage your touch for topView here...
[view touchesBegan:touches withEvent:event];
}
I've implemented a really simple custom UISwitch that uses touches events like:
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
I can use this control in my views without problem. The Control simulates a UISwitch, so it can change value through a drag or through a tap.
My problem is that I can't let this Control work inside a Cell of a UITableView. Only the single tap seems to work (note that I'm not using gesture... but the events that I've previously listed) but I can't "swipe" the switch handle.
I instantiate the controller within the tableView:cellForRowAtIndexPath method adding the control as subview of the cell contentView:
[cell.contentView addSubview:customSwitch];
I suppose that it is something related with the fact that UITableView is a UIScrollView and I think that touches events get somehow "stolen" by it.
// EDIT --------------------
Here is the code related with the Touch events.
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
[super beginTrackingWithTouch:touch withEvent:event];
self.dragged = NO;
return YES;
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
if (!self.enabled) {
return NO;
}
[super continueTrackingWithTouch:touch withEvent:event];
self.dragged = YES;
CGPoint touchPoint = [touch locationInView:self];
float centerPoint = FIXED_WIDTH / 2.0;
[self centerOn:(touchPoint.x > centerPoint) animated:YES completion:nil];
return YES;
}
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
[super endTrackingWithTouch:touch withEvent:event];
CGPoint touchPoint = [touch locationInView:self];
BOOL currentOn = self.on;
BOOL nextOn;
if (self.dragged) {
float centerPoint = FIXED_WIDTH / 2.0;
nextOn = (touchPoint.x > centerPoint);
[self setOn:nextOn animated:NO];
}else{
nextOn = !self.on;
[self setOn:nextOn animated:YES];
}
self.dragged = NO;
if (currentOn != nextOn) {
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
}
How can I make the control work inside a Cell without interfering with the UIScrollView/UITableView?
You need to implement your custom switch using gestures instead of trying to directly process events.
The gesture recognizers work behind the scenes to coordinate their event processing which, for example, is why a UIScrollView can work inside of another UIScrollView. You need that coordination for the UITableView (really a UIScrollView) to properly handle swipe gestures within its content.
Search the web for Hardy Macia's UICustomSwitch sample code for a good example of matching the UISwitch behaviors in a custom control.
Did you miss the touchesBegan: and touchesMoved:?
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
[super touchesBegan:touches withEvent:event];
// Get the only touch (multipleTouchEnabled is NO)
UITouch* touch = [touches anyObject];
// Track the touch
[self beginTrackingWithTouch:touch withEvent:event];
}
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
[super touchesMoved:touches withEvent:event];
// Get the only touch (multipleTouchEnabled is NO)
UITouch* touch = [touches anyObject];
// Track the touch
[self continueTrackingWithTouch:touch withEvent:event];
}
I would like to be able to retrieve info on a tap, about all the different subviews that are placed in that tap spot. For example, if there was a background, and in front of it was a game character, I would like to be able to tap on that character, and it will retrieve the info saying that both the character and the background are in that tap spot.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//retrieve info about what other subviews lie behind at this point
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch=[touches anyObject];
CGPoint p=[touch locationInView:self.view];
NSLog(#"Coordiantes of Tap Point:(%f,%f)", p.x, p.y);
NSArray *anArrayOfSubviews = [self.view subviews];
NSMutableArray *requiredSubviewArray = [NSMutableArray array];
for (UIView *aSubView in anArrayOfSubviews){
if(CGRectContainsPoint(aSubView.frame, p)) {
//aSubView is there at point 'p'
[requiredSubviewArray addObject:aSubView];
}
}
// requiredSubviewArray contains all the Subviews at the Tap Point.
}
try this.it maybe helpful to you..
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//retrieve info about what other subviews lie behind at this point
NSLog(#"subviews--%#",[self.view subviews]); //it prints all subviews as Array
NSLog(#"superview--%#",[self.view superview]); //it prints superview of your view
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject]; // here you get all subviews on ur touchpoint
if ([touch view] == imageView) {
CGPoint location = [touch locationInView: self.view];
imageView.center = location;
}
}
/// To check both views are in one spot, use this
// CGRectContainsRect() and CGRectIntersectsRect().
You can try this one..
You can get all subviews if you use [self.view subviews]. You can compare those views frames with touch location.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint touchLocation = [touch locationInView:self.view];
startX = touchLocation.x;
startY = touchLocation.y;
for (UIView *view in [self.view subviews]){
//Here you can compare each view frame with touch location
}
}
So I have a Subclass of UIView that is suppose to detect touches. The view detect touches only if the touches started inside the current view. When the touches start outside of the view and they move inside my custom view touchesMoved doesn't get called. Any solution to detect moving touches that have not started in the current view?
#implementation MycustomView
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// This only gets called if touches have started in the current View
}
#end
The following solution worked. I have multiple instances of MyCustomView; as the touches move I want to detect the views that are being touched
I ended up moving touch detection from MyCustomView to its superView, so the following code is no longer in MyCustomView class:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.contentView];
for (UIView *view in self.contentView.subviews)
{
if ([view isKindOfClass:[MyCustomView class]] &&
CGRectContainsPoint(view.frame, touchLocation))
{
}
}
}
this should fix it:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
for (UIView* subView in self.subviews)
{
if([subView pointInside:[self convertPoint:touch toView:subView] withEvent:event])
{
//do your code here
}
}
}
One way to do it (though there might be others) is to disable user interaction for the subviews and make their parent view track the movement (use the hitTest method to figure out which view the touch is currently over).
Try this....
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch *touch in touches)
{
CGPoint touchPointFirstBtn = [touch locationInView:self.ChordView];
if(CGRectContainsPoint(_btnC.frame, touchPointFirstBtn))
{
if (!_btnC.isHighlighted)
{
if(!Boolean)
{
title = #"C";
[_tlbView reloadData];
NSLog(#"%#",#"touches C");
}
[_btnC setHighlighted:YES];
Boolean = YES;
}
}
else
{
[_btnC setHighlighted:NO];
Boolean = NO;
}
}