What is the event in iPhone development to write code to a slide left and slide right operation.
As in when you slide the view of your phone, you go into another view. What is the event that i should write my code ?
The event you are looking to catch is called a swipe. Apple provides a UISwipeGestureRecognizer class to handle this for you. Implementation advice can be found in the Gesture Recognizers section of the Event Handling Guide for iOS.
Briefly, you create the recognizer:
UISwipeGestureRecognizer *swipeGestureRecognizer =
[[[UISwipeGestureRecognizer alloc]
initWithTarget:self action:#selector(swipe:)] autorelease];
Then set how many fingers the swipe is, and what direction it needs to be in:
swipeGestureRecognizer.numberOfTouchesRequired = 2; // default is 1
// allow swiping either left or right, default is right only
swipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionLeft |
UISwipeGestureRecognizerDirectionRight;
And then add it to your view:
[self.view addGestureRecognizer:swipeGestureRecognizer];
When the user swipes, your swipe: method will get called.
Darvids0n covered a gesture to slide the view out. I interpreted the question as an animation to slide the view out, in which case you'll want UIView's transitionFromView:toView:duration:options:completion: class method:
[UIView transitionFromView:view1 toView:view2 duration:1.0 options:(UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionTransitionFlipFromLeft) completion:NULL];
This actually gives you a curl. If you want a slide, you'll have to code a custom animation. Check out UIView's documentation and especially the 'animateWithDuration:animations:' class method.
Related
I'm trying to do a Tabbar Controller like below effect:
By swiping an viewcontroller will redirect to next tab. How can we achieve this in iOS? Is there any other controls to do like this?
Just add UISwipeGestureRecognizer to your tabBarView controller and change your tabBar index after swipe.
swipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:#selector(swipeMethod:)];
swipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionLeft;
[self addGestureRecognizer:swipeRecognizer];
And my method to handle swipe is :
-(void)swipeMethod: (UISwipeGestureRecognizer *) sender
{
NSLog(#"Swipe!");
}
EDIT
Or you can use UIScrollView with paging enable and UIView to display your data.
Here is the tutorial you are looking for Tabbar Controller with swipte effect
There is a library for this on GitHub, it is called MGSwipeTabBarController and is designed to do exactly what you are looking for.
It is as simple as :
NSArray *viewControllers = . . . //your view controllers
MGSwipeTabBarController *swipeController = [[MGSwipeTabBarController alloc] initWithViewControllers:viewControllers];
Please Note that it is only compatible with iOS7 and + and that you'll still need to design your own tab bar that respond to scroll events using the MGSwipeTabBarControllerDelegateprotocol.
https://github.com/mglagola/MGSwipeTabBarController
https://github.com/nicklockwood/SwipeView
you can use this class to achieve your goal...
or else you have to make animation for tap on tabbar using following method,
[UIView transitionFromView:<#(UIView *)#> toView:<#(UIView *)#> duration:<#(NSTimeInterval)#> options:<#(UIViewAnimationOptions)#> completion:<#^(BOOL finished)completion#>]
If anyone is still looking you can find another implementation here on this youtube series
https://www.youtube.com/watch?v=3Xv1mJvwXok&list=PL0dzCUj1L5JGKdVUtA5xds1zcyzsz7HLj
Edit:
So to my knowledge and according to the video, the idea is that you'll want to use two UICollectionViews in one view controller. One collection view to display the content (apps) and the other for the horizontal navigation containing the categories.
To create the green 'highlight' bar you can use a UIView and adjust the height/width of the bar using constraints - heightAnchor/widthAnchor and add that to the navigation bar.
To get the bar moving with the distance the user will swipe, there is a method you can override to capture the horizontal scrolling called scrollViewDidScroll. From here you'll want to provide a variable from your the UIView's constraint (of type NSLayoutConstraint) to be able to update the x position of the UIView
override func scrollViewDidScroll(_ scrollView: UIScrollView)
{
print(scrollView.contentOffset.x)
menuBar.myGreenBarLeftConstraint.constant = scrollView.contentOffset.x / 4
//or however many categories you have
}
I'd like to detect swipe on the entire screen, however, the screen contains UIButtons, and if the user taps one of these buttons, I want the Touch Up Inside event to be triggered.
I've create a UIView on the top of my screen, and added a UIPanGestureRecognizer on it to detect the swipe, but now I need to pass the gesture through that view when I detect that it's a tap rather than a swipe.
I know how to differentiate the gestures, but I've no idea on how to pass it to the view below.
Can anyone help on that? Thanks!
Thanks for your answer. The link helped me to solve part of my problem.
I've set the buttons as subviews of my gestureRecognizer view and I can now start a swipe from one of the buttons (and continue to use the buttons as well). I managed to prevent the buttons to go to the "down" state by using the following code :
UIPanGestureRecognizer *swipe = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(swipeDetected:)];
swipe.maximumNumberOfTouches = 1;
swipe.delaysTouchesBegan =YES;
swipe.cancelsTouchesInView = YES;
[self.gestureRecognitionView addGestureRecognizer:swipe];
there is a BOOL property of UIGestureRecognizer cancelsTouchesInView. default is yes. set it to NO , and the touches will pass thru to the UIView
also have a look at the solution for this question
If you want to prevent the recognizer from receiving the touch at all, UIGestureRecognizerDelegate has a method gestureRecognizer:shouldReceiveTouch: you can use:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// don't override any other recognizers
if (gestureRecognizer != panRecognizer) {
return YES;
}
CGPoint touchedPoint = [touch locationInView:self.someButton];
return CGRectContainsPoint(self.someButton.bounds, touchedPoint) == NO;
}
I have a UIScrollView inside a UIView. For customized paging purpose I have set the clipping of this UIScrollView to No so the UIScrollView still shows up in Region A and Region B of the UIView.
[ region A [UIScrollView] region B ]
Now I want Region A B to be able to trigger scroll events of the UIScrollView's when touched.. I remember there is an one liner (something like [X addGestureRecognizer ...]) that does the trick but I've forgotten what it is... It would be great if someone can tell me what that is!
If you want to redirect the UIScrollView's scrolling gestures to another view, you can do this:
[paddingView addGestureRecognizer:scrollView.panGestureRecognizer];
This won't let you have a fluid control on your scrolling, like the one you get from the UIScrollView.
However, you can use this code :
UISwipeGestureRecognizer *leftSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(viewSwiped:)];
[leftSwipeGestureRecognizer setDirection:UISwipeGestureRecognizerDirectionLeft];
[self.view addGestureRecognizer:leftSwipeGestureRecognizer];
[leftSwipeGestureRecognizer release];
UISwipeGestureRecognizer *rightSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(viewSwiped:)];
[rightSwipeGestureRecognizer setDirection:UISwipeGestureRecognizerDirectionRight];
[self.view addGestureRecognizer:rightSwipeGestureRecognizer];
[rightSwipeGestureRecognizer release];
firing this method :
- (void)viewSwiped:(UISwipeGestureRecognizer *)swipeGestureRecognizer {
switch (swipeGestureRecognizer.direction) {
case UISwipeGestureRecognizerDirectionLeft:
// Make your scroll view scroll
break;
case UISwipeGestureRecognizerDirectionRight:
// Make your scroll view scroll
break;
default:
// Do Nothing
break;
}
}
It will allow you to retrieve the swipes gestures and page your UIScrollView accordingly.
Two other solutions might be better :
You could use the UIPanGestureRecognizer the same way as above. It recognizes real pan gestures and not only discrete swipes but the implementation of the sync between your finger and the UIScrollView will be slightly more complicated.
You could let your UIScrollView take the total width of the UIView and manage the paging by yourself, recalculating your steps while tracking the current state of the UIScrollView via UIScrollViewDelegate. Again, a bit harder.
Hope this will help,
I'm animating a couple of views with animateWithDuration: and i'm simply unable to detect any touches on them.
I've tried simple touch handling (touchesEnded:) and a tapGestureRecognizer.
First i've animated them with CGAffineTransformTranslation but then i realized that this won't if i check the coordinate with touchesMoved: so i switched to animate the frame property. I quickly noticed, that the frame values are not really changing during the animation so i dropped the touchesEnded: idea. So i changed to a tapGestureRecognizer which doesn't work too.
I've enabled userInteraction on all views and i also added the option UIViewAnimationOptionAllowUserInteraction to the animation.
Here's the code of the animation and the stuff that happens before:
// init the main view
singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapOnItem:)]; // singleFingerTap is an ivar
// code somewhere:
// userItem is a subview of MainView
[userItem addGestureRecognizer:singleFingerTap];
[UIView animateWithDuration:animationTime
delay:0.0f
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction
animations:^{
userItem.frame = CGRectMake(-(self.bounds.size.width + userItem.frame.size.width), userItem.frame.origin.y, userItem.frame.size.width, userItem.frame.size.height);
}
completion:^(BOOL finished) {
if (finished) {
[unusedViews addObject:userItem];
[userItem removeFromSuperview];
[userItem removeGestureRecognizer: singleFingerTap];
}
}
];
And here's the gesture recognizer:
- (void) handleTapOnItem:(UITapGestureRecognizer *)recognizer{
NSLog(#"Touched");
}
So how can i actually get a touch from an animated View or what is the best solution?
Adding transparent uibutton to each view is not an option. :(
When an animation is applied to a view, the animated property changes to its end value right away. what you are actually seeing on screen is the presentation layer of your views layer.
I wrote a blog post about hit testing animating views/layers a while back that explain it all in more detail.
While anything is being moved using Core Animation touches on the object are halted until the object completes its movement. Interesting tid-bit, if you move the object and touch where its final location will be, the touch is picked up. This is because as soon as the animation is started the frame of the object is set to the ending point, it is not updated as it moves across the screen.
You might have to look into alternate technologies like Quartz or OpenGL ES to detect touches on your views as they are being moved.
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.