I want to do smooth swipe animation. I just want to that swipe only can be possible when user swipe the page from the right or left border only. Middle of the page swipe should not possible.Both the swipe should be possible left to right and right to left.
I have tried lots of swipe animation sample code or demo code. But its not what I want. I want animation like this https://itunes.apple.com/in/app/clear-tasks-to-do-list/id493136154?mt=8
In this app its like when we touch the right border its swipe smoothly.Please guide me to do this animation. Thanks in advance.
Sorry for the late reply. Just saw this question.
If you want your swipe operation to happen from the edges, create 2 subviews in the far ends (left and right) of your main view and give then a width of 30 or 40.
I believe you have 2 other views popin up from left and right. So inorder to do this you need to add 2 views right on top of your main view.
Now for the left view, set it's right horizondal space constraint connecting to the main view to a value lesser than (-1)x width of the main view. For the right view set its right horizondal space constraint connecting to the main view to a value greater than the width of the main view, so that both the views are outside the main view
X stands for a value greater than or equal to the mainview's width
Add two NSLayoutConstraint variables as IBOutlet holding these 2 values.
NSLayoutConstraint *leftViewHorizondalRightPadding;
NSLayoutConstraint *rightViewHorizondalRightPadding;
Now add the UISwipeGestures to these subViews (indicated in orange).
UISwipeGestureRecognizer *leftToRightSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
[leftToRightSwipe setDirection:UISwipeGestureRecognizerDirectionRight];
[self.leftSubview addGestureRecognizer:leftToRightSwipe];
UISwipeGestureRecognizer *rightToLeftSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
[rightToLeftSwipe setDirection:UISwipeGestureRecognizerDirectionLeft];
[self.rightSubview addGestureRecognizer:rightToLeftSwipe];
///Now in the swipe handler distinguish the swipe actions
-(void)handleSwipe:(UISwipeGestureRecognizer *)recognizer {
NSLog(#"Swipe received.");
if (recognizer.direction == UISwipeGestureRecognizerDirectionRight) {
//It's leftToRight
leftViewHorizondalRightPadding.constant = 0;
[UIView animateWithDuration:1
animations:^{
[self.view layoutIfNeeded];
}];
}
else {
//It's rightToLeft
rightViewHorizondalRightPadding.constant = 0;
[UIView animateWithDuration:1
animations:^{
[self.view layoutIfNeeded];
}];
}
}
}
This will make a swipe animation from left to right and right to left.
Hope this helps..
After you create the 2 swipe gesture recognisers you should set their delegates. Then use this delegate method:
UISwipeGestureRecognizer *_swipeLeft;
UISwipeGestureRecognizer *_swipeRight;
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
static const CGFloat borderWidth = 50.0f;
if(gestureRecognizer == _swipeLeft) {
return [gestureRecognizer locationInView:self].x > self.frame.size.width - borderWidth;
}
else if(gestureRecognizer == _swipeRight) {
return [gestureRecognizer locationInView:self].x < borderWidth;
}
return YES;
}
Do note that for smooth swiping/dragging you will probably need to use a pan gesture or even long press gesture recogniser rather then the swipe gesture. They are very similar except the long press takes a bit of time to begin (which is settable). If you use them you may still want to use the same delegate method. Or you can simply do all the code in the gestures target method. Try something like this:
CGPoint gestureStartPoint;
- (void)dragFromBoreder:(UIGestureRecognizer *)sender {
static const CGFloat borderWidth = 50.0f;
switch (sender.state) {
case UIGestureRecognizerStateBegan: {
CGPoint location = [sender locationInView:self];
if(location.x > borderWidth || location.x < self.frame.size.width-borderWidth) {
//break the gesture
sender.enabled = NO;
sender.enabled = YES;
}
else {
gestureStartPoint = location;
}
break;
}
case UIGestureRecognizerStateChanged: {
CGPoint location = [sender locationInView:self];
CGFloat deltaX = location.x - gestureStartPoint.x;
UIView *viewToMove;
CGPoint defaultCenter;
viewToMove.center = CGPointMake(defaultCenter.x+deltaX, defaultCenter.y);
break;
}
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled: {
CGPoint location = [sender locationInView:self];
CGFloat deltaX = location.x - gestureStartPoint.x;
/*
if(deltaX > someWidth) {
show the left view
}
else if(deltaX < -someWidth) {
show the right view
}
else {
put everything back the way it was
}
*/
break;
}
default:
break;
}
}
In ios7 there is a gesture recogniser specifically for gestures beginning from the edge of the screen. You should use this.
I can't help with your "smooth" problem, because you haven't said what your current animation looks like or how you are doing it. But a pan gesture, like the one linked, which directly updates view positions, will track the user's movement much more smoothly than a swipe.
Related
How to animate constraint change smoothly with pan gesture in iOS?
I am trying to develop a screen, where a view is at bottom of the screen. And I've added pan gesture to that view. On dragging that view I want change top constraint of that view. Pan gesture is only allowed in vertical and downward direction. I have added some limit for dragging the view. It working but not smoothly. How to animate constraint change smoothly with pan gesture? Here is my code.
- (void)handleGesture:(UIPanGestureRecognizer *)sender
{
CGPoint velocity = [sender velocityInView:_locationContainer];
[sender setTranslation:CGPointMake(0, 0) inView:self.view];
if (fabs(velocity.y) > fabs(velocity.x)) {
NSLog(#"velocity y %f ",velocity.y * 0.13);
if(velocity.y < 0 && (self.locationDetailsTop.constant > minimumTop) )
{
NSLog(#"gesture moving Up");
self.locationDetailsTop.constant = self.locationDetailsTop.constant - fabs(velocity.y * 0.1);
}
else if (self.locationDetailsTop.constant < firstTop)
{
NSLog(#"gesture moving Bottom");
self.locationDetailsTop.constant = self.locationDetailsTop.constant + fabs(velocity.y * 0.1);
}
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.1 animations:^{
[self.mapView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.locationContainer.frame.origin.y)];
}];
}
}
This is sample image,
My screen is of the same kind like this, But on my screen, there is a map view instead of the calender view
To move view while user is touching a screen, you can use translationInView: property. You can set a translation to current constraint's value and get new value (in a handler of UIGestureRecognizerStateBegan) and change a constraint's constant in a handler of UIGestureRecognizerStateChanged:
- (void)padRecognizerStateChanged:(UIPanGestureRecognizer*)sender
{
if(sender.state == UIGestureRecognizerStateBegan)
{
[sender setTranslation:CGPointMake(0.0, [self getConstraintValue]) inView: _locationContainer];
}
else if (sender.state == UIGestureRecognizerStateChanged)
{
[self setConstraintValue: [sender translationInView:_locationContainer].y];
[self.view setNeedsLayout];
}
}
You can use velocity if you need to move view when a user raised his thumb over the screen for upward or downward movement. For example, you can implement deceleration effect.
If you want it to animate smoothly, try calling layoutIfNeeded inside the animation block like so:
[UIView animateWithDuration:0.1 animations:^{
[self.view layoutIfNeeded];
[self.mapView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.locationContainer.frame.origin.y)];
}];
I think the original question was asking how to perform this animation smoothly. However, if the map view constraints are linked to the dragged view constraints, due to the polynomial relationship between autolayout constraints and laying out the MKMapView the computation will be quite intense and therefore there will likely be lag. I suggest disconnecting the map constraints from the dragged view constraints if the UI/UX design allows.
Ok so I am helping convert an android game to iOS. The game is based on 2048, but with letters instead of numbers. I have a good bit of it working but am still learning Objective C/iOS quirks. So far I have the tiles/grid working, movement is working, etc but I need a bit of help. The goal is to allow the user to long-press on a tile to select it, then slide their finger to an adjacent tile to begin spelling a word. I have the long press portion implemented but I'm at a bit of a loss on how to get it to long-press then swipe. On top of this I already have a swipe that allows the user to move the tiles. In searching on here I've seen suggestions about subclassing so I am figuring I need to subclass the UISwipeGestureRecognizer method. I already put in the simultaneously gesture recognizer, but am unsure where to go from here.
So, there are several questions to this.
What would be the best way to do this? Implement a subclass of each UISwipeGestureRecognizer?
Will my current swipe detection interfere? (right now a swipe by itself moves tiles in direction of swipe)
I would guess I need to do a (if long press) then activate subclassed swipe methods?
Any examples to answer the above questions would be of great help. I'm not asking you to do it for me but at least point me in a general direction. Thanks!
Code below.
// Grid.m
#import "Grid.h"
#import "Tile.h"
- (void)didLoadFromCCB {
// listen for swipes to the left
UISwipeGestureRecognizer * swipeLeft= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeLeft)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[[[CCDirector sharedDirector] view] addGestureRecognizer:swipeLeft];
// listen for swipes to the right
UISwipeGestureRecognizer * swipeRight= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeRight)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[[[CCDirector sharedDirector] view] addGestureRecognizer:swipeRight];
// listen for swipes up
UISwipeGestureRecognizer * swipeUp= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeUp)];
swipeUp.direction = UISwipeGestureRecognizerDirectionUp;
[[[CCDirector sharedDirector] view] addGestureRecognizer:swipeUp];
// listen for swipes down
UISwipeGestureRecognizer * swipeDown= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeDown)];
swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
[[[CCDirector sharedDirector] view] addGestureRecognizer:swipeDown];
// listen for long press
UILongPressGestureRecognizer *longpress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(onLongPress:)];
[longpress setMinimumPressDuration:0.5];
[[[CCDirector sharedDirector] view] addGestureRecognizer:longpress];
}
- (void)swipeLeft {
[self move:ccp(-1, 0)];
}
- (void)swipeRight {
[self move:ccp(1, 0)];
}
- (void)swipeDown {
[self move:ccp(0, -1)];
}
- (void)swipeUp {
[self move:ccp(0, 1)];
}
// detect longpress, convert to NodeSpace and check if touch location is within tile boundingbox. If yes, set background white, text black.
- (void)onLongPress:(UILongPressGestureRecognizer *) recognizer {
CGPoint touchPoint = [[CCDirector sharedDirector] convertToGL:[recognizer locationInView:[recognizer view]]];
touchPoint = [self convertToNodeSpace:touchPoint];
if (recognizer.state == UIGestureRecognizerStateBegan) {
for (Tile *tile in self.children) {
if([tile isKindOfClass:[Tile class]]) {
CGRect tileBoundingBox = tile.boundingBox;
if (CGRectContainsPoint(tileBoundingBox, touchPoint)) {
tile.backgroundNode.color = [CCColor whiteColor];
tile.valueLabel.color = [CCColor blackColor];
[self spellWord:tile.value];
[_word setString:[_word lowercaseString]];
CCLOG(#"%#", _word);
}
}
}
}
if (recognizer.state == UIGestureRecognizerStateChanged) {
}
if (recognizer.state == UIGestureRecognizerStateEnded) {
for (Tile *tile in self.children) {
if([tile isKindOfClass:[Tile class]]) {
CGRect tileBoundingBox = tile.boundingBox;
if (CGRectContainsPoint(tileBoundingBox, touchPoint)) {
tile.backgroundNode.color = [tile getColor:tile.value];
tile.valueLabel.color = [self getContrastColor:r green:g blue:b];
}
}
}
}
}
// allow for simultaneous gestures
- (BOOL)gestureRecognizer:(UIGestureRecognizer *) recognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
In answer to your questions:
This doesn't strike me as a coding situation that requires one to subclass UILongPressGestureRecognizer. Having said that, subclassing is often a nice way to clean up one's view controller code so you don't have gory gesture recognizer code in the view controller class. But there's nothing here (as I understand it) that demands that. You generally dive into subclassing of gesture recognizers where you need some special custom behavior (e.g. have the gesture fail if some complicated criterion fails). I'd first see if you could achieve the desired UX with standard gestures before I went down that road, though.
The only reason I could see the swipe gestures interfering with each other is that you've specified that shouldRecognizeSimultaneouslyWithGestureRecognizer should return YES. That's used in cases where you need multiple recognizers running at the same, which doesn't seem necessary here (and only a source of problems).
It's unclear to me as to whether you really wanted a separate swipe gesture or whether you just wanted a single gesture ("long press and drag"). If you needed that separate swipe gesture, though, you would generally specify the relative priority of gesture recognizers by specifying requireGestureRecognizerToFail (e.g. have the swipe require long press to fail in order for the swipe to be recognized). But if you really only have one gesture ("long press and drag"), then only one gesture recognizer is needed.
It seems unnecessary. If you want to detect movement after the long press has been recognized, you can put that "move after long press" code in the if statement for UIGestureRecognizedStateChanged in your onLongPress, which occurs after the long press has been recognized, but before the user lifts their finger. The UILongPressGestureRecognizer is a continuous gesture recognizer which will continue to get updates as the user's finger moves after the gesture was initially recognized.
I know you didn't ask for code, but if you wanted a swipe gesture, as well as a long press gesture that was, essentially, the idea of picking it up and dragging it, you could do something like the following. Note, I make the swipe gesture require the long press to fail, so if the user is long pressing, that takes precedence, otherwise it does swipe. But you may not need the swipe gesture at all, so if you don't need it, just remove it altogether:
#import <UIKit/UIGestureRecognizerSubclass.h>
- (void)viewDidLoad {
[super viewDidLoad];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
[self.view addGestureRecognizer:longPress];
// if you needed a second gesture, a swipe, completely distinct from the long press and drag
// gesture, you could add it like so:
//
// UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
// [swipe requireGestureRecognizerToFail:longPress];
// // do additional swipe configuration
// [self.view addGestureRecognizer:swipe];
}
- (void)handleSwipe:(UISwipeGestureRecognizer *)gesture
{
// do your separate swipe stuff here
}
- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
{
static UIView *tileToMove;
static CGPoint startCenter;
static CGPoint startLocation;
CGPoint location = [gesture locationInView:self.view];
switch (gesture.state) {
case UIGestureRecognizerStateBegan:
{
// find the tile
tileToMove = [self findTileToMove:location];
if (tileToMove) {
// if found, capture state ...
startCenter = tileToMove.center;
startLocation = location;
// ... and animate "pick up tile", so the user gets positive feedback
// that the drag/swipe portion of the gesture is starting.
[UIView animateWithDuration:0.25 animations:^{
tileToMove.transform = CGAffineTransformMakeScale(1.2, 1.2);
}];
} else {
gesture.state = UIGestureRecognizerStateFailed;
}
break;
}
case UIGestureRecognizerStateChanged:
{
// move the tile as the user's finger moves
CGPoint translate = CGPointMake(location.x - startLocation.x, location.y - startLocation.y);
// note, if you want to constrain the translation to be, for example, on the
// x-axis alone, you could do something like:
//
// CGPoint translate = CGPointMake(location.x - startLocation.x, 0);
tileToMove.center = CGPointMake(startCenter.x + translate.x, startCenter.y + translate.y);
break;
}
case UIGestureRecognizerStateEnded:
{
// animate "drop the tile"
[UIView animateWithDuration:0.25 animations:^{
tileToMove.transform = CGAffineTransformIdentity;
// if you want the tile to "snap" to some location having let it go,
// set the `center` or `frame` here.
}];
// clear our variables, just in case
tileToMove = nil;
startCenter = CGPointZero;
startLocation = CGPointZero;
break;
}
default:
break;
}
}
- (UIView *)findTileToMove:(CGPoint)location
{
for (UIView *tile in self.tiles) {
if (CGRectContainsPoint(tile.frame, location)) {
return tile;
}
}
return nil;
}
This might not be quite the exact UI you're looking for, but it illustrates:
How to have two gestures, where one requires the other to fail in order to establish a precedence between the gestures (and clearly only an issue if you want two distinct gestures, which you probably don't);
To not have shouldRecognizeSimultaneouslyWithGestureRecognizer method because I don't want them both to be recognized simultaneously. Note, that's only needed if you really need two gestures, which you may or may not need; and
How to have a long press that not only recognizes initial long press, but subsequent swipe/drag movement, too.
I'm trying to make an UIViewImage, and an UILabel draggable, and i having some problems to figure out how to make the Views, only draggable at one direction, for example, i want to drag the views to left(x) or down(y), but never left and down at same time.
I tried to use the UISwipeGestureRecognizer, to see in which direction i should move UP, DOWN or LEFT and RIGHT, but things are not working as i tough.
To make things easier this is what a have on viewController.h:
///Images
#property (nonatomic) UIImageView *mainImage; // Draggable Image
#property (nonatomic) UISwipeGestureRecognizer *swipeDirection; // This will be used on TouchesMoved.
//Label
#property(nonatomic) UILabel *mainLabel; // Draggable Label
I'm adding the Swipe recognizer in the viewDidLoad Method, just for the Left (for now):
UISwipeGestureRecognizer *detectSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(setSwipe:)];
[detectSwipe setDirection:UISwipeGestureRecognizerDirectionLeft];
[self.view addGestureRecognizer:detectSwipe];
Here is where i set the "swipeDirection" property:
-(void)setSwipe:(UISwipeGestureRecognizer *)gesture {
if (gesture.direction == UISwipeGestureRecognizerDirectionLeft) { // this is just for testing
self.swipeDirection = gesture;
NSLog(#"Gesture = %#", gesture);
}
}
Here is where I'm actually trying to move things (currently only to left):
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches ) {
CGPoint currentLocalation = [touch locationInView:touch.view];
if (self.swipeDirection.direction == UISwipeGestureRecognizerDirectionLeft) {
NSLog(#"Swipe Left");
if (currentLocalation.x < startLocation.x) { // Startlocation is a global CGPoint.
NSLog(#"Current Y = %f, starting Y = %f", currentLocalation.y, startLocation.y);
CGFloat distance = startLocation.x - currentLocalation.x;
CGPoint newPosition = CGPointMake(160 - distance, 170);
CGPoint labelPosition = CGPointMake(160 - distance, 390);
self.mainImage.center = newPosition;
self.mainLabel.center = labelPosition;
}
} else {
NSLog(#"Other direction");
}
}
What should i do? I'm looking at this from the wrong direction? Any help will be appreciated.
It looks like you're trying to use a swipe gesture for something it's not fit for (i.e. tracking finger movement and moving views along with the finger). This is exactly what UIPanGestureRecognizer is for. Here's an example of how this would work with a pan gesture:
First, attach the gesture recognizer:
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(onPan:)];
[self.view addGestureRecognizer:panGesture];
Then, handle finger movement:
-(void)onPan:(UIPanGestureRecognizer*)recognizer
{
// Find out how far the finger has moved (+x is right, -x is left, +y is down, -y is up)
CGPoint movement = [recognizer translationInView:recognizer.view];
if(movement.x < 0){
// Finger moved left by movement.x pixels
}
if(movement.y > 0){
// Finger moved down by movement.y pixels
}
[recognizer setTranslation:CGPointZero inView:recognizer.view];
}
In this example, I'm accepting both left and downwards movement at the same time. I'll leave it up to you to figure out how to decide which direction gets precedence if the user drags down and left simultaneously. One suggestion would be to compare the absolute value of the x and y directions, and act on whichever is larger
I would use a Pan Gesture recognizer, and lock the direction. I setup a simple typedef for my axis. Default means it hasn't been set yet. When the axis is not set it looks for which direct the user starts off. In this case when the users moves 20 points in one direction it will lock. You want to set a minimum threshold for this to ensure expected results.
typedef enum{
elAxisUpDown,elAxisLeftRight, elAxisDefault
}elAxis;
-(IBAction)handlePan:(UIPanGestureRecognizer *)sender
{
CGPoint testPoint = [sender locationInView:self.view];
switch (sender.state) {
case UIGestureRecognizerStateBegan:
// #property elAxis
self.axis = elAxisDefault;
// #property CGPoints
self.startingPoint = testPoint;
self.startingCenter = sender.view.center;
break;
case UIGestureRecognizerStateChanged:
switch (self.axis)
{
case elAxisDefault:
{
if (fabsf(testPoint.x-self.startingPoint.x) > fabsf(testPoint.y-self.startingPoint.y) && fabs(testPoint.x-self.startingPoint.x)>20) {
self.axis = elAxisLeftRight;
}
else if (fabsf(testPoint.x-self.startingPoint.x) < fabsf(testPoint.y-self.startingPoint.y) && fabs(testPoint.y-self.startingPoint.y)>20) {
self.axis = elAxisUpDown;
}
break;
}
case elAxisLeftRight:
self.button7.center = CGPointMake(self.startingCenter.x + (testPoint.x - self.startingPoint.x), self.startingCenter.y);
break;
case elAxisUpDown:
self.button7.center = CGPointMake(self.startingCenter.x, self.startingCenter.y + (testPoint.y - self.startingPoint.y));
break;
default:
break;
}
break;
case UIGestureRecognizerStateEnded:
self.axis = elAxisDefault;
break;
default:
break;
}
}
- (void)panDetected:(UIPanGestureRecognizer *)panGestureRecognizer {
if(panGestureRecognizer.state == UIGestureRecognizerStateBegan) {
// record the point of the touch - decide whether the pan is moving an
// object or misses everything and should be ignored
} else if(panGestureRecognizer.state == UIGestureRecognizerStateChanged) {
// animate the object that might be dragged in the direction you allow, and back,
// if the gesture point moves around a bit
} else if(panGestureRecognizer.state == UIGestureRecognizerStateEnded) {
// if the gesture ends with a net movement in the allowed direction, finalize the
// object's move else restore its original position with an animation back
// to its original place
}
}
This is the kind of thing you want, in the gesture recogniser handler.
I am trying to implement a "extras" menu for a app I am creating. Essentially I have a UITableView with multiple types of cells, when a user swipes to the left on the cell I want to be able to dynamically show them "extras" they can do. For example on a post they can swipe over and then see options like share, like ...ect. If you have used the Alien Blue app on ios for Reddit then that is what I am looking to do...
So far I have the swipe recognizer working and it identifies the type of cell properly... I just don't know how to start the subview programming...
Do I just make every cell larger and hide the extras until swipe or do I dynamically add views to each cell as I go...
Thank for any advice or help
I can provide code if needed....
A
I think you are right, and at least, that's how I did on my cell.
The only difference is i am not making the cell width large than window width. I add a view with the extra stuff, in my case it's a delete button, under the regular cell.contentview. then when the cell detects a swipe from right to left, it will call a function to handle the gesture.
Since i want the user to see that delete button when drag the cell to the left and show that button entirely when they pan the cell far enough
here is a snippet for how i handle the pan gesture,
CGPoint _originalTouchPoint;
- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
switch (recognizer.state) {
case UIGestureRecognizerStateBegan:
//save the original touch point when pan starts
_originalTouchPoint = [recognizer locationInView:_tableView];
break;
case UIGestureRecognizerStateChanged:
[self handlePan:recognizer];
break;
case UIGestureRecognizerStateEnded:
[self panEnded:recognizer];
break;
default:
break;
}
}
- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
MyCell *ourCell = (MyCell *)recognizer.view;
CGPoint touchPoint = [recognizer locationInView:_tableView];
float movedDistance = (_originalTouchPoint.x - touchPoint.x);
if(movedDistance < 0)
movedDistance = 0;
float maxX = ourCell.deleteButton.frame.size.width;
float ourTranslation = MAX(-1 * ourCell.deleteButton.frame.size.width, -1 * movedDistance);
ourCell.contentView.transform = CGAffineTransformMakeTranslation(ourTranslation, 0.0f);
// i only show the button when user pan all the way though
_shouldDeleteButtonShow = movedDistance / maxX >= 1.0;
}
- (void)panEnded:(UIPanGestureRecognizer *)recognizer
{
MyCell *ourCell = (MyCell *)recognizer.view;
if (_shouldDeleteButtonShow)
{
//do whatever you want in this case
}
else
{
//move the cell back to normal
[UIView animateWithDuration:0.3
animations:^
{
ourCell.contentView.transform = CGAffineTransformIdentity;
}];
}
}
Those are my codes, maybe not working exactly like you want, but hopefully, that gave you a rough idea about how to do this
I'm looking to animate bubbles with text on them to slide on and off the screen. The ideal implementation for this animation is iOS's horizonatal scroll with paging enabled. I definitely want the "bounce" when I reach the end of the speech bubbles and I definetely want the bubbles to track the finger until a certain point before they will slide off the screen. I believe this is not the same as a swipe (which is just a flick in one direction).
However, the problem with the horizontal scroll is that it is optimized for a static number of images. I will be having a dynamic number of images and as far as I can tell, you cannot dynamically append images to horizontal scroller. The idea is the app dynamically adds content to the scroller as you continue to progress through it.
The scroller was easy enough to get going but I'm going to have to tear it down now. How can I get started with the gesture (I'm not sure if the standard gesture recognizers will work for me at this point) as well as the animation? I've never worked with that portion of iOS code before.
I'm not sure if I follow your question entirely, but if you want to animate the movement of something based upon a gesture, you can use a UIPanGestureRecognizer and change the center of whatever subview you want. For example, in viewDidLoad you would:
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(movePiece:)];
[whateverViewYouWantToAnimate addGestureRecognizer:panGesture];
You can then have your gesture recognizer move it where ever you want:
- (void)movePiece:(UIPanGestureRecognizer *)gestureRecognizer
{
static CGPoint originalCenter;
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
originalCenter = [gestureRecognizer view].center;
}
else if (gestureRecognizer.state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [gestureRecognizer translationInView:self.view];
gestureRecognizer.view.center = CGPointMake(originalCenter.x + translation.x, originalCenter.y);
// if you wanted to animate both left/right and up/down, it would be:
// gestureRecognizer.view.center = CGPointMake(originalCenter.x + translation.x, originalCenter.y + translation.y);
}
else if (gestureRecognizer.state == UIGestureRecognizerStateEnded)
{
// replace this offscreen CGPoint with something that makes sense for your app
CGPoint offscreen = CGPointMake(480, gestureRecognizer.view.center.y);
[UIView animateWithDuration:0.5
animations:^{
gestureRecognizer.view.center = offscreen;
}
completion:^(BOOL finished){
// when you're done, you might want to do whatever cleanup
// is appropriate for your app (e.g. do you want to remove it?)
[gestureRecognizer.view removeFromSuperview];
}];
}
}