I have an UIButton and I want to move that button by touching and swiping it in the screen. When I release the touch it will be in the current position. Explain clearly, please.
You can move a view by using touch moved event. There is a sample tutorial MoveMe by Apple which drags a view and after releasing the touch animate the view. Check specially the touch events (touchesBegan, touchesMoved, touchesEnded) in MoveMeView.m to get the idea how they have moved placardView. You can move your button just like the placardView.
Taken from 'drag' move a uibutton so it acts like uiScrollView
check this
you should make move frame from the points and move frame accordingly so that your button moves in places of touches
If you are scripting for iOS 3.2 and above, consider using UIPanGestureRecognizer.
Simply attach an instance of it like this,
...
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
panGesture.maximumNumberOfTouches = 1;
panGesture.minimumNumberOfTouches = 1;
[self.button addGestureRecognizer:panGesture];
[panGesture release];
...
and define handlePan: like this,
- (void)handlePan:(UIPanGestureRecognizer *)panGesture {
CGRect buttonFrame = self.button.frame;
CGPoint translation = [panGesture translationInView:panGesture.view];
buttonFrame.origin.x += translation.x;
buttonFrame.origin.y += translation.y;
[panGesture setTranslation:CGPointMake(0, 0) inView:panGesture.view];
self.button.frame = buttonFrame;
}
Related
I have googling a while for a solution. But didn't get anything what I needed. later I found a Library that works the same but in a reverse manner and the library is this LNPopupController
My Question is how Can I make a viewcontroller move from top to bottom on swipe Gesture ? Can I tweak this library to achieve it ?
You're looking to implement a UIPanGesture rather than a UISwipeGesture based of the project you linked.
Create a UIPanGestureRecognizer
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(viewDragged:)];
[yourCustomView addGestureRecognizer:panGestureRecognizer];
Then implement the "viewDragged:" method.
heightForTheDraggableRegionLeftInTheView is a value of how much of the view you want to leave on the screen when the user tries to dismiss youCustomView.
- (void) viewDragged: (UIPanGestureRecognizer *) gestureRecognizer {
CGRect viewFrame = gestureRecognizer.view.frame;
CGPoint locationOfTouch = [gestureRecognizer locationInView:self.view];
// Let the user's finger match with the bottom of the NotificationView
[gestureRecognizer.view setFrame:CGRectMake(viewFrame.origin.x, locationOfTouch.y + draggableHeightOfTheNotificationView - viewFrame.size.height, viewFrame.size.width, viewFrame.size.height)];
// If the yourCustomView is being dragged too high, make sure you leave a draggable area so that the user can drag it later
if (locationOfTouch.y >= self.view.frame.size.height - heightForTheDraggableRegionLeftInTheView) {
[gestureRecognizer.view setFrame:CGRectMake(viewFrame.origin.x, 0, viewFrame.size.width, viewFrame.size.height)];
}
// If the NotificationView will go to far below the screen keep it resting at the bottom of the screen
if (locationOfTouch.y <= draggableHeightOfTheNotificationView) {
[gestureRecognizer.view setFrame:CGRectMake(viewFrame.origin.x, draggableHeightOfTheNotificationView * 2 - self.view.frame.size.height, viewFrame.size.width, viewFrame.size.height)];
}
}
I had a project which contains lots of UIButton, using xcode 4.5 and storyboard and ARC. after testing in ios6, everything goes fine. But in ios5, UIButton touch up inside event not working, the action not called. I tried to use touch down and it works. However, I have a lot of UIButton, I cannot change that one by one. what's more, the touch down event does give a good experience.
I used code below in many of my view controllers:
in viewDidLoad:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
-(void)dismissKeyboard {
[aTextField resignFirstResponder];
}
this might be the reason. I will check it out later. But it works in ios6.
Do you know what's wrong ? Thanks very much!
I had the same problem to you.
That's because the touch event in iOS5 is prevented when the gestureRecognizer you registered captures the event.
There are two solutions.
One:
1) Add a new view inside your view. It should have the same level to the buttons. The priority of the buttons should be higher than the new view.
2) change the call of 'addGestureRecognizer' to the new view.
[self.newView addGestureRecognizer:tap];
Two:
1) Implement the code below. You should return NO when the point is in the buttons.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
CGPoint point = [gestureRecognizer locationInView:self.view];
NSLog(#"x = %.0f, y = %.0f", point.x, point.y);
if (CGRectContainsPoint(self.testBtn.layer.frame, point))
return NO;
return YES;
}
ps.
you should import QuartzCore.h to access layer's attributes.
#import <QuartzCore/QuartzCore.h>
Just use the property "cancelsTouchesInView" (NO) on UITapGestureRecognizer tap
Example:
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTap)];
gesture.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:gesture];
Override your button parent view pointinside method, setting a new custom frame size that contains your button.
I've added a TapGestureRecognizer to my self.view:
tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTap:)];
tap.numberOfTapsRequired = 1;
tap.numberOfTouchesRequired = 1;
[self.view addGestureRecognizer:tap];
[tap release];
The view contains a single UIScrollView with images and labels. I want to detect if the user taps on a label or not.
- (void)singleTap:(UIGestureRecognizer*)gestureRecognizer {
CGPoint pt = [gestureRecognizer locationInView:self.view];
UIView *v = [self.view hitTest:pt withEvent:nil];
if ([v isKindOfClass:[UILabel class]]) {
NSLog(#"label!");
return;
}
// else do other stuff if its not a label
However I don't see the label! in my log.
I think it's because userInteractionEnabled is by default NO on UILabels. Try turning that on.
EDIT: It was really a guess, but just to confirm, Apple docs on [UIView hitTest:withEvent:] state:
This method ignores view objects that are hidden, that have disabled user interaction, or have an alpha level less than 0.01.
Your subviews, such as the labels themself, actually hide the user interactions from the underlying view.
Why don't you add the gesture recognizers to your label(s).
Alternatively you may want to use UIButton for the labels.
Or -
if you do not want to determine which label has been touched, you may want to add an invisible view (an empty view, neither a hidden one nor one with alpha=0) on top of all labels and add the gesture recognizers to those.
I have a UIButton that i'd like the user to be able to drag with TouchDragInside. How do i get the button to move as the user moves their finger?
As Jamie noted, a pan gesture recognizer is probably the way to go. The code would look something like what follows.
The button's view controller might add a gesture recognizer to the button (possibly in viewDidLoad) as follows:
UIPanGestureRecognizer *pangr = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
[myButton addGestureRecognizer:pangr];
[pangr release];
And, the view controller would have the following target method to handle the gesture:
- (void)pan:(UIPanGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateChanged ||
recognizer.state == UIGestureRecognizerStateEnded) {
UIView *draggedButton = recognizer.view;
CGPoint translation = [recognizer translationInView:self.view];
CGRect newButtonFrame = draggedButton.frame;
newButtonFrame.origin.x += translation.x;
newButtonFrame.origin.y += translation.y;
draggedButton.frame = newButtonFrame;
[recognizer setTranslation:CGPointZero inView:self.view];
}
}
CORRECTED as per rohan-patel's comment.
In the previously posted code , the x and y coordinate's of the origin of the button's frame were set directly. It was incorrect as: draggedButton.frame.origin.x += translation.x. A view's frame can be changed, but the frame's components cannot be changed directly.
You probably don't want to use TouchDragInside. That is a method of recognizing that a button or other control has been activated in a certain way. To move the button, you probably want to use a UIPanGestureRecognizer and then change the buttons position in its superview as the users finger moves around.
You have to implement these four methods, touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:, and touchesCancelled:withEvent: in the view that holds the button. The property you are referring to cannot be used directly to drag any uiview
I have a UIView inside of a UIScrollView, both created using IB. The UIView scrolls horizontally inside the UIScrollView. I want to detect left and right 2 finger swipes.
Borrowing from the sample code I found in SmpleGestureRecognizers, I have put the following code in the viewDidLoad method of the UIScrollView's ViewController...
UIGestureRecognizer *recognizer;
UISwipeGestureRecognizer *swipeRightRecognizer, *swipeLeftRecognizer;
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
swipeRightRecognizer = (UISwipeGestureRecognizer *)recognizer;
swipeRightRecognizer.numberOfTouchesRequired = 2;
[self.view addGestureRecognizer:swipeRightRecognizer];
[recognizer release];
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
swipeLeftRecognizer = (UISwipeGestureRecognizer *)recognizer;
swipeLeftRecognizer.numberOfTouchesRequired = 2;
swipeLeftRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipeLeftRecognizer];
[recognizer release];
I have set in the viewcontroller.h. and have the following delegate method...
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return YES;
}
I am assuming this is a valid gestureRecognizer delegate method, but I cannot find any reference to it in the documentation.
I do not get any errors but nothing happens when I do a 2 finger swipe. The delegate method is not called and neither is my action method. I tried removing the numbeOfTouchesRequired call to see if it might work with a single finger swipe to no avail.
Am I adding the gestureRecognizers to the right view? I tried adding it to the UIView, the UIScrollView as well as self.view.superView.
The sample code runs great. The only difference I can see between my implementation of the code and the sample code is the fact that I used IB to create the views and the sample code did not. I suspect that something is consuming the swipe gesture before it gets to my recognizers.
What am I doing wrong.
Thanks,
John
I had the same problem and I solved by using UIPanGestureRecognizer instead of UISwipeGestureRecognizer.
To emulate the detection of swipe, we'll play with the speed of gesture in scrollview.
If the speed of x direction >= 3000 (for example) the swipe will be detected.
If x>0 it will be a right swipe.
The code I implemented to resolve your situation is:
In a uiscrollview named _scroll1:
UIPanGestureRecognizer *pan;
pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(Swipe4ScrollViews:)];
[pan setMinimumNumberOfTouches:2];
[_scroll1 addGestureRecognizer:pan];
[pan release];
With a global BOOL variable named _panning, Swipe4ScrollViews will do the hard job:
-(void)Swipe4ScrollViews:(UIPanGestureRecognizer *)sender
{
if(sender.state == UIGestureRecognizerStateBegan) _panning = NO;
CGPoint v =[sender velocityInView:_scroll1];
NSLog(#"%f, %f",v.x,v.y);
if( (abs(v.x) >= UMBRAL) && !_panning)
{
_panning = YES;
[sender cancelsTouchesInView];
if(v.x>0) NSLog(#"Right");
else NSLog(#"Left");
[self doSomething];
}
}
I encapsulated it on a UIGestureRecognizer subclass: UISwipe4ScrollGestureRecognizer
The biggest difference between the sample code and your code is that your code involves a UIScrollView.
Internally, scroll views, table views, and web views all use gesture recognizers to some degree. If you're expecting to receive gestures within those views – gestures that are similar to the ones already supported internally – they will almost certainly be consumed or significantly delayed before you can get to them. Receiving gestures outside or above those views should work fine, if your use case supports it.
Try setting the delayContentTouches-property of the UIScrollView to NO, maybe it'll help.