I have UIBUtton in UICollectionViewCell as show in image. I had set touchUpInside Action in xib. I had set background image of button is pink and lable as yellow. UIButton comes at top of the label. Now the problem is that UIButton in not getting touch event in pink area it only get touch events on orange area. why it is so.
- (IBAction)checkButtonTap:(id)sender event:(id)event
{
DLog(#"%s",__func__);
}
O a hidden view is overlapping the button due to which it is touch event was not reaching to the button.
Just to be sure I understand your issue, you have your UICollectionView in yellow and your UIbutton in pink, correct ?
If so, it seems you want to intercept the touchUpInside event outside your button's superview in yellow. You can look at this answer which deal with kind of problem.
Even if you finally find the solution to your problem, to clarify my answer, if you want to interact with an UIButton which is not inside its superview's frame, you may need to need to implement the method - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event of the superview (here the UICollectionViewCell):
- (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;
}
(thanks Noam!)
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTapped:)];
[buttonname addGestureRecognizer:tapGesture];
buttonname.userInteractionEnabled = YES;
(IBAction)imageTapped:(UITapGestureRecognizer *)gestureRecognizer {
if(gestureRecognizer.state == UIGestureRecognizerStateRecognized) {
[buttonname becomeFirstResponder];
}
}
O sorry, there was hidden view that is overlapping the button due to which touch event was not reaching to the button.
Related
Hi I have some buttons that trigger action methods.
In addition, I would like the user to be able to swipe left or right over the area with the buttons to show some different buttons
My idea was to add a UIView with a clear background color on top of the buttons so that the user could still see the buttons but could also swipe to the right or left.
However, when the view is over the buttons the buttons no longer work and when it is under the buttons, the swipe is not detected.
In addition to changing the view color to clear, I also tried adjusting the alpha however this seems to work the same way. When alpha of the UIView is zero, swipes are no longer detected and when alpha is greater than zero, the buttons no longer work.
Can anyone suggest a way to do this?
Thanks in advance for any suggestions.
Code I am using for buttons and to detect swipes seems standard. Trying to figure out a way to expose view and buttons at the same time.
Action methods to which buttons are wired:
//.h file
- (IBAction)showIncoming:(id)sender;
- (IBAction)showOutcoming:(id)sender;
/.m file
- (IBAction)showIncoming:(id)sender {
_showIncoming=YES;
_fetchedResultsController=nil;
[self.tableView reloadData];
[self updateInterface];
}
- (IBAction)showOutgoing:(id)sender {
_showIncoming=NO;
_fetchedResultsController=nil;
[self.tableView reloadData];
[self updateInterface];
}
Swipes:
//in viewWillAppear
UISwipeGestureRecognizer *rightRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(rightSwipeHandle:)];
rightRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[rightRecognizer setNumberOfTouchesRequired:1];
rightRecognizer.delegate = self;
[_topView addGestureRecognizer:rightRecognizer];
[_topView setUserInteractionEnabled:YES];
// [rightRecognizer release];
//........towards left Gesture recogniser for swiping.....//
UISwipeGestureRecognizer *leftRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(leftSwipeHandle:)];
leftRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
[leftRecognizer setNumberOfTouchesRequired:1];
leftRecognizer.delegate = self;
[_topView addGestureRecognizer:leftRecognizer];
[_topView setUserInteractionEnabled:YES];
}
- (void)rightSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
//Do moving
NSLog(#"Right Swipe performed");
_showOld=YES;
[self updateInterface];
}
- (void)leftSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
// do moving
NSLog(#"Left Swipe performed");
_showOld=NO;
[self updateInterface];
}
The approach I suggest is listening to a user moving a finger events and firing specified method that would check if user's finger is on your button's view. Sample code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchedViewWithTouches:touches andEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchedViewWithTouches:touches andEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchedViewWithTouches:touches andEvent:event];
}
- (void)didTouchedButton:(NSSet *)touches andEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
UIView *touchedView;
for (UIView *view in self.subviews) {
if(CGRectContainsPoint(view.frame, touchLocation)) {
touchedView = view;
break;
}
}
if (view == self.showIncomingButton) {
[self showIncoming:self.showIncomingButton];
} else if (view == self.showOutcomingButton) {
[self howOutcoming:self.showOutcomingButton];
}
}
Note that you will have to add two outlets for your buttons (if you don't have any). Also, you can get rid off (id)sender in your IBAction calls.
I have two UIViews. On second "UIView" I have one UIButton, but it must be over the both views.
When I click lower middle UIButton - event is fire, but when I click above the middle - nothing works.
How to fix it?
example image
move the button outside of both views and center it vertically
You should create a subclass of UIView for UIView2 and override hitTest like this:
- (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;
}
I'm dynamically creating buttons on UIView.
I can move them by dragging using this code
- (IBAction)draggedOut: (id)sender withEvent: (UIEvent *) event: (NSSet *)touches {
UIButton *selected = (UIButton *)sender;
selected.center = [[[event allTouches] anyObject] locationInView:hallView];
}
I can have more then one button. When I'm dragging some button, I need to check are there any intersections with other buttons?
How can I do this?
You should cycle through the other buttons in the view and, for each of them, check whether in intersect the dragged one via:
CGRectIntersectsRect (draggedButton.frame, anotherButton.frame);
You could use a function like:
- (BOOL)isThereButtonsIntersectionInView:(UIView *)containerView
forButton:(UIButton *)draggedButton
{
for(UIView *view in containerView.subviews){
if([view isKindOfClass:[UIButton class]] &&
view != draggedButton &&
CGRectIntersectsRect (view.frame, draggedButton.frame)){
return YES;
}
}
}
return NO;
}
Call this method passing as a parameter the view containing the buttons and the dragged button.
You can get frames of buttons and check using this
if(CGRectIntersectsRect(firstButton.frame, secondButton.frame)) {
return YES;
}
You simply need to compare the frame of this button with the frame of all the other buttons.
Here is a bit of sample code, which should probably go in your view controller because it requires knowledge of the other buttons.
- (BOOL) button:(UIButton*)button intersectsWithButtons:(NSArray*)moreButtons
{
CGRect buttonFrame = button.frame;
for (UIButton *checkButton in moreButtons) {
if (button != checkButton && CGRectIntersectsRect(buttonFrame, checkButton.frame))
return YES;
}
return NO;
}
Say I have 2 UIButtons next to each other and both of them will turn from white to black when I put my finger on them.
That obviously works fine, but if I put my finger on button 1 it turns black and then when I move my finger over the button 2 without lifting my finger, button 2 doesn't turn black, button 1 is still black.
So how can I "swipe" over one button and then over another one and change the highlighted button from the first one to the second one.
In your viewcontroller override the touchesMoved event. This will tell you when touches occur. The problem is that your buttons will have to have userInteractionEnabled set to NO so that they don't gobble the touch event. This will be ok if you're trying to do a custom slider or something where you don't need the actual button events.
Then in the touchesMoved you can loop through your buttons and see which button is pressed. Here is some code stolen from an excellent answer at Highlight the button when drag enter
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *t in touches) {
CGPoint touchPoint = [t locationInView:self.view];
CGPoint testPoint = [self.view convertPoint:touchPoint toView:aButton];
if ([aButton pointInside:testPoint withEvent:event]) {
//Do something
}
//rest of code
[self.button1 addTarget:self
action:#selector(dragEnter:)
forControlEvents:UIControlEventTouchDragEnter];
[self.button2 addTarget:self
action:#selector(dragEnter:)
forControlEvents:UIControlEventTouchDragEnter];
[self.button1 addTarget:self
action:#selector(dragExit:)
forControlEvents:UIControlEventTouchDragExit];
[self.button2 addTarget:self
action:#selector(dragExit:)
forControlEvents:UIControlEventTouchDragExit];
- (void)dragEnter:(id)sender
{
UIButton *button = (UIButton *)sender;
button.highlighted = YES;
}
- (void)dragExit:(id)sender
{
UIButton *button = (UIButton *)sender;
button.highlighted = NO;
}
In my app I should implement the drag and drop of a imageView; the problem is that my imageView is inside a scrollview; it's my code
- (void) viewDidLoad{
[super viewDidLoad];
UILongPressGestureRecognizer *downwardGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(dragGestureChanged:)];
[scrollViewAlfabeto addGestureRecognizer:downwardGesture];
for (UIGestureRecognizer *gestureRecognizer in myscrollView.gestureRecognizers)
{
[gestureRecognizer requireGestureRecognizerToFail:downwardGesture];
}
}
- (void) dragGestureChanged:(UIPanGestureRecognizer*)gesture
{
CGPoint point = [gesture locationInView:scrollViewAlfabeto];
if (gesture.state == UIGestureRecognizerStateBegan)
{
[imageViewToMove removeFromSuperview];
[self.view addSubview:imageViewToMove];
UIView *draggedView = [myscrollView hitTest:point withEvent:nil];
if ([draggedView isKindOfClass:[UIImageView class]])
{
imageViewToMove = (UIImageView*)draggedView;
}
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
imageToMove.center = point;
}
else if (gesture.state == UIGestureRecognizerStateEnded ||
gesture.state == UIGestureRecognizerStateCancelled ||
gesture.state == UIGestureRecognizerStateFailed)
{
// Determine if dragged view is in an OK drop zone
// If so, then do the drop action, if not, return it to original location
NSLog(#"point.x final:%f", point.x);
NSLog(#"point.y final:%f", point.y);
if (CGRectContainsPoint(goal.frame, point)){
imageToMove.frame = CGRectMake(167, 159, 100, 100);
}
else{
[imageToMove removeFromSuperview];
[myscrollView addSubview:imageToMove];
[imageToMove setFrame:CGRectMake(12, 38, 100, 100)];
imageToMove = nil;
}
}
}
Then with my code I'm able to take an imageView from scrollView with longpress, drag it inside "self.view"; also if I drop this imageView over another imageView in self.view it puts on it. It work fine. But I have two problems:
1- when I drag this imageView and I do
[imageViewToMove removeFromSuperview];
[self.view addSubview:imageViewToMove];
the image view don't appear under my finger but in other position and I want that it remains under my finger
2- This code work only the first time when I launch my viewcontroller, because If I don't drop the imageview over other imageview inside self.view, itr return inside scrollview, but If I want drag it a second time, it don't work.
Can you help me?
I'm not advanced in objc, but...
Allow user ineraction [self.view userInteractionEnabled:YES];
Try [self.view setMultipleTouchEnabled:YES];
Taken from the documentation of UIView in relation to userInteractionEnabled:
Discussion
When set to NO, user events—such as touch and
keyboard—intended for the view are ignored and removed from the event
queue. When set to YES, events are delivered to the view normally. The
default value of this property is YES.
During an animation, user interactions are temporarily disabled for
all views involved in the animation, regardless of the value in this
property. You can disable this behavior by specifying the
UIViewAnimationOptionAllowUserInteraction option when configuring the
animation.
Hope it works